Skip to content

fix(hal): read riscv64 time via rdtime, not CLINT MMIO - #145

Merged
kernalix7 merged 1 commit into
mainfrom
fix/riscv64-timer-rdtime
Jul 15, 2026
Merged

fix(hal): read riscv64 time via rdtime, not CLINT MMIO#145
kernalix7 merged 1 commit into
mainfrom
fix/riscv64-timer-rdtime

Conversation

@kernalix7

Copy link
Copy Markdown
Owner

RiscvTimer::read_mtime read the CLINT mtime register directly (0x0200_BFF8). That MMIO is M-mode only — OpenSBI's PMP faults an S-mode load, and with the early trap vector still a stub the fault storms and hangs the kernel right after PLIC initialized (the timer one-shot never arms).

Fix: read the architectural time CSR via rdtime (Zicntr — the S-mode-accessible mirror of mtime the firmware maintains).

Verified (qemu-system-riscv64 -M virt -bios default, first local riscv runtime with qemu-extra installed):

[ONCRIX/riscv64] Kernel booting...
[ONCRIX/riscv64] NS16550 UART initialized (115200 8N1)
[ONCRIX/riscv64] Heap initialized (16 MiB)
[ONCRIX/riscv64] PLIC initialized
[ONCRIX/riscv64] Timer armed (10 ms via SBI)
[ONCRIX/riscv64] All early initialization complete.
[ONCRIX/riscv64] Entering halt loop.

No traps. x86_64/aarch64 unaffected.

RiscvTimer::read_mtime read the CLINT mtime register directly at
0x0200_BFF8. That MMIO is M-mode only — OpenSBI configures PMP so an
S-mode load faults, and with the early trap vector still a stub the fault
storms and hangs the kernel right after 'PLIC initialized' (the timer
one-shot never arms). Read the architectural 'time' CSR via rdtime
instead (Zicntr; the S-mode-accessible mirror of mtime that firmware
maintains).

Verified: 'qemu-system-riscv64 -M virt -bios default' now boots all the
way through — Kernel booting -> NS16550 -> Heap -> PLIC -> Timer armed
(10 ms via SBI) -> All early initialization complete -> halt loop, no
traps. First runtime boot of the riscv64 kernel (qemu-extra now
installed locally). x86_64/aarch64 unaffected.
@kernalix7
kernalix7 merged commit 479e2c5 into main Jul 15, 2026
2 checks passed
@kernalix7
kernalix7 deleted the fix/riscv64-timer-rdtime branch July 15, 2026 06:23
kernalix7 added a commit that referenced this pull request Jul 15, 2026
Brings riscv64 to parity with aarch64: it now takes S-mode timer
interrupts and preempts busy kernel threads.

- boot.rs: replace the spin-stub trap vector with a real S-mode handler.
  It saves the caller-saved GPRs + sepc + sstatus into a 144-byte frame
  (sepc/sstatus stacked so a preemptive switch can't clobber them), calls
  riscv_handle_trap, restores, and srets.
- irq.rs (new): riscv_handle_trap reads scause; on the S-mode timer
  interrupt (0x8000_0000_0000_0005) it re-arms the SBI one-shot (which
  also clears the pending STIP and keeps sie.STIE), charges a tick, and
  runs a guarded sched_yield_once. No GIC/EOI on riscv — the re-arm is
  the acknowledgement.
- kthread.rs (new): mirrors the aarch64 pool; spawn_kthread seeds the
  112-byte switch frame with entry at offset 0 (riscv switch_context does
   first, unlike aarch64's +8).
- sched_glue.rs: real sched_yield_once (prepare_switch -> switch_context);
  read_cr3 reads satp.
- main.rs: riscv cooperative + preemptive demos (busy C/D that never
  yield; the SBI timer alone rotates them). Threads set sstatus.SIE on
  entry (the interrupt-mask-inheritance lesson from aarch64).
- timer.rs: drop the now-unused CLINT_MTIME const (read_mtime moved to
  rdtime in #145).

Verified: 'qemu-system-riscv64 -M virt -bios default' runs the cooperative
demo, then C and D interleave under the timer and print 'timer preemption
verified', with no S-mode faults (remaining traps are OpenSBI HPM
probing). x86_64/aarch64 unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant