From 37cc98977590154ea0c703bf9396e26326adaa0a Mon Sep 17 00:00:00 2001 From: James Robinson Date: Thu, 7 May 2026 23:54:34 -0400 Subject: [PATCH 1/2] Keep M-priv access to indirect CSRs as illegal-instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sscsrind_reg_csr_t serves both Sscsrind (sireg, vsireg — S/HS-priv) and Smcsrind (mireg — M-priv). Its verify_permissions accumulated three H-extension V=1 illegal->virtual conversions (Smstateen hstateen0.CSRIND gate, the unconditional VU rule from PR #2221, and the base csr_t::verify_permissions S/HS conversion). All three are correct for the S/HS-priv siblings but spec-violating for the M-priv mireg: the H-ext conversion is restricted to csr_priv <= HS, so M-priv access from below M must continue to raise illegal-instruction. Add an early carve-out at the top of verify_permissions so any M-priv access from below M short-circuits to illegal before the V=1 conversion machinery runs. The downstream rules then only execute on S/HS-priv CSRs where their conversions are spec-correct, and don't need to special-case csr_priv themselves. Address bits [9:8] are used to derive the CSR's priv class because csr_priv is private to csr_t. --- riscv/csrs.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 476fba1744..d9f98056c2 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1848,6 +1848,12 @@ sscsrind_reg_csr_t::sscsrind_reg_csr_t(processor_t* const proc, const reg_t addr } void sscsrind_reg_csr_t::verify_permissions(insn_t insn, bool write) const { + // This class includes mireg / mireg2..6, for which access from + // below M always gives illegal not virtual instruction exception. + if (((address >> 8) & 3) > PRV_HS && state->prv < PRV_M) { + throw trap_illegal_instruction(insn.bits()); + } + if (proc->extension_enabled(EXT_SMSTATEEN)) { if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) throw trap_illegal_instruction(insn.bits()); From 13978b11f96504c53d30a0b0d9361ec00ba64bee Mon Sep 17 00:00:00 2001 From: James Robinson Date: Thu, 7 May 2026 23:55:06 -0400 Subject: [PATCH 2/2] Honor mstateen0.CSRIND in virtualized_indirect_csr_t wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sireg / vsireg are wrapped in virtualized_indirect_csr_t to alias sireg -> vsireg under V=1. The wrapper's verify_permissions called the base priv check first, so a VU access to sireg with mstateen0.CSRIND=0 hit the H-ext priv-class conversion (csr_priv=S, V=1) and trapped virtual-instruction. Per Smstateen the bit-clear case must raise illegal-instruction regardless of V — the inner sscsrind_reg_csr_t::verify_permissions enforces this but never runs once the wrapper has thrown. Add the Smstateen.CSRIND check at the top of the wrapper so it fires before the priv-class conversion. The inner copy stays in place for mireg / mireg2..6 and vsireg / vsireg2..6, which are registered without this wrapper. --- riscv/csrs.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/riscv/csrs.cc b/riscv/csrs.cc index d9f98056c2..6475188dc1 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1835,6 +1835,17 @@ virtualized_indirect_csr_t::virtualized_indirect_csr_t(processor_t* const proc, } void virtualized_indirect_csr_t::verify_permissions(insn_t insn, bool write) const { + // Check Smstateen.CSRIND before the wrapper's base priv check so a + // below-M access with mstateen0.CSRIND=0 raises illegal-instruction + // (per the Smstateen spec) rather than being converted to virtual + // by the H-ext priv-class rule. The same check exists in + // sscsrind_reg_csr_t::verify_permissions for the M-priv mireg path + // that doesn't go through this wrapper; leaving both is idempotent. + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) + throw trap_illegal_instruction(insn.bits()); + } + virtualized_csr_t::verify_permissions(insn, write); if (state->v) virt_csr->verify_permissions(insn, write);