Calibrated timer / clock

This commit is contained in:
2026-07-03 14:17:00 +01:00
parent 9a834c91ff
commit e80043b611
9 changed files with 212 additions and 14 deletions
+11 -5
View File
@@ -39,10 +39,15 @@ LVT-timer entry giving it a **vector** (32) and **periodic** mode, then an initi
count that becomes the reload value. From then on it fires vector 32 repeatedly, on
its own, forever.
> The count isn't calibrated to real time yet — the tick *rate* is arbitrary
> (bus-clock dependent). Turning it into a known frequency (say 100 Hz) needs a
> reference clock to measure against (the PIT, HPET, or the TSC). That's a later
> step; for now it just needs to tick.
The reload count isn't picked arbitrarily — it's **calibrated to real time**,
which the [real-time](vision.md) scheduling guarantees depend on. Since the LAPIC
timer's raw rate is bus-clock dependent and unknown up front, `calibrate` measures
it against the **PIT** (the legacy 8254, whose 1.193182 MHz is fixed): run the
LAPIC timer one-shot from its maximum count while the PIT counts out a known 10 ms
(polling channel 2, no interrupt needed), then see how far the LAPIC got. That
yields its counts-per-millisecond, from which `initTimer(hz)` computes the reload
count for any target frequency. danos runs it at **1000 Hz** (a 1 ms tick), and the
tick count times the known period gives a monotonic `uptimeMs()`.
## Two kinds of vector, one dispatch
@@ -101,7 +106,8 @@ spinning in unrelated code — is the whole mechanism working end to end.
- **The keyboard**: bring up the IO-APIC, route its IRQ to a vector, and read
scancodes from the PS/2 controller — the first *input* device.
- **A calibrated timer** at a known frequency, and a monotonic clock.
- **`sleep()` / timeouts** built on the calibrated clock (the monotonic
`uptimeMs()` is in place).
- **Uncacheable MMIO**: the LAPIC page is currently mapped writeback-cacheable like
the rest of the identity map. QEMU tolerates it, but real hardware wants MMIO
marked uncacheable (via the page's cache bits or an MTRR).