From 1aaefcb24197067f9a0a3cd078688d027d766cf1 Mon Sep 17 00:00:00 2001 From: linzhida Date: Fri, 27 Dec 2024 10:29:54 +0800 Subject: [PATCH] fix(csr, exception): check exception for indirect csr finally 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. --- src/isa/riscv64/system/priv.c | 164 ++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 56 deletions(-) diff --git a/src/isa/riscv64/system/priv.c b/src/isa/riscv64/system/priv.c index 9af1c66b8..7a3b4dcc7 100644 --- a/src/isa/riscv64/system/priv.c +++ b/src/isa/riscv64/system/priv.c @@ -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 @@ -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); @@ -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;