Skip to content

Commit

Permalink
Fix issues with smcsrind not considering stateen, throw illegal on
Browse files Browse the repository at this point in the history
missing proxy csr and check for csr privilege in sscsring_reg_csr_t
since mireg uses the same class.
Add stateen checks for scontext/hcontext
Fix for issue: 1893
  • Loading branch information
JJ-Gaisler committed Jan 28, 2025
1 parent 49727e8 commit a8e9876
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 15 deletions.
14 changes: 8 additions & 6 deletions riscv/csr_init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
add_csr(CSR_TINFO, std::make_shared<const_csr_t>(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<masked_csr_t>(proc, CSR_SCONTEXT, (reg_t(1) << scontext_length) - 1, 0));
add_supervisor_csr(CSR_SCONTEXT, scontext = std::make_shared<scontext_csr_t>(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<masked_csr_t>(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0);
auto hcontext = std::make_shared<hcontext_csr_t>(proc, CSR_HCONTEXT, (reg_t(1) << hcontext_length) - 1, 0);
add_hypervisor_csr(CSR_HCONTEXT, hcontext);
add_csr(CSR_MCONTEXT, mcontext = std::make_shared<proxy_csr_t>(proc, CSR_MCONTEXT, hcontext));
add_csr(CSR_MSECCFG, mseccfg = std::make_shared<mseccfg_csr_t>(proc, CSR_MSECCFG));
Expand Down Expand Up @@ -284,7 +284,8 @@ 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 hstateen0_mask = sstateen0_mask | HSTATEEN0_SENVCFG | HSTATEEN_SSTATEEN |
(proc->extension_enabled(EXT_SSCSRIND) ? HSTATEEN0_CSRIND : 0);
const reg_t mstateen0_mask = hstateen0_mask | (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;
Expand Down Expand Up @@ -349,11 +350,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<basic_csr_t>(proc, CSR_VSISELECT, 0);
auto vsiselect = std::make_shared<sscsrind_select_csr_t>(proc, CSR_VSISELECT, 0);
add_hypervisor_csr(CSR_VSISELECT, vsiselect);

csr_t_p siselect = std::make_shared<basic_csr_t>(proc, CSR_SISELECT, 0);
add_supervisor_csr(CSR_SISELECT, std::make_shared<virtualized_csr_t>(proc, siselect, vsiselect));
auto siselect = std::make_shared<sscsrind_select_csr_t>(proc, CSR_SISELECT, 0);
// Correct virtualized type?
add_supervisor_csr(CSR_SISELECT, std::make_shared<virtualized_select_indirect_csr_t>(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 };
Expand Down
118 changes: 109 additions & 9 deletions riscv/csrs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) :
Expand All @@ -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);

}


Expand All @@ -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();
Expand Down Expand Up @@ -1878,3 +1950,31 @@ 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);

}
25 changes: 25 additions & 0 deletions riscv/csrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -899,4 +912,16 @@ 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;
};
#endif

0 comments on commit a8e9876

Please sign in to comment.