--- name: schunix-wall-clock description: The clock read 1970 because nothing ever called cmostime(); kernel/core/time.c now reads the RTC at boot. metadata: node_type: memory type: project originSessionId: 9d8a2aef-bcf0-47a0-96c6-f706efab4a95 modified: 2026-08-08T19:44:10.022Z --- Fixed 2026-08-08. Nexoniarz reported "time has stopped, or it's just too slow — type `date`, wait 10 seconds, it's still the same or pretty close." **The clock was not stopped.** `ticks` advanced correctly (measured: uptime 19.81 → 34.51 over ~14 real seconds, identical at `-smp 1` and `-smp 2`). The bug was the *origin*: `sys_gettimeofday`, `sys_clock_gettime` and `sys_time` all returned `ticks / 100` — seconds since **boot**, presented as seconds since the **epoch**. So every machine believed it was 1 Jan 1970 and the date crawled at the rate of its own uptime. `cmostime()` in `kernel/arch/x86_64/lapic.c` could read the hardware clock the whole time and had no caller. `kernel/core/time.c` now reads the RTC once in `main()` (after the timer is running, before userspace), converts it with Howard Hinnant's `days_from_civil`, and stores `boot_epoch`. `wallclock(&sec, &usec)` is the one place that answers "what time is it", so the three syscalls cannot disagree. - **`days_from_civil`, not a loop over years** — branchless, exact for any year, no table. Accumulating 365/366 since 1970 gets leap centuries wrong unless you remember 1900 was not a leap year and 2000 was. - **RTC read once, not per call** — it is polled over two I/O ports and must be sampled twice to catch it mid-update. - **Interpreted as UTC.** A PC that has had Windows on it usually keeps the RTC in local time, but there is no timezone store and nowhere to ask. `date` shows UTC; Nexoniarz is UTC+2 in summer, so it reads two hours behind local. When a settings store exists, the offset goes in `time_init()`. - **`CLOCK_MONOTONIC` (clkid 1) subtracts `boot_epoch`**; everything else is treated as realtime. - Implausible CMOS readings leave `boot_epoch` at 0, i.e. the old behaviour, rather than putting the machine in the Bronze Age. Verified: `Sat Aug 8 19:36:43 UTC 2026`, advancing 14s in 14 real seconds, host at 21:37 CEST. ## The stale-image trap, now guarded A running QEMU holds `build/fs.img` open; on Windows `rm` then fails with "Device or resource busy", and **make stops after the kernel has already relinked**. The next test boots the *previous* kernel and the change looks like it did nothing. This cost several cycles across the session. The `fs.img` rule now prints what is wrong and how to clear it. When a fix appears to have no effect, check `schunix.img`'s timestamp before debugging the code.