]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/ticks.c
tree-wide: fix typo
[thirdparty/systemd.git] / src / boot / efi / ticks.c
CommitLineData
1e66a233
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
1e66a233 3#include "ticks.h"
bafc5945 4#include "util.h"
ba279392 5#include "vmm.h"
3bcc999f 6
09614b35 7#if defined(__i386__) || defined(__x86_64__)
2a3ae5fa 8# include <cpuid.h>
706fd67e
JJ
9
10static uint64_t ticks_read_arch(void) {
bafc5945
JJ
11 /* The TSC might or might not be virtualized in VMs (and thus might not be accurate or start at zero
12 * at boot), depending on hypervisor and CPU functionality. If it's not virtualized it's not useful
13 * for keeping time, hence don't attempt to use it. */
3bcc999f
LP
14 if (in_hypervisor())
15 return 0;
16
09614b35 17 return __builtin_ia32_rdtsc();
1e66a233 18}
706fd67e
JJ
19
20static uint64_t ticks_freq_arch(void) {
2a3ae5fa
JJ
21 /* Detect TSC frequency from CPUID information if available. */
22
23 unsigned max_leaf, ebx, ecx, edx;
24 if (__get_cpuid(0, &max_leaf, &ebx, &ecx, &edx) == 0)
25 return 0;
26
27 /* Leaf 0x15 is Intel only. */
28 if (max_leaf < 0x15 || ebx != signature_INTEL_ebx || ecx != signature_INTEL_ecx ||
29 edx != signature_INTEL_edx)
30 return 0;
31
32 unsigned denominator, numerator, crystal_hz;
33 __cpuid(0x15, denominator, numerator, crystal_hz, edx);
34 if (denominator == 0 || numerator == 0)
35 return 0;
36
37 uint64_t freq = crystal_hz;
38 if (crystal_hz == 0) {
fcdd21ec 39 /* If the crystal frequency is not available, try to deduce it from
2a3ae5fa
JJ
40 * the processor frequency leaf if available. */
41 if (max_leaf < 0x16)
42 return 0;
43
44 unsigned core_mhz;
45 __cpuid(0x16, core_mhz, ebx, ecx, edx);
46 freq = core_mhz * 1000ULL * 1000ULL * denominator / numerator;
47 }
48
49 return freq * numerator / denominator;
706fd67e
JJ
50}
51
1e66a233 52#elif defined(__aarch64__)
706fd67e
JJ
53
54static uint64_t ticks_read_arch(void) {
db4122d1 55 uint64_t val;
2df8574a 56 asm volatile("mrs %0, cntvct_el0" : "=r"(val));
1e66a233
LP
57 return val;
58}
1e66a233 59
706fd67e 60static uint64_t ticks_freq_arch(void) {
db4122d1 61 uint64_t freq;
2df8574a 62 asm volatile("mrs %0, cntfrq_el0" : "=r"(freq));
1e66a233
LP
63 return freq;
64}
706fd67e 65
1e66a233 66#else
706fd67e
JJ
67
68static uint64_t ticks_read_arch(void) {
69 return 0;
70}
71
72static uint64_t ticks_freq_arch(void) {
73 return 0;
74}
75
76#endif
77
db4122d1 78static uint64_t ticks_freq(void) {
db4122d1 79 static uint64_t cache = 0;
fb63526f
LP
80
81 if (cache != 0)
82 return cache;
1e66a233 83
706fd67e
JJ
84 cache = ticks_freq_arch();
85 if (cache != 0)
86 return cache;
87
88 /* As a fallback, count ticks during a millisecond delay. */
89 uint64_t ticks_start = ticks_read_arch();
1e66a233 90 BS->Stall(1000);
706fd67e 91 uint64_t ticks_end = ticks_read_arch();
1e66a233 92
476c0e96 93 if (ticks_end < ticks_start) /* Check for an overflow (which is not that unlikely, given on some
da890466 94 * archs the value is 32-bit) */
476c0e96
LP
95 return 0;
96
fb63526f
LP
97 cache = (ticks_end - ticks_start) * 1000UL;
98 return cache;
1e66a233 99}
1e66a233 100
db4122d1 101uint64_t time_usec(void) {
706fd67e 102 uint64_t ticks = ticks_read_arch();
1e66a233
LP
103 if (ticks == 0)
104 return 0;
105
706fd67e 106 uint64_t freq = ticks_freq();
fb63526f
LP
107 if (freq == 0)
108 return 0;
1e66a233
LP
109
110 return 1000UL * 1000UL * ticks / freq;
111}