:: commit 69dcdf77f7ba3bbb78e9edfeb588fed2b92d56c8

sanana <umutinanerdogan@pm.me> — 2025-06-29 12:05

parents: bceab08f77

sys/cpu: Implement TSC frequency calibration

`tsc_freq_arch` is the architecture-specific function to get the frequency of
rdtsc. If that fails (e.g. on an x86_64 machine without CPUID leaf 0x15) then
the TSC is calibrated with EFI Boot Services' `Stall`.
diff --git a/common/sys/cpu.h b/common/sys/cpu.h
index 434c436c..0ced9511 100644
--- a/common/sys/cpu.h
+++ b/common/sys/cpu.h
@@ -4,6 +4,7 @@
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
+#include <lib/misc.h>
 
 #if defined(__x86_64__) || defined(__i386__)
 
@@ -160,6 +161,15 @@ static inline uint64_t rdtsc(void) {
     return ((uint64_t)edx << 32) | eax;
 }
 
+static inline uint64_t tsc_freq_arch(void) {
+    uint32_t eax, ebx, ecx, edx;
+    if (!cpuid(0x15, 0, &eax, &ebx, &ecx, &edx))
+        return 0;
+    if (eax == 0 || ebx == 0 || ecx == 0)
+        return 0;
+    return ecx * ebx / eax;
+}
+
 #define rdrand(type) ({ \
     type rdrand__ret; \
     asm volatile ( \
@@ -221,6 +231,10 @@ static inline uint64_t rdtsc(void) {
     return v;
 }
 
+static inline uint64_t tsc_freq_arch(void) {
+    return 0; // FIXME
+}
+
 #define locked_read(var) ({ \
     typeof(*var) locked_read__ret = 0; \
     asm volatile ( \
@@ -289,6 +303,10 @@ static inline uint64_t rdtsc(void) {
     return v;
 }
 
+static inline uint64_t tsc_freq_arch(void) {
+    return 0; // FIXME
+}
+
 #define csr_read(csr) ({\
     size_t v;\
     asm volatile ("csrr %0, " csr : "=r"(v));\
@@ -348,10 +366,34 @@ static inline uint64_t rdtsc(void) {
     return v;
 }
 
+static inline uint64_t tsc_freq_arch(void) {
+    return 0; // FIXME
+}
+
 #else
 #error Unknown architecture
 #endif
 
+static inline uint64_t tsc_freq(void) {
+    uint64_t freq = tsc_freq_arch();
+    if (freq != 0) {
+        return freq;
+    }
+
+#if defined(UEFI)
+    uint64_t tsc_start = rdtsc();
+    gBS->Stall(1000);
+    uint64_t tsc_end = rdtsc();
+
+    if (tsc_end < tsc_start)
+        return 0;
+
+    return (tsc_end - tsc_start) * 1000ULL;
+#else
+    return 0;
+#endif
+}
+
 static inline void delay(uint64_t cycles) {
     uint64_t next_stop = rdtsc() + cycles;
 
tab: 248 wrap: offon