Skip to content

Commit

Permalink
fix(csr, exception): check exception for indirect csr finally
Browse files Browse the repository at this point in the history
Before this, we assumed that all possible exceptions during CSR
read and write operations should be handled according to their priority.

Therefore, we used has_vi to record whether a virtual instruction exception
exists and ensured that all illegal instruction exceptions take precedence
over virtual instruction exceptions.

However, with the implementation of certain extensions like Smcsrind and
Smstateen, we encounter scenarios where virtual instruction exceptions must
take precedence over illegal instruction exceptions triggered.

For instance, when mstateen0.csrind is set to 1 and hstateen0.csrind is 0,
a virtual instruction exception should be raised if VS mode attempts to
access sireg. However, if the vsiselect value is reserved in this situation,
an illegal instruction exception will be raised instead. If these checks are
treated as being at the same priority level, an illegal instruction exception
would ultimately be raised.

In reality, a virtual instruction exception should take precedence because
when the extension is disabled, we should not even evaluate the value of
vsiselect.

We should first check whether the CSR exists, is read-only, has proper
permissions, and is enabled/disabled before proceeding to check indirect CSR
accesses.
  • Loading branch information
NewPaulWalker authored and huxuan0307 committed Jan 9, 2025
1 parent 32c0d5a commit 173f240
Showing 1 changed file with 108 additions and 56 deletions.
164 changes: 108 additions & 56 deletions src/isa/riscv64/system/priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -2315,69 +2315,18 @@ static bool aia_extension_permit_check(const word_t *dest_access, bool is_write)
longjmp_exception(EX_II);
}
}
if (is_access(mireg)) {
if (
(miselect->val <= ISELECT_2F_MASK) ||
(miselect->val > ISELECT_2F_MASK && miselect->val <= ISELECT_3F_MASK && miselect->val & 0x1) ||
(miselect->val > ISELECT_3F_MASK && miselect->val <= ISELECT_6F_MASK) ||
(miselect->val > ISELECT_7F_MASK && miselect->val <= ISELECT_MAX_MASK && miselect->val & 0x1) ||
(miselect->val > ISELECT_MAX_MASK)
) {
longjmp_exception(EX_II);
}
}
if (is_access(sireg)) {
if (!cpu.v) {
if (
(siselect->val <= ISELECT_2F_MASK) ||
(siselect->val > ISELECT_2F_MASK && siselect->val <= ISELECT_3F_MASK && siselect->val & 0x1) ||
(siselect->val > ISELECT_3F_MASK && siselect->val <= ISELECT_6F_MASK) ||
(cpu.mode == MODE_S && mvien->seie && siselect->val > ISELECT_6F_MASK && siselect->val <= ISELECT_MAX_MASK) ||
(siselect->val > ISELECT_7F_MASK && siselect->val <= ISELECT_MAX_MASK && siselect->val & 0x1) ||
(siselect->val > ISELECT_MAX_MASK)
) {
longjmp_exception(EX_II);
}
}
if (cpu.v) {
if (
(vsiselect->val <= ISELECT_2F_MASK) ||
(vsiselect->val > ISELECT_3F_MASK && vsiselect->val <= ISELECT_6F_MASK) ||
(vsiselect->val > ISELECT_MAX_MASK)
) {
longjmp_exception(EX_II);
}
if (
(vsiselect->val > ISELECT_2F_MASK && vsiselect->val <= ISELECT_3F_MASK) ||
((hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) && vsiselect->val > ISELECT_6F_MASK && vsiselect->val <= ISELECT_MAX_MASK) ||
(vsiselect->val > ISELECT_7F_MASK && vsiselect->val <= ISELECT_MAX_MASK && vsiselect->val & 0x1)
) {
has_vi = true;
}
}
}
if (is_access(vsireg)) {
if (
(vsiselect->val <= ISELECT_6F_MASK) ||
((hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) && vsiselect->val > ISELECT_6F_MASK && vsiselect->val <= ISELECT_MAX_MASK) ||
(vsiselect->val > ISELECT_7F_MASK && vsiselect->val <= ISELECT_MAX_MASK && vsiselect->val & 0x1) ||
(vsiselect->val > ISELECT_MAX_MASK)
) {
longjmp_exception(EX_II);
}
}
if (is_access(sip) || is_access(sie)) {
if (cpu.v && (cpu.mode == MODE_S)) {
if (hvictl->vti) {
has_vi = true;
}
if (cpu.v && (cpu.mode == MODE_S) && hvictl->vti) {
has_vi = true;
}
}
#ifdef CONFIG_RV_SSTC
if (is_access(stimecmp)) {
if (cpu.v && (cpu.mode == MODE_S) && hvictl->vti && is_write) {
has_vi = 1;
has_vi = true;
}
}
#endif // CONFIG_RV_SSTC
return has_vi;
}
#endif // CONFIG_RV_IMSIC
Expand Down Expand Up @@ -2412,6 +2361,105 @@ static inline bool vec_permit_check(const word_t *dest_access) {
}
#endif // CONFIG_RVV

