sys/cpu: Add PIT-based TSC calibration for BIOS
diff --git a/common/protos/limine.c b/common/protos/limine.c
index b8767436..6a782cf4 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -1595,7 +1595,6 @@ FEAT_END
#endif
// Bootloader Performance
- // rdtsc_usec depends on EFI boot services
FEAT_START
if (usec_at_bootloader_entry == 0) {
break;
diff --git a/common/sys/cpu.h b/common/sys/cpu.h
index 60cc72bd..2b006280 100644
--- a/common/sys/cpu.h
+++ b/common/sys/cpu.h
@@ -504,15 +504,6 @@ static inline uint64_t rdtsc_usec(void) {
}
static inline void stall(uint64_t us) {
-#if defined(BIOS)
- if (tsc_freq == 0) {
- // ~1 us per inb on ISA/LPC bus
- for (uint64_t i = 0; i < us; i++) {
- inb(0x80);
- }
- return;
- }
-#endif
uint64_t ticks = (tsc_freq * us + 999999) / 1000000;
uint64_t next_stop = rdtsc() + ticks;
while (rdtsc() < next_stop);
diff --git a/common/sys/cpu.s2.c b/common/sys/cpu.s2.c
index d4d6ec89..a5ea5bff 100644
--- a/common/sys/cpu.s2.c
+++ b/common/sys/cpu.s2.c
@@ -22,5 +22,28 @@ void calibrate_tsc(void) {
if (tsc_end > tsc_start) {
tsc_freq = (tsc_end - tsc_start) * 1000ULL;
}
+#elif defined(BIOS)
+ // Calibrate TSC using PIT channel 2
+ // PIT oscillator frequency: 1193182 Hz
+ // Count of 11932 gives ~10ms calibration interval
+ #define PIT_CALIBRATION_COUNT 11932
+
+ uint8_t port61 = inb(0x61);
+ outb(0x61, port61 & ~0x03); // disable gate and speaker
+ outb(0x43, 0xb0); // channel 2, lobyte/hibyte, mode 0, binary
+ outb(0x42, PIT_CALIBRATION_COUNT & 0xff);
+ outb(0x42, (PIT_CALIBRATION_COUNT >> 8) & 0xff);
+
+ outb(0x61, (inb(0x61) | 0x01)); // enable gate to start counting
+ uint64_t tsc_start = rdtsc();
+
+ while ((inb(0x61) & 0x20) == 0); // wait for output high
+ uint64_t tsc_end = rdtsc();
+
+ outb(0x61, port61); // restore
+
+ if (tsc_end > tsc_start) {
+ tsc_freq = (tsc_end - tsc_start) * 1193182 / PIT_CALIBRATION_COUNT;
+ }
#endif
}
