New cause codes
H adds to the base cause table: interrupts 2/6/10 (VS software/timer/external) and 12 (supervisor guest external); exceptions 10 (ecall from VS — separate from HS’s 9, so the two delegate independently), 20/21/23 (instruction/load/store guest-page faults, slotted into the priority order right beside their page-fault cousins), and 22 (virtual instruction).
The virtual-instruction rule
When V=1, an instruction that is HS-qualified — it would execute in HS-mode assuming TSR=TVM=0 — but is blocked under virtualization raises virtual-instruction (22), not illegal-instruction. The enumerated cases: counter CSRs blocked by hcounteren (or scounteren in VU) while mcounteren grants them; any hypervisor instruction or CSR touched from VS/VU; supervisor instructions/CSRs from VU; WFI under VTW (VS) or TW=0-in-VU; SRET under VTSR; SFENCE/SINVAL/satp under VTVM; high-half CSR partners on XLEN=32.
Why a separate code? Delegation speed: M-mode routes code 22 straight to the hypervisor (its emulation hook), while code 2 typically visits M-mode first. A hypervisor that chooses not to emulate converts it to an illegal-instruction for the guest. One codified exception: FP/vector instructions blocked by FS/VS=Off in either sstatus or vsstatus are always illegal-instruction — a legacy-preserving carve-out.
Trap entry, three destinations
| State written | |
|---|---|
| Into M-mode | V←0; mstatus.MPV/MPP per Table 52 (VS-mode → MPV=1, MPP=1), GVA, MPIE/MIE; mepc, mcause, mtval, mtval2, mtinst. |
| Into HS-mode | V←0; hstatus.SPV = old V, GVA; sstatus.SPP/SPIE/SIE; sepc, scause, stval, htval, htinst. |
| Into VS-mode | V stays 1; vsstatus.SPP (VU→0, VS→1), SPIE/SIE; vsepc, vscause, vstval. hstatus and HS-sstatus untouched — indistinguishable from a native S-mode trap. |
Returns mirror entries: MRET picks the mode from MPP+MPV (MPP=3 forces V=0), then clears MPV/MPP, restores MIE from MPIE. SRET at V=0 uses hstatus.SPV + sstatus.SPP (clearing SPV); SRET at V=1 (VTSR permitting) is a purely-VS affair through vsstatus/vsepc. With Ssdbltrp, SRET entering VU (or executed in VS) clears vsstatus.SDT.
mtinst / htinst — the pre-decoded trap
On synchronous exceptions from explicit memory accesses, hardware may write a transformed instruction so the handler never fetches or decodes guest code:
The value grammar keeps the register forward-compatible: bit 0 = 1 with “set bit 1” yielding a standard instruction → transform; a custom-space encoding → custom value (non-standard trapping instructions only); bits 1:0 = 00 → pseudoinstruction; anything else (and always on interrupts, fetch-side faults, ecalls) → zero. Atomics and HLV/HSV transform like loads/stores with all fields preserved except rs1 → Addr. Offset.
| Meaning | |
|---|---|
| 0x00002000 / 0x00003000 | 32-bit (VSXLEN=32) / 64-bit (VSXLEN=64) READ for VS-stage address translation — the walker couldn’t read a guest PTE. ≈ lw/ld x0,0(x0) with bits 1:0 = 00. |
| 0x00002020 / 0x00003020 | The WRITE case — hardware A/D update of a VS-level PTE faulted at G-stage. Never occurs if A/D updates are software’s job. (Atomicity of the real update is ignored here — the hypervisor just makes the page accessible and retries.) |
Hardware Designer Notes
The transform hardware is a latch of decode fields (funct3, rd, rs2, compressed?) carried to the commit stage, plus one subtractor for Addr. Offset — cheap, and it removes a guest-memory round trip from every MMIO emulation exit. Measure before omitting: trap-and-emulate latency is THE hypervisor performance metric.
Minimal Linux-boot hart MUST
- Implement the virtual-vs-illegal selector: (V=1) ∧ HS-qualified ∧ blocked → 22, with the FS/VS-off carve-out to code 2
- Write the pseudoinstruction values on implicit-access guest-page faults whenever htval/mtval2 is nonzero — zero is non-conformant exactly there
- Keep the three-destination entry state machine exact, including SPVP’s only-if-V-was-1 update and MRET’s MPP=3-forces-V=0 rule
MAY simplify / trap-and-emulate
- Write zero to mtinst/htinst for every transformable case — transforms are a pure emulation-speed optimization
- Reduce htinst storage to the handful of supported values
Check yourself — H traps
1.A VS-mode guest reads the cycle CSR with hcounteren.CY=0 but mcounteren.CY=1. Which exception, and why does the distinction matter?
2.Which exception deliberately BREAKS the virtual-instruction rule?
3.A trap from VU-mode lands in VS-mode (fully delegated). What does hardware write?
4.htinst reads 0x00003000 after a guest-page fault. What happened?
5.In a transformed load written to htinst, what replaces the rs1 field?