Skip to content

Smcsrind exception fixex #1896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions riscv/csr_init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<masked_csr_t>(proc, CSR_HEDELEG, hedeleg_mask, 0));
add_hypervisor_csr(CSR_HEDELEGH, std::make_shared<hedelegh_csr_t>(proc, CSR_HEDELEGH, 0));
add_hypervisor_csr(CSR_HCOUNTEREN, hcounteren = std::make_shared<masked_csr_t>(proc, CSR_HCOUNTEREN, counteren_mask, 0));
htimedelta = std::make_shared<basic_csr_t>(proc, CSR_HTIMEDELTA, 0);
if (xlen == 32) {
Expand Down Expand Up @@ -215,9 +216,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,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<masked_csr_t>(proc, CSR_MSTATEEN0 + i, mstateen_mask, 0);
Expand Down Expand Up @@ -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<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
133 changes: 124 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,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);

}
31 changes: 31 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,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
9 changes: 7 additions & 2 deletions riscv/encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down