stval — what faulted
On a trap into S, stval receives exception-specific evidence
(otherwise hardware never writes it). The platform declares per
exception class whether it’s informative or hardwired zero.
| Value | |
|---|---|
| Breakpoint, misaligned, access-fault, page-fault, hardware-error on fetch/load/store | The faulting virtual address |
| EBREAK / C.EBREAK | Zero or the instruction’s own address. |
| Illegal instruction (optional feature) | The faulting instruction bits, right-justified, zero-filled: the shortest of the actual instruction, ILEN bits, or SXLEN bits — spares the handler a fetch-and-decode round trip. |
| Software check (cause 18) | 0 = no info, 2 = Zicfilp landing-pad fault, 3 = Zicfiss shadow-stack fault. |
| Everything else | Zero (future standards may extend). |
Like sepc, stval is WARL: it must hold every valid virtual address and zero (plus all values below 2^min(SXLEN, ILEN) if instruction-bit capture is implemented), and may canonicalize invalid addresses.
senvcfg — shaping the U-mode environment
senvcfg (0x10A), RV64 — Figure 29
The pattern continues down from menvcfg: each mode’s envcfg governs the next-lower mode, and an enable only works if the level above granted it too.
satp — the root of address translation
satp (0x180), SXLEN=64 — Figure 32
On SXLEN=32 the layout is MODE[31] (0 Bare, 1 Sv32), ASID[30:22] (9 bits), PPN[21:0]. satp is active when the effective privilege is S or U — M-mode fetches run untranslated regardless.
Three rules every OS port learns the hard way: (1) writing satp
neither orders prior page-table stores nor flushes cached
translations — that’s SFENCE.VMA’s job; (2) changes to
SUM/MXR, Bare↔paged MODE toggles, and ASID changes do take
effect immediately with no fence; (3) storing PPN+ ASID
asid Address Space IDentifier: satp field tagging TLB entries per address space so context switches need no flush. Hart-local meaning; ASIDLEN discoverable by write-ones-readback (max 9 bits Sv32, 16 bits Sv39/48/57); may legally be zero bits.
defined in ch. II·12 — open in glossary
together makes the context switch a single atomic CSRRW.
stimecmp — Sstc, the direct timer
A 64-bit comparator (RV32: stimecmp + stimecmph): STIP pends
whenever time ≥ stimecmp (unsigned), evaluated eventually — so a
handler that advances stimecmp and returns may take one spurious
re-trap, which the spec judges cheaper than polling STIP down. With
Sstc, S-mode schedules its own timer with one CSR write; without it,
every timer arm is an SBI call up to M-mode. Access from S requires
menvcfg.STCE.
Hardware Designer Notes
satp.MODE is the biggest WARL decision in the design: each supported Sv mode is another walker depth. Sv39’s 3-level walk covers 512 GiB of VA — ample for embedded Linux; servers want Sv48. The comparator for stimecmp shares the time bus you already route for rdtime.
Minimal Linux-boot hart MUST
- stval capturing faulting VAs for page/access faults (Linux page-fault handling reads it on every fault)
- satp with Bare + at least Sv39 (RV64), full-register-ignore on unsupported MODE writes, active-mode gating on effective privilege
- senvcfg present (fields may be RO-0 as extensions dictate); FIOM if satp has a paged mode and you target hypervisor-less device emulation
MAY simplify / trap-and-emulate
- Implement ASIDLEN=0 first: correct, just slower context switches; add ASIDs when TLB flush cost shows up in profiles
- Skip Sstc initially and let the SBI provide timers via mtimecmp — but budget for it: one 64-bit comparator against time
- Hardwire instruction-bit capture in stval to zero (Linux decodes from sepc instead)
Check yourself — stval, senvcfg, satp, stimecmp
1.A misaligned 8-byte load straddles a page boundary and the second page is unmapped. What does stval hold (if the platform sets it informatively)?
2.Why do ASID and the root-page-table PPN share the single satp CSR?
3.Software writes satp with MODE=Sv48 on a core that only implements Sv39. What happens?
4.Which of these takes effect immediately, with NO SFENCE.VMA needed?
5.With Sstc, a timer handler advances stimecmp and returns instantly — and immediately re-traps on the same interrupt. Spec bug?