summaryrefslogtreecommitdiff
path: root/src/boot
diff options
context:
space:
mode:
authorJan Janssen <medhefgo@web.de>2023-04-13 15:31:36 +0200
committerJan Janssen <medhefgo@web.de>2023-04-13 15:39:32 +0200
commit2a3ae5fae09a48387d40768faf0ba5a837dc0513 (patch)
tree3157c52fb4041180622381a84b661fd4b0f86bfe /src/boot
parent706fd67e4a61e615e9d05427e00e7e676973d8f2 (diff)
downloadsystemd-2a3ae5fae09a48387d40768faf0ba5a837dc0513.tar.gz
boot: Use CPUID to detect TSC frequency
Aside from being more accurate on CPUs that report the information this is also orders of magnitude faster than sleeping for 1ms.
Diffstat (limited to 'src/boot')
-rw-r--r--src/boot/efi/ticks.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/boot/efi/ticks.c b/src/boot/efi/ticks.c
index 7dd808ae19..f902b83a99 100644
--- a/src/boot/efi/ticks.c
+++ b/src/boot/efi/ticks.c
@@ -5,6 +5,7 @@
#include "vmm.h"
#if defined(__i386__) || defined(__x86_64__)
+# include <cpuid.h>
static uint64_t ticks_read_arch(void) {
/* The TSC might or might not be virtualized in VMs (and thus might not be accurate or start at zero
@@ -17,7 +18,35 @@ static uint64_t ticks_read_arch(void) {
}
static uint64_t ticks_freq_arch(void) {
- return 0;
+ /* Detect TSC frequency from CPUID information if available. */
+
+ unsigned max_leaf, ebx, ecx, edx;
+ if (__get_cpuid(0, &max_leaf, &ebx, &ecx, &edx) == 0)
+ return 0;
+
+ /* Leaf 0x15 is Intel only. */
+ if (max_leaf < 0x15 || ebx != signature_INTEL_ebx || ecx != signature_INTEL_ecx ||
+ edx != signature_INTEL_edx)
+ return 0;
+
+ unsigned denominator, numerator, crystal_hz;
+ __cpuid(0x15, denominator, numerator, crystal_hz, edx);
+ if (denominator == 0 || numerator == 0)
+ return 0;
+
+ uint64_t freq = crystal_hz;
+ if (crystal_hz == 0) {
+ /* If the crystal frquency is not available, try to deduce it from
+ * the processor frequency leaf if available. */
+ if (max_leaf < 0x16)
+ return 0;
+
+ unsigned core_mhz;
+ __cpuid(0x16, core_mhz, ebx, ecx, edx);
+ freq = core_mhz * 1000ULL * 1000ULL * denominator / numerator;
+ }
+
+ return freq * numerator / denominator;
}
#elif defined(__aarch64__)