#ifdef CONFIG_RV_IMSIC
static inline bool csrind_permit_check(const word_t *dest_access) {
bool has_vi = false;

if (is_access(mireg)) {
if (miselect->val <= ISELECT_2F_MASK) longjmp_exception(EX_II);
else if (miselect->val <= ISELECT_3F_MASK) {
#ifdef CONFIG_RV_AIA
if (miselect->val & 0x1) longjmp_exception(EX_II);
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (miselect->val <= ISELECT_6F_MASK) longjmp_exception(EX_II);
else if (miselect->val <= ISELECT_MAX_MASK) {
#ifdef CONFIG_RV_IMSIC
if (miselect->val > ISELECT_7F_MASK && (miselect->val & 0x1)) longjmp_exception(EX_II);
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else longjmp_exception(EX_II);
}

if (is_access(sireg)) {
if (MUXDEF(CONFIG_RVH, !cpu.v, 1)) {
if (siselect->val <= ISELECT_2F_MASK) longjmp_exception(EX_II);
else if (siselect->val <= ISELECT_3F_MASK) {
#ifdef CONFIG_RV_AIA
if (siselect->val & 0x1) longjmp_exception(EX_II);
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (siselect->val <= ISELECT_6F_MASK) longjmp_exception(EX_II);
else if (siselect->val <= ISELECT_MAX_MASK) {
#ifdef CONFIG_RV_IMSIC
if (
((cpu.mode == MODE_S) && mvien->seie) ||
(siselect->val > ISELECT_7F_MASK && (siselect->val & 0x1))
) longjmp_exception(EX_II);
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else longjmp_exception(EX_II);
}
#ifdef CONFIG_RVH
if (cpu.v) {
if (vsiselect->val <= ISELECT_2F_MASK) longjmp_exception(EX_II);
else if (vsiselect->val <= ISELECT_3F_MASK) {
#ifdef CONFIG_RV_AIA
has_vi = true;
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (vsiselect->val <= ISELECT_6F_MASK) longjmp_exception(EX_II);
else if (vsiselect->val <= ISELECT_MAX_MASK) {
#ifdef CONFIG_RV_AIA
#ifdef CONFIG_RV_IMSIC
if (
(hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) ||
(vsiselect->val > ISELECT_7F_MASK && (vsiselect->val & 0x1))
) has_vi = true;
#else // !CONFIG_RV_IMSIC
has_vi = true;
#endif // CONFIG_RV_IMSIC
#else // !CONFIG_RV_AIA
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else longjmp_exception(EX_II);
}
#endif // CONFIG_RVH
}

#ifdef CONFIG_RVH
if (is_access(vsireg)) {
if (vsiselect->val <= ISELECT_2F_MASK) longjmp_exception(EX_II);
else if (vsiselect->val <= ISELECT_3F_MASK) longjmp_exception(EX_II);
else if (vsiselect->val <= ISELECT_6F_MASK) longjmp_exception(EX_II);
else if (vsiselect->val <= ISELECT_MAX_MASK) {
#ifdef CONFIG_RV_IMSIC
if (
(hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) ||
(vsiselect->val > ISELECT_7F_MASK && (vsiselect->val & 0x1))
) longjmp_exception(EX_II);
#else
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else longjmp_exception(EX_II);
}
#endif // CONFIG_RVH
return has_vi;
}
#endif // CONFIG_RV_IMSIC

static inline void csr_permit_check(uint32_t addr, bool is_write) {
bool has_vi = false; // virtual instruction
word_t *dest_access = csr_decode(addr);
Expand Down Expand Up @@ -2441,6 +2489,10 @@ static inline void csr_permit_check(uint32_t addr, bool is_write) {

if (has_vi) longjmp_exception(EX_VI);

// We should first check whether the CSR exists, is read-only, has proper permissions, and is enabled/disabled
// before proceeding to check indirect CSR accesses.
IFDEF(CONFIG_RV_IMSIC, has_vi |= csrind_permit_check(dest_access));
if (has_vi) longjmp_exception(EX_VI);
}
static void csrrw(rtlreg_t *dest, const rtlreg_t *src, uint32_t csrid, uint32_t instr) {
ISADecodeInfo isa;
Expand Down

0 comments on commit 173f240

Please sign in to comment.