diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index a03d188d4c..5b59ed42c4 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -179,6 +179,7 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) (1 << CAUSE_SOFTWARE_CHECK_FAULT) | (1 << CAUSE_HARDWARE_ERROR_FAULT); add_hypervisor_csr(CSR_HEDELEG, hedeleg = std::make_shared(proc, CSR_HEDELEG, hedeleg_mask, 0)); + add_hypervisor_csr(CSR_HEDELEGH, std::make_shared(proc, CSR_HEDELEGH, 0)); add_hypervisor_csr(CSR_HCOUNTEREN, hcounteren = std::make_shared(proc, CSR_HCOUNTEREN, counteren_mask, 0)); htimedelta = std::make_shared(proc, CSR_HTIMEDELTA, 0); if (xlen == 32) { @@ -215,9 +216,9 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) add_csr(CSR_TINFO, std::make_shared(proc, CSR_TINFO, 0)); } unsigned scontext_length = (xlen == 32 ? 16 : 32); // debug spec suggests 16-bit for RV32 and 32-bit for RV64 - add_supervisor_csr(CSR_SCONTEXT, scontext = std::make_shared(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0)); + add_supervisor_csr(CSR_SCONTEXT, scontext = std::make_shared(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0)); unsigned hcontext_length = (xlen == 32 ? 6 : 13) + (proc->extension_enabled('H') ? 1 : 0); // debug spec suggest 7-bit (6-bit) for RV32 and 14-bit (13-bit) for RV64 with (without) H extension - auto hcontext = std::make_shared(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); + auto hcontext = std::make_shared(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0); add_hypervisor_csr(CSR_HCONTEXT, hcontext); add_csr(CSR_MCONTEXT, mcontext = std::make_shared(proc, CSR_MCONTEXT, hcontext)); add_csr(CSR_MSECCFG, mseccfg = std::make_shared(proc, CSR_MSECCFG)); @@ -284,8 +285,11 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) const reg_t sstateen0_mask = (proc->extension_enabled(EXT_ZFINX) ? SSTATEEN0_FCSR : 0) | (proc->extension_enabled(EXT_ZCMT) ? SSTATEEN0_JVT : 0) | SSTATEEN0_CS; - const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN; - const reg_t mstateen0_mask = hstateen0_mask | (proc->extension_enabled(EXT_SSQOSID) ? MSTATEEN0_PRIV114 : 0); + const reg_t hstateen0_mask = sstateen0_mask | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN | + (proc->extension_enabled(EXT_SSCSRIND) ? HSTATEEN0_CSRIND : 0) | + (proc->get_cfg().trigger_count > 0 ? HSTATEEN0_SCONTEXT : 0); + const reg_t mstateen0_mask = hstateen0_mask | MSTATEEN0_PRIV113 | + (proc->extension_enabled(EXT_SSQOSID) ? MSTATEEN0_PRIV114 : 0); for (int i = 0; i < 4; i++) { const reg_t mstateen_mask = i == 0 ? mstateen0_mask : MSTATEEN_HSTATEEN; mstateen[i] = std::make_shared(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0); @@ -349,11 +353,12 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) } if (proc->extension_enabled_const(EXT_SSCSRIND)) { - csr_t_p vsiselect = std::make_shared(proc, CSR_VSISELECT, 0); + auto vsiselect = std::make_shared(proc, CSR_VSISELECT, 0); add_hypervisor_csr(CSR_VSISELECT, vsiselect); - csr_t_p siselect = std::make_shared(proc, CSR_SISELECT, 0); - add_supervisor_csr(CSR_SISELECT, std::make_shared(proc, siselect, vsiselect)); + auto siselect = std::make_shared(proc, CSR_SISELECT, 0); + // Correct virtualized type? + add_supervisor_csr(CSR_SISELECT, std::make_shared(proc, siselect, vsiselect)); const reg_t vsireg_csrs[] = { CSR_VSIREG, CSR_VSIREG2, CSR_VSIREG3, CSR_VSIREG4, CSR_VSIREG5, CSR_VSIREG6 }; const reg_t sireg_csrs[] = { CSR_SIREG, CSR_SIREG2, CSR_SIREG3, CSR_SIREG4, CSR_SIREG5, CSR_SIREG6 }; diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 2267f7f47d..afcf2304a7 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1731,11 +1731,29 @@ 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 { - virtualized_csr_t::verify_permissions(insn, write); if (state->v) virt_csr->verify_permissions(insn, write); else orig_csr->verify_permissions(insn, write); + virtualized_csr_t::verify_permissions(insn, write); +} + +virtualized_select_indirect_csr_t::virtualized_select_indirect_csr_t(processor_t *const proc, + csr_t_p orig, + csr_t_p virt) + : virtualized_csr_t(proc, orig, virt) {} + +void virtualized_select_indirect_csr_t::verify_permissions(insn_t insn, + bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && + !(state->mstateen[0]->read() & MSTATEEN0_CSRIND)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_CSRIND)) + throw trap_virtual_instruction(insn.bits()); + } + virtualized_csr_t::verify_permissions(insn, write); } sscsrind_reg_csr_t::sscsrind_reg_csr_t(processor_t* const proc, const reg_t addr, csr_t_p iselect) : @@ -1744,19 +1762,43 @@ 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 { - // Don't call base verify_permission for VS registers remapped to S-mode - if (insn.csr() == address) - csr_t::verify_permissions(insn, write); + const auto csr_priv = get_field(insn.csr(), 0x300); + const bool is_vsi = csr_priv == PRV_HS; + // csr_priv checked due to mireg using the same class + if (csr_priv < PRV_M && state->prv < PRV_M){ + // The CSRIND bit in mstateen0 controls access to the siselect, sireg*, vsiselect, and the vsireg* + // Stateen takes precedence over general sscsrind rules + if (proc->extension_enabled(EXT_SMSTATEEN)) { + const bool m_csrind = state->mstateen[0]->read() & MSTATEEN0_CSRIND; + const bool h_csrind = state->hstateen[0]->read() & HSTATEEN0_CSRIND; + if (!m_csrind) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !h_csrind) + throw trap_virtual_instruction(insn.bits()); + } + } + + // A virtual instruction exception is raised for attempts from VS-mode or VU-mode to directly access + // vsiselect or vsireg*, or attempts from VU-mode to access siselect or sireg*. + if (state->v and csr_priv < PRV_M){ + if (is_vsi) + throw trap_virtual_instruction(insn.bits()); + else if (state->prv == PRV_U) + throw trap_virtual_instruction(insn.bits()); + } csr_t_p proxy_csr = get_reg(); if (proxy_csr == nullptr) { - if (!state->v) { - throw trap_illegal_instruction(insn.bits()); - } else { - throw trap_virtual_instruction(insn.bits()); - } + // The spec recomends raising illegal if the proxy csr is not implemented. + throw trap_illegal_instruction(insn.bits()); } proxy_csr->verify_permissions(insn, write); + + // Don't call base verify_permission for VS registers remapped to S-mode + if (insn.csr() == address) + csr_t::verify_permissions(insn, write); + } @@ -1777,6 +1819,36 @@ bool sscsrind_reg_csr_t::unlogged_write(const reg_t val) noexcept { } // Returns the actual CSR that maps to value in *siselect or nullptr if no mapping exists +sscsrind_select_csr_t::sscsrind_select_csr_t(processor_t *const proc, const reg_t addr, + const reg_t init) + : basic_csr_t(proc, addr, init) {} + +void sscsrind_select_csr_t::verify_permissions(insn_t insn, bool write) const { + const auto csr_priv = get_field(insn.csr(), 0x300); + const bool is_vsi = csr_priv == PRV_HS; + // The CSRIND bit in mstateen0 controls access to the siselect, sireg*, vsiselect, and the vsireg* + if (proc->extension_enabled(EXT_SMSTATEEN) && state->prv < PRV_M) { + const bool m_csrind = state->mstateen[0]->read() & MSTATEEN0_CSRIND; + const bool h_csrind = state->hstateen[0]->read() & HSTATEEN0_CSRIND; + if (!m_csrind) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !h_csrind) + throw trap_virtual_instruction(insn.bits()); + } + // A virtual instruction exception is raised for attempts from VS-mode or VU-mode to directly access + // vsiselect or vsireg*, or attempts from VU-mode to access siselect or sireg*. + if (state->v){ + if (is_vsi){ + throw trap_virtual_instruction(insn.bits()); + } else if (state->prv == PRV_U) + throw trap_virtual_instruction(insn.bits()); + } + basic_csr_t::verify_permissions(insn, write); +}; + +// Returns the actual CSR that maps to value in *siselect or nullptr if no +// mapping exists csr_t_p sscsrind_reg_csr_t::get_reg() const noexcept { auto proxy = ireg_proxy; auto isel = iselect->read(); @@ -1878,3 +1950,46 @@ bool hstatus_csr_t::unlogged_write(const reg_t val) noexcept { proc->get_mmu()->flush_tlb(); return basic_csr_t::unlogged_write(new_hstatus); } + +scontext_csr_t::scontext_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init) : +masked_csr_t(proc, addr, mask, init){}; +void scontext_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && + !(state->mstateen[0]->read() & MSTATEEN0_HCONTEXT)) + throw trap_illegal_instruction(insn.bits()); + + if (state->v && !(state->hstateen[0]->read() & HSTATEEN0_SCONTEXT)) + throw trap_virtual_instruction(insn.bits()); + } + masked_csr_t::verify_permissions(insn, write); + +} + +hcontext_csr_t::hcontext_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init) : +masked_csr_t(proc, addr, mask, init){}; +void hcontext_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && + !(state->mstateen[0]->read() & MSTATEEN0_HCONTEXT)) + throw trap_illegal_instruction(insn.bits()); + + } + masked_csr_t::verify_permissions(insn, write); + +} + +hedelegh_csr_t::hedelegh_csr_t(processor_t* const proc, const reg_t addr, const reg_t init) : +const_csr_t(proc, addr, init){}; +void hedelegh_csr_t::verify_permissions(insn_t insn, bool write) const { + if (proc->get_const_xlen() != 32) + throw trap_illegal_instruction(insn.bits()); + if (proc->extension_enabled(EXT_SMSTATEEN)) { + if ((state->prv < PRV_M) && + !(state->mstateen[0]->read() & MSTATEEN0_PRIV113)) + throw trap_illegal_instruction(insn.bits()); + + } + const_csr_t::verify_permissions(insn, write); + +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 278bdb3713..058e56b741 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -849,6 +849,19 @@ class sscsrind_reg_csr_t : public csr_t { csr_t_p get_reg() const noexcept; }; +class sscsrind_select_csr_t: public basic_csr_t { + public: + sscsrind_select_csr_t(processor_t* const proc, const reg_t addr, const reg_t init); + protected: + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class virtualized_select_indirect_csr_t: public virtualized_csr_t { + public: + virtualized_select_indirect_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + // smcntrpmf_csr_t caches the previous state of the CSR in case a CSRW instruction // modifies the state that should not be immediately visible to bump() class smcntrpmf_csr_t : public masked_csr_t { @@ -899,4 +912,22 @@ class hstatus_csr_t final: public basic_csr_t { protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; + +class scontext_csr_t: public masked_csr_t { + public: + scontext_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class hcontext_csr_t: public masked_csr_t { + public: + hcontext_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class hedelegh_csr_t: public const_csr_t { + public: + hedelegh_csr_t(processor_t* const proc, const reg_t addr, const reg_t init); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; #endif diff --git a/riscv/encoding.h b/riscv/encoding.h index dcd4e248ed..4411ac2506 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -4,7 +4,7 @@ /* * This file is auto-generated by running 'make' in - * https://github.com/riscv/riscv-opcodes (47862ce) + * https://github.com/riscv/riscv-opcodes (9f70bcd) */ #ifndef RISCV_CSR_ENCODING_H @@ -81,8 +81,9 @@ #define USTATUS_UPIE 0x00000010 #define MNSTATUS_NMIE 0x00000008 -#define MNSTATUS_MNPP 0x00001800 #define MNSTATUS_MNPV 0x00000080 +#define MNSTATUS_MNPELP 0x00000200 +#define MNSTATUS_MNPP 0x00001800 #define DCSR_XDEBUGVER (15U<<28) #define DCSR_EXTCAUSE (7<<24) @@ -194,6 +195,7 @@ #define MSTATEEN0_FCSR 0x00000002 #define MSTATEEN0_JVT 0x00000004 #define MSTATEEN0_CTR 0x0040000000000000 +#define MSTATEEN0_PRIV113 0x0100000000000000 #define MSTATEEN0_PRIV114 0x0080000000000000 #define MSTATEEN0_HCONTEXT 0x0200000000000000 #define MSTATEEN0_AIA 0x0800000000000000 @@ -202,6 +204,7 @@ #define MSTATEEN_HSTATEEN 0x8000000000000000 #define MSTATEEN0H_CTR 0x00400000 +#define MSTATEEN0H_PRIV113 0x01000000 #define MSTATEEN0H_PRIV114 0x00800000 #define MSTATEEN0H_HCONTEXT 0x02000000 #define MSTATEEN0H_AIA 0x08000000 @@ -2768,6 +2771,7 @@ #define CSR_VSIEH 0x214 #define CSR_VSIPH 0x254 #define CSR_VSTIMECMPH 0x25d +#define CSR_HEDELEGH 0x612 #define CSR_HTIMEDELTAH 0x615 #define CSR_HIDELEGH 0x613 #define CSR_HVIENH 0x618 @@ -4313,6 +4317,7 @@ DECLARE_CSR(stimecmph, CSR_STIMECMPH) DECLARE_CSR(vsieh, CSR_VSIEH) DECLARE_CSR(vsiph, CSR_VSIPH) DECLARE_CSR(vstimecmph, CSR_VSTIMECMPH) +DECLARE_CSR(hedelegh, CSR_HEDELEGH) DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) DECLARE_CSR(hidelegh, CSR_HIDELEGH) DECLARE_CSR(hvienh, CSR_HVIENH)