henvcfg — the guest environment dial
The envcfg cascade gains its hypervisor tier: henvcfg governs execution when V=1, sitting between menvcfg (which must grant first) and senvcfg (which the guest uses to govern VU).
henvcfg (0x60A) — Figure 59
hcounteren repeats the scounteren pattern for V=1:
a counter read in VS needs mcounteren AND hcounteren bits (VU adds
scounteren); blocked-but-M-granted reads raise virtual-instruction.
Its TM bit additionally gates guest access to vstimecmp-via-stimecmp.
htimedelta shifts the guest’s clock: VS/VU reads of time return
time + htimedelta (64-bit wrap → negative offsets), keeping virtual
time continuous across migration.
htval and htinst
On a trap into HS, htval carries the guest physical address for
guest-page faults, shifted right 2 bits (GPAs may be 2 bits wider than
XLEN; same encoding as PMP/PTE addresses). The low 2 bits equal
stval’s — except when the fault hit an implicit VS-stage page-table
access, where htval holds the PT access’s GPA (the original GPA is
unknowable mid-walk) and htinst disambiguates with a
pseudoinstruction (the traps page has the format). htval is
WARL and may hold only the GPAs the hart can actually fault on.
hgatp — the G-stage root
hgatp (0x680), HSXLEN=64 — Figure 65
hgatp is active unless effective privilege is U with hstatus.HU=0
(so speculative HLV/HSV execution stays simple), and — like satp —
writing it flushes nothing: VMID vmid Virtual Machine IDentifier in hgatp: tags G-stage (and combined) TLB entries per guest so world switches need no flush, and scopes HFENCE.GVMA. Up to 7 bits (Sv32x4) or 14 bits (Sv39/48/57x4); discovery by write-ones-readback.
defined in ch. II·15 — open in glossary
-tagged TLBs or
HFENCE.GVMA handle staleness.
vsstatus, vsip, vsie
vsstatus is a full sstatus layout with three twists. FS/VS are
doubly-gated: when V=1, an FP/vector instruction traps
(illegal-instruction — never virtual, a codified legacy rule) if
either vsstatus.FS or the HS-level sstatus.FS is Off, and
dirtying sets both. That’s what lets hypervisor and guest each run
independent lazy-switch protocols — the hypervisor can’t trust
vsstatus.FS (the guest scribbles on it), and the guest can’t see
sstatus.FS. SD/XS summarize only the VS view; UXL may be hardwired to
hstatus.VSXL, UBE to VSBE; SDT exists when henvcfg.DTE grants it.
| When delegated (hideleg bit set) / when not | |
|---|---|
| SEIP/SEIE ← hideleg[10] | Alias of hip.VSEIP / hie.VSEIE — the renumbered VS external interrupt. Not delegated → read-only zero. |
| STIP/STIE ← hideleg[6] | Alias of hip.VSTIP / hie.VSTIE. |
| SSIP/SSIE ← hideleg[2] | Alias of hip.VSSIP / hie.VSSIE. |
| LCOFIP/LCOFIE ← hideleg[13] | Only with Shlcofideleg (hideleg[13] writable): aliases of sip.LCOFIP / sie.LCOFIE — the guest samples its own perf counters. Else RO-0. |
Hardware Designer Notes
The dual-FS gating is the one piece here that touches the datapath rather than CSR plumbing: the FP-issue legality check becomes (vsstatus.FS ≠ Off) ∧ (sstatus.FS ≠ Off) when V=1, and the dirty update fans out to both fields. Everything else on this page is address decode, muxes, and one 64-bit adder on the time bus.
Minimal Linux-boot hart MUST
- Implement the two-level counter gate (m ∧ h, plus s for VU) with virtual-instruction on the h/s-denied cases
- Add htimedelta into both the time read path (V=1) and the vstimecmp comparator
- Enforce the 16 KiB root alignment for Sv*x4 (PPN[1:0] treatment) and the GPA>>2 encoding in htval
MAY simplify / trap-and-emulate
- Hardwire VMIDLEN=0 — correct but forces full G-stage TLB flushes on world switch; add VMIDs when VM density matters
- Pin henvcfg extension bits (PBMTE/ADUE/DTE/SSE/LPE/PMM) to zero when the underlying extensions are absent — each is independently optional
- Make vsstatus.UXL/UBE read-only copies of hstatus.VSXL/VSBE
Check yourself — henvcfg, hgatp, vsstatus
1.How does hgatp's response to an unsupported MODE write differ from satp's, and why does its PPN have a special constraint?
2.When V=1, a guest sets vsstatus.FS=Off but the hypervisor's sstatus.FS=Dirty. A guest FP instruction executes. What happens?
3.Why is a guest physical address in htval shifted right by 2 bits?
4.What does vsip.SEIP actually read when hideleg bit 10 is set?
5.What does htimedelta accomplish, and how are negative offsets represented?