diff --git a/FABRIC.md b/FABRIC.md index 686c337..5145918 100644 --- a/FABRIC.md +++ b/FABRIC.md @@ -2009,6 +2009,12 @@ on until there is a tick on all three architectures (§16.1, §16.5).* Replace the one-way `riscv64_trap_entry` in `arch/riscv64/isr.S` with save / dispatch / restore / `sret`. Route `scause` bit 63 + cause 5 to the timer path; everything else keeps falling through to the existing fatal handler. + **FP state is not optional (B2 verified):** the kernel builds `-march=rv64gc -mabi=lp64d` + (`Makefile.starkernel:162`) — hard-float ABI, and kernel code genuinely uses doubles + (`hotwords_stats_print`). The trap entry must save the ABI's caller-saved FP registers + plus `fcsr` alongside the integer set; verify the exact register list against the RISC-V + psABI, not this document. Do not "fix" this by switching to soft-float — that breaks + existing code and is a build-system decision nobody has made. *Done when:* riscv64 boots to the prompt unchanged, having taken and returned from at least one trap. Exceptions still halt with the same diagnostic as before. @@ -2025,15 +2031,27 @@ on until there is a tick on all three architectures (§16.1, §16.5).* relying on it; if it is absent, stop and report rather than falling back silently. - [ ] **0.4 — aarch64: determine the exception level at runtime.** - Read `CurrentEL` in `timer_init()` and select the `CNTP_*_EL0` or `CNTHP_*_EL2` register - set accordingly. Do not hardcode either. + Read `CurrentEL` once, early, and let it govern **everything EL-dependent**, not just the + timer (B3): the vector base register (`VBAR_EL1` vs `VBAR_EL2` — today's `isr.S` writes + `VBAR_EL1` unconditionally, which is never consulted for exceptions taken at EL2), the + saved-state pair (`ELR_ELx`/`SPSR_ELx`), and the timer register set (`CNTP_*_EL0` vs + `CNTHP_*_EL2`). Do not hardcode either level anywhere. *Done when:* the boot log states which EL was detected, on real QEMU output. - [ ] **0.5 — aarch64: IRQ vector split.** - Split `irq_spx` out of the shared fatal handler in `arch/aarch64/isr.S`: save `x0`–`x30`, - `ELR_EL1`, `SPSR_EL1`, call a C handler, restore, `eret`. The other fifteen vectors are - unchanged. Note the 128-byte slot limit — the save sequence will not fit inline and must - branch to a trampoline. + Split `irq_spx` out of the shared fatal handler in `arch/aarch64/isr.S`: save `x0`–`x30` + plus the saved-state registers (see B3 note below), call a C handler, restore, `eret`. + The other fifteen vectors are unchanged. Note the 128-byte slot limit — the save sequence + will not fit inline and must branch to a trampoline. + **FP state is not optional (B2 verified):** the kernel builds without + `-mgeneral-regs-only` (`Makefile.starkernel:146`), so the compiler may use SIMD registers + anywhere. Save the ABI's caller-saved SIMD set plus `FPSR`/`FPCR` alongside the integer + set; verify the exact list against the AAPCS64, not this document. + **EL governs the whole path (B3):** this item previously hardcoded `ELR_EL1`/`SPSR_EL1`, + while 0.4 refuses to hardcode the EL — and today's `isr.S` installs `VBAR_EL1`, which is + never consulted for exceptions taken at EL2. The EL detected in 0.4 must select the + vector base register (`VBAR_ELx`), the saved-state pair (`ELR_ELx`/`SPSR_ELx`), and the + `eret` target state, not just the timer registers. *Done when:* aarch64 boots to the prompt having taken and returned from at least one IRQ. - [ ] **0.6 — aarch64: minimal GICv2.**