The xenvcfg gating trees
You met the CBIE/CBCFE/CBZE fields on the menvcfg, senvcfg, and henvcfg pages; here is the full decision logic they feed. The shape is always the same cascade — M’s denial is illegal-instruction; the hypervisor’s or guest kernel’s denial is virtual-instruction, so the trap lands at the layer that can emulate or reject:
| Outcome | |
|---|---|
| priv < M ∧ menvcfg.CBIE=00, or U ∧ senvcfg.CBIE=00 | Illegal-instruction exception. |
| VS ∧ henvcfg.CBIE=00, or VU ∧ (henvcfg or senvcfg =00) | Virtual-instruction exception. |
| ANY governing level has CBIE=01 | Executes, but performs a FLUSH operation. |
| All governing levels CBIE=11 | Executes a true invalidate. |
CBO.CLEAN/CBO.FLUSH follow the same tree on the boolean CBCFE bits (execute or trap — no downgrade tier), and CBO.ZERO on CBZE. The fields in different xenvcfg registers never affect each other’s read/write behavior; all are WARL, with the legal values learned from the platform’s discovery data.
Encodings
Semantics fine print: cbo.clean may legally be implemented as a
flush, and so may cbo.inval (writeback-then-invalidate is
indistinguishable from the permitted outcomes). CBO management ops
ignore cacheability attributes — a PBMT-downgraded page still
gets its block operated on. CBO.ZERO writes its zeros in any order,
granularity, and atomicity, cacheable target or not. Prefetch
composition with NTL hints steers the destination level.
Discovery: software must learn the management/prefetch block
size, the (possibly different) CBO.ZERO block size, and per-level
CBIE support from the execution environment — device tree
(riscv,cbom-block-size, riscv,cboz-block-size) or ACPI, not CSRs.
Hardware Designer Notes
Sizing note for CBO.ZERO: advertise the zero-block size equal to your cache-line size only if a full-line non-allocating store path exists; otherwise a smaller advertised size (even 8 bytes) is conformant and keeps clear_page correct, just slower. The discovery split between cbom/cboz block sizes exists precisely for this freedom.
Minimal Linux-boot hart MUST
- Implement the three gating cascades exactly, including the any-level-01 flush downgrade for CBIE and the illegal-vs-virtual selection
- Keep the CBO imm12 decode strict — values other than 0/1/2/4 under funct3=010 are reserved and must trap
- Block-align internally from an arbitrary rs1, while reporting the unaligned rs1 in xtval on faults
MAY simplify / trap-and-emulate
- Implement CBO.ZERO as a full-line store-buffer allocation without fetching the old line — its raison d’être (Linux uses it for clear_page when advertised)
- Treat all three prefetches as no-ops, or route them into your existing prefetcher’s request queue with I/R/W intent
Check yourself — CBO controls & encodings
1.Why would an OS deliberately set senvcfg.CBIE = 01 (execute-as-flush) instead of 11 (invalidate) for user mode?
2.In VU-mode, CBO.ZERO executes only when which enables are set?
3.How are the four CBO instructions and three prefetches distinguished in the encoding?
4.What must software discover before using these instructions, and how?