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 committed Dec 27, 2024
1 parent b80c37a commit 8be71d2
Showing 1 changed file with 175 additions and 56 deletions.
231 changes: 175 additions & 56 deletions src/isa/riscv64/system/priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -2319,69 +2319,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 @@ -2416,6 +2365,172 @@ 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;
// mireg
if (is_access(mireg)) {
if (miselect->val <= ISELECT_2F_MASK) {
// 0x00-0x2f reserved
longjmp_exception(EX_II);
}
else if (miselect->val <= ISELECT_3F_MASK) {
// 0x30-0x3f major interrupt priorities
#ifdef CONFIG_RV_AIA
if (miselect->val & 0x1) {
longjmp_exception(EX_II);
}
#else
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (miselect->val <= ISELECT_6F_MASK) {
// 0x40-0x6f reserved
longjmp_exception(EX_II);
}
else if (miselect->val <= ISELECT_MAX_MASK) {
// 0x70-0xff external interrupts(only with an IMSIC)
#ifdef CONFIG_RV_IMSIC
if (miselect->val > ISELECT_7F_MASK && (miselect->val & 0x1)) {
longjmp_exception(EX_II);
}
#else
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else {
// 0x100- reserved
longjmp_exception(EX_II);
}
}
// sireg
if (is_access(sireg)) {
if (MUXDEF(CONFIG_RVH, !cpu.v, 1)) {
if (siselect->val <= ISELECT_2F_MASK) {
// 0x00-0x2f reserved
longjmp_exception(EX_II);
}
else if (siselect->val <= ISELECT_3F_MASK) {
// 0x30-0x3f major interrupt priorities
#ifdef CONFIG_RV_AIA
if (siselect->val & 0x1) {
longjmp_exception(EX_II);
}
#else
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (siselect->val <= ISELECT_6F_MASK) {
// 0x40-0x6f reserved
longjmp_exception(EX_II);
}
else if (siselect->val <= ISELECT_MAX_MASK) {
// 0x70-0xff external interrupts(only with an IMSIC)
#ifdef CONFIG_RV_IMSIC
if ((cpu.mode == MODE_S) && mvien->seie) {
longjmp_exception(EX_II);
}
if (siselect->val > ISELECT_7F_MASK && siselect->val & 0x1) {
longjmp_exception(EX_II);
}
#else
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else {
// 0x100- reserved
longjmp_exception(EX_II);
}
}
#ifdef CONFIG_RVH
if (cpu.v) {
if (vsiselect->val <= ISELECT_2F_MASK) {
// 0x00-0x2f reserved
longjmp_exception(EX_II);
}
else if (vsiselect->val <= ISELECT_3F_MASK) {
// 0x30-0x3f inaccessible for aia
#ifdef CONFIG_RV_AIA
has_vi = true;
#else
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else if (vsiselect->val <= ISELECT_6F_MASK) {
// 0x40-0x6f reserverd
longjmp_exception(EX_II);
}
else if (vsiselect->val <= ISELECT_MAX_MASK) {
// 0x70-0xff
#ifdef CONFIG_RV_AIA
#ifdef CONFIG_RV_IMSIC
if (hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) {
longjmp_exception(EX_VI);
}
if (vsiselect->val > ISELECT_7F_MASK && (vsiselect->val & 0x1)) {
longjmp_exception(EX_VI);
}
#else // !CONFIG_RV_IMSIC
// inaccessible
longjmp_exception(EX_VI);
#endif // CONFIG_RV_IMSIC
#else // !CONFIG_RV_AIA
// unimplemented iselect value
longjmp_exception(EX_II);
#endif // CONFIG_RV_AIA
}
else {
// 0x100- reserved for future use
longjmp_exception(EX_II);
}
}
#endif // CONFIG_RVH
}
// vsireg
#ifdef CONFIG_RVH
if (is_access(vsireg)) {
if (vsiselect->val <= ISELECT_2F_MASK) {
// 0x00-0x2f reserved
longjmp_exception(EX_II);
}
else if (vsiselect->val <= ISELECT_3F_MASK) {
// 0x30-0x3f
// unimplemented iselect value OR inaccessible for aia
longjmp_exception(EX_II);
}
else if (vsiselect->val <= ISELECT_6F_MASK) {
// reserved
longjmp_exception(EX_II);
}
else if (vsiselect->val <= ISELECT_MAX_MASK) {
#ifdef CONFIG_RV_IMSIC
// external interrupts(IMSIC only)
if (hstatus->vgein == 0 || hstatus->vgein > CONFIG_GEILEN) {
longjmp_exception(EX_II);
}
if (vsiselect->val > ISELECT_7F_MASK && (vsiselect->val & 0x1)) {
longjmp_exception(EX_II);
}
#else
// unimplemented iselect value OR inaccessible for aia
longjmp_exception(EX_II);
#endif // CONFIG_RV_IMSIC
}
else {
// 0x100- reserved
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 @@ -2445,6 +2560,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 8be71d2

Please sign in to comment.