diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index 104a4dc9a7..e7b4fc5859 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -247,14 +247,20 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) } else if (ext_str == "zkr") { extension_table[EXT_ZKR] = true; } else if (ext_str == "zkt") { + } else if (ext_str == "smcfiss") { + extension_table[EXT_SMCFISS] = true; } else if (ext_str == "smepmp") { extension_table[EXT_SMEPMP] = true; } else if (ext_str == "smstateen") { extension_table[EXT_SMSTATEEN] = true; + } else if (ext_str == "smpmpind") { + extension_table[EXT_SMPMPIND] = true; } else if (ext_str == "smpmpmt") { extension_table[EXT_SMPMPMT] = true; } else if (ext_str == "smrnmi") { extension_table[EXT_SMRNMI] = true; + } else if (ext_str == "smucfiss") { + extension_table[EXT_SMUCFISS] = true; } else if (ext_str == "sscofpmf") { extension_table[EXT_SSCOFPMF] = true; } else if (ext_str == "svadu") { @@ -562,6 +568,15 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) !extension_table[EXT_ZCMOP]) { bad_isa_string(str, "'Zicfiss' extension requires 'Zcmop' extension when `Zca` is supported"); } + if (extension_table[EXT_SMCFISS] && !extension_table[EXT_ZICFISS]) { + bad_isa_string(str, "'Smcfiss' extension requires 'Zicfiss'"); + } + if (extension_table[EXT_SMCFISS] && !extension_table[EXT_SMPMPIND]) { + bad_isa_string(str, "'Smcfiss' extension requires 'Smpmpind'"); + } + if (extension_table[EXT_SMUCFISS] && !extension_table[EXT_SMCFISS]) { + bad_isa_string(str, "'Smucfiss' extension requires 'Smcfiss'"); + } #ifdef WORDS_BIGENDIAN // Access to the vector registers as element groups is unimplemented on big-endian setups. if (extension_table[EXT_ZVKG] || extension_table[EXT_ZVKNHA] || extension_table[EXT_ZVKNHB] || @@ -607,6 +622,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table['U'] = user; extension_table['S'] = supervisor; + if (extension_table[EXT_SMUCFISS] && (extension_table['S'] || !extension_table['U'])) { + bad_isa_string(str, "'Smucfiss' extension is only supported for M+U systems"); + } + if (extension_table['H'] && !supervisor) bad_isa_string(str, "'H' extension requires S mode"); diff --git a/riscv/csr_init.cc b/riscv/csr_init.cc index ffb11ecfeb..20f1178081 100644 --- a/riscv/csr_init.cc +++ b/riscv/csr_init.cc @@ -441,13 +441,29 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa) csr_t_p miselect = std::make_shared(proc, CSR_MISELECT, 0); add_csr(CSR_MISELECT, miselect); - sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg; + sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg, mireg2; add_csr(CSR_MIREG, mireg = std::make_shared(proc, CSR_MIREG, miselect)); if (proc->extension_enabled_const(EXT_SMAIA)) add_iprio_proxy(proc, mireg); - const reg_t mireg_csrs[] = { CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; + add_csr(CSR_MIREG2, mireg2 = std::make_shared(proc, CSR_MIREG2, miselect)); + const reg_t mireg_csrs[] = { CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 }; for (auto csr : mireg_csrs) add_csr(csr, std::make_shared(proc, csr, miselect)); + + if (proc->extension_enabled_const(EXT_SMPMPIND)) { + // For indirect access to PMP registers, `miselect` selects the target PMP + // entry; `mireg` accesses its `pmpaddr` register, and `mireg2` accesses its + // `pmpcfg` register. Attempts to access `mireg3` through `mireg6` raise an + // illegal instruction exception. + // The mireg2 (mireg_csrs[0]) proxies to ind_pmpcfg_csr_t objects as there + // is no direct proxy for these registers. In the ind_pmpcfg_csr_t object, + // the address member holds the entry number (i). + for (int i = 0; i < max_pmp; ++i) { + mireg->add_ireg_proxy(MISELECT_PMPIND_START + i, pmpaddr[i]); + auto ind_pmpcfg = std::make_shared(proc, i); + mireg2->add_ireg_proxy(MISELECT_PMPIND_START + i, ind_pmpcfg); + } + } } if (proc->extension_enabled_const(EXT_SSCSRIND)) { diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 249c76d52a..cb138b82d7 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -182,17 +182,43 @@ bool pmpaddr_csr_t::subset_match(reg_t addr, reg_t len) const noexcept { return !(is_tor ? tor_homogeneous : napot_homogeneous); } -bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx) const noexcept { +bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx, bool ss_access) const noexcept { + const uint8_t xwr = cfg & (PMP_X | PMP_W | PMP_R); const bool cfgx = cfg & PMP_X; const bool cfgw = cfg & PMP_W; const bool cfgr = cfg & PMP_R; const bool cfgl = cfg & PMP_L; - - const bool prvm = mode == PRV_M; - const bool typer = type == LOAD; const bool typex = type == FETCH; const bool typew = type == STORE; + const bool prvm = mode == PRV_M; + const bool prvu = mode == PRV_U; + const bool msse = state->mseccfg->get_msse(); + const bool usse = ((state->menvcfg->read() & MENVCFG_SSE) != 0) && + proc->extension_enabled(EXT_SMUCFISS); + const bool is_m_ss_rgn = E && (xwr == PMP_W) && msse; + const bool is_u_ss_rgn = E && (xwr == (PMP_W | PMP_X)) && usse; + /* + * Shadow-stack access rules (Smcfiss / Smucfiss): + * - Shadow-stack accesses with effective privilege mode M are permitted + * only when accessing an M-mode shadow-stack region. Loads with effective + * privilege mode M are permitted to read an M-mode shadow-stack region. + * - When Smucfiss is implemented, shadow-stack accesses with effective + * privilege mode U are permitted only when accessing a U-mode shadow-stack + * region. Loads with effective privilege mode U are permitted to read a + * U-mode shadow-stack region. + * - All other accesses (stores, instruction fetches, or accesses from an + * incorrect privilege mode) to M-mode or U-mode shadow-stack regions are + * disallowed. + * - When E = 1 and the PMP entry does not denote a valid shadow-stack + * region, all accesses are disallowed. + */ + if (ss_access && prvm) return is_m_ss_rgn; + if (ss_access && prvu && proc->extension_enabled(EXT_SMUCFISS)) return is_u_ss_rgn; + if (is_m_ss_rgn) return prvm && typer && !hlvx; + if (is_u_ss_rgn) return prvu && typer && !hlvx; + if (E) return false; + const bool normal_rwx = (typer && cfgr && (!hlvx || cfgx)) || (typew && cfgw) || (typex && cfgx); const bool mseccfg_mml = state->mseccfg->get_mml(); @@ -238,47 +264,55 @@ reg_t pmpcfg_csr_t::read() const noexcept { return cfg_res; } +void pmpcfg_csr_t::update_pmpcfg_entry(const size_t index, const uint8_t cfg_in, const bool E) { + const bool locked = (state->pmpaddr[index]->cfg & PMP_L); + const bool rlb = state->mseccfg->get_rlb(); + const bool mml = state->mseccfg->get_mml(); + uint8_t cfg = cfg_in; + if (rlb || !locked) { + // Drop R=0 W=1 when MML = 0 + // Remove the restriction when MML = 1 or, when E=1 + if (!mml && !E) { + cfg &= ~PMP_W | ((cfg & PMP_R) ? PMP_W : 0); + } + // Disallow A=NA4 when granularity > 4 + if (proc->lg_pmp_granularity != PMP_SHIFT && (cfg & PMP_A) == PMP_NA4) + cfg |= PMP_NAPOT; + // MT value 0x3 is reserved + if (get_field(cfg, PMP_MT) == 0x3) + cfg = set_field(cfg, PMP_MT, 0); + /* + * Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region + * is not possible and such pmpcfg writes are ignored, leaving pmpcfg unchanged. + * This restriction can be temporarily lifted e.g. during the boot process, by setting mseccfg.RLB. + */ + const bool cfgx = cfg & PMP_X; + const bool cfgw = cfg & PMP_W; + const bool cfgr = cfg & PMP_R; + if (rlb || !(mml && ((cfg & PMP_L) // M-mode-only or a locked Shared-Region + && !(cfgx && cfgw && cfgr) // RWX = 111 is allowed + && (cfgx || (cfgw && !cfgr)) // X=1 or RW=01 is not allowed + && !E // Only apply this restruction when E=0 + ))) { + state->pmpaddr[index]->cfg = cfg; + state->pmpaddr[index]->E = E; + } + } + return; +} + bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept { if (proc->n_pmp == 0) return false; bool write_success = false; - const bool rlb = state->mseccfg->get_rlb(); - const bool mml = state->mseccfg->get_mml(); for (size_t i0 = (address - CSR_PMPCFG0) * 4, i = i0; i < i0 + proc->get_xlen() / 8; i++) { if (i < proc->n_pmp) { - const bool locked = (state->pmpaddr[i]->cfg & PMP_L); - if (rlb || !locked) { - uint8_t all_cfg_fields = (PMP_R | PMP_W | PMP_X | PMP_A | - (proc->extension_enabled(EXT_SMPMPMT) ? PMP_MT : 0) | + uint8_t all_cfg_fields = (PMP_R | PMP_W | PMP_X | PMP_A | + (proc->extension_enabled(EXT_SMPMPMT) ? PMP_MT : 0) | PMP_L); - uint8_t cfg = (val >> (8 * (i - i0))) & all_cfg_fields; - // Drop R=0 W=1 when MML = 0 - // Remove the restriction when MML = 1 - if (!mml) { - cfg &= ~PMP_W | ((cfg & PMP_R) ? PMP_W : 0); - } - // Disallow A=NA4 when granularity > 4 - if (proc->lg_pmp_granularity != PMP_SHIFT && (cfg & PMP_A) == PMP_NA4) - cfg |= PMP_NAPOT; - // MT value 0x3 is reserved - if (get_field(cfg, PMP_MT) == 0x3) - cfg = set_field(cfg, PMP_MT, 0); - /* - * Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region - * is not possible and such pmpcfg writes are ignored, leaving pmpcfg unchanged. - * This restriction can be temporarily lifted e.g. during the boot process, by setting mseccfg.RLB. - */ - const bool cfgx = cfg & PMP_X; - const bool cfgw = cfg & PMP_W; - const bool cfgr = cfg & PMP_R; - if (rlb || !(mml && ((cfg & PMP_L) // M-mode-only or a locked Shared-Region - && !(cfgx && cfgw && cfgr) // RWX = 111 is allowed - && (cfgx || (cfgw && !cfgr)) // X=1 or RW=01 is not allowed - ))) { - state->pmpaddr[i]->cfg = cfg; - } - } + uint8_t cfg = (val >> (8 * (i - i0))) & all_cfg_fields; + update_pmpcfg_entry(i, cfg, 0); write_success = true; } } @@ -286,6 +320,34 @@ bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept { return write_success; } +ind_pmpcfg_csr_t::ind_pmpcfg_csr_t(processor_t* const proc, const reg_t addr): + pmpcfg_csr_t(proc, addr) { +} + +reg_t ind_pmpcfg_csr_t::read() const noexcept { + // Bit MXLEN-1 of the pmpcfg register is the extended-attributes (E) field. + // The address member of this object holds the PMP entry index. + return state->pmpaddr[address]->cfg | + ((proc->get_const_xlen() == 32) + ? (state->pmpaddr[address]->E ? PMPCFG32_E : 0) + : (state->pmpaddr[address]->E ? PMPCFG64_E : 0)); +} + +bool ind_pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept { + const bool E = (proc->get_const_xlen() == 32) + ? ((val & PMPCFG32_E) ? 1 : 0) + : ((val & PMPCFG64_E) ? 1 : 0); + // The low 8 bits of the indirect pmpcfg register alias to the + // PMP configurations accessible via the direct CSRs + const uint8_t cfg = val & 0xFF; + + // The address member of this object holds the PMP entry index. + update_pmpcfg_entry(address, cfg, E); + + proc->get_mmu()->flush_tlb(); + return true; +} + // implement class mseccfg_csr_t mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr): basic_csr_t(proc, addr, 0) { @@ -319,6 +381,9 @@ bool mseccfg_csr_t::get_useed() const noexcept { bool mseccfg_csr_t::get_sseed() const noexcept { return (read() & MSECCFG_SSEED); } +bool mseccfg_csr_t::get_msse() const noexcept { + return (read() & MSECCFG_MSSE); +} bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept { reg_t new_val = read(); @@ -351,6 +416,11 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept { new_val |= (val & MSECCFG_MLPE); } + if (proc->extension_enabled(EXT_SMCFISS)) { + new_val &= ~MSECCFG_MSSE; + new_val |= (val & MSECCFG_MSSE); + } + if (proc->extension_enabled(EXT_SMMPM)) { const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM reg_t pmm = get_field(val, MSECCFG_PMM); diff --git a/riscv/csrs.h b/riscv/csrs.h index b1d5a3ba43..f3e6deb4bc 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -102,7 +102,7 @@ class pmpaddr_csr_t: public csr_t { bool subset_match(reg_t addr, reg_t len) const noexcept; // Is the specified access allowed given the pmpcfg privileges? - bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept; + bool access_ok(access_type type, reg_t mode, bool hlvx, bool ss_access) const noexcept; // To check lock bit status from outside like mseccfg bool is_locked() const noexcept { @@ -127,8 +127,10 @@ class pmpaddr_csr_t: public csr_t { bool next_locked_and_tor() const noexcept; reg_t val; - friend class pmpcfg_csr_t; // so he can access cfg + friend class pmpcfg_csr_t; // so he can access cfg + friend class ind_pmpcfg_csr_t; // so he can access cfg uint8_t cfg; + bool E; // Extended attribute (E) const size_t pmpidx; }; @@ -141,6 +143,7 @@ class pmpcfg_csr_t: public csr_t { virtual reg_t read() const noexcept override; protected: virtual bool unlogged_write(const reg_t val) noexcept override; + virtual void update_pmpcfg_entry(const size_t index, const uint8_t cfg_in, const bool E); }; class mseccfg_csr_t: public basic_csr_t { @@ -152,6 +155,7 @@ class mseccfg_csr_t: public basic_csr_t { bool get_rlb() const noexcept; bool get_useed() const noexcept; bool get_sseed() const noexcept; + bool get_msse() const noexcept; protected: virtual bool unlogged_write(const reg_t val) noexcept override; }; @@ -877,6 +881,14 @@ class sscsrind_reg_csr_t : public csr_t { csr_t_p get_reg() const noexcept; }; +class ind_pmpcfg_csr_t: public pmpcfg_csr_t { + public: + ind_pmpcfg_csr_t(processor_t* const proc, const reg_t addr); + reg_t read() const noexcept override; + protected: + virtual bool unlogged_write(const reg_t val) noexcept 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 { diff --git a/riscv/encoding.h b/riscv/encoding.h index 5203544b88..3e444a8079 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -284,11 +284,15 @@ #define MISELECT_IMSIC _RISCV_UL(0x70) #define MISELECT_IMSIC_TOP _RISCV_UL(0xff) + #define SISELECT_IPRIO _RISCV_UL(0x30) #define SISELECT_IPRIO_TOP _RISCV_UL(0x3f) #define SISELECT_IMSIC _RISCV_UL(0x70) #define SISELECT_IMSIC_TOP _RISCV_UL(0xff) +#define MISELECT_PMPIND_START _RISCV_UL(0x300) +#define MISELECT_PMPIND_TOP _RISCV_UL(0x33F) + #define VSISELECT_IMSIC _RISCV_UL(0x70) #define VSISELECT_IMSIC_TOP _RISCV_UL(0xff) @@ -330,6 +334,7 @@ #define MSECCFG_USEED _RISCV_UL(0x00000100) #define MSECCFG_SSEED _RISCV_UL(0x00000200) #define MSECCFG_MLPE _RISCV_UL(0x00000400) +#define MSECCFG_MSSE _RISCV_UL(0x00000800) #define MSECCFG_PMM _RISCV_ULL(0x0000000300000000) /* jvt fields */ @@ -393,6 +398,8 @@ #define SPMP_U _RISCV_UL(0x100) #define SPMP_SHARED _RISCV_UL(0x200) +#define PMPCFG64_E _RISCV_UL(0x8000000000000000) +#define PMPCFG32_E _RISCV_UL(0x80000000) #define MCTRCTL_U _RISCV_ULL(0x0000000000000001) #define MCTRCTL_S _RISCV_ULL(0x0000000000000002) diff --git a/riscv/insns/ssamoswap_d.h b/riscv/insns/ssamoswap_d.h index 4169ac3e50..5dd1b36cec 100644 --- a/riscv/insns/ssamoswap_d.h +++ b/riscv/insns/ssamoswap_d.h @@ -3,5 +3,11 @@ require_extension(EXT_ZAAMO); require_rv64; DECLARE_XENVCFG_VARS(SSE); -require_envcfg(SSE); + +if (p->extension_enabled('S')) { + require_envcfg(SSE); +} else { + require_extension(EXT_SMUCFISS); + require(mSSE); +} WRITE_RD(MMU.ssamoswap(RS1, RS2)); diff --git a/riscv/insns/ssamoswap_w.h b/riscv/insns/ssamoswap_w.h index d971ebece8..c5b3dde65a 100644 --- a/riscv/insns/ssamoswap_w.h +++ b/riscv/insns/ssamoswap_w.h @@ -3,4 +3,10 @@ require_extension(EXT_ZAAMO); DECLARE_XENVCFG_VARS(SSE); require_envcfg(SSE); +if (p->extension_enabled('S')) { + require_envcfg(SSE); +} else { + require_extension(EXT_SMUCFISS); + require(mSSE); +} WRITE_RD(sext32(MMU.ssamoswap(RS1, RS2))); diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index 101ce81063..1cc7a8eb43 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -38,10 +38,13 @@ typedef enum { EXT_ZVFHMIN, EXT_ZVFOFP4MIN, EXT_ZVFOFP8MIN, + EXT_SMCFISS, EXT_SMEPMP, EXT_SMSTATEEN, + EXT_SMPMPIND, EXT_SMPMPMT, EXT_SMRNMI, + EXT_SMUCFISS, EXT_SSCOFPMF, EXT_SVADU, EXT_SVADE, diff --git a/riscv/mmu.cc b/riscv/mmu.cc index e2ca0f0356..06f519a909 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -79,7 +79,8 @@ reg_t mmu_t::translate(mem_access_info_t access_info, reg_t len) reg_t mode = (reg_t) access_info.effective_priv; reg_t paddr = walk(access_info) | (addr & (PGSIZE-1)); - if (!pmp_ok(paddr, len, access_info.flags.ss_access ? STORE : type, mode, access_info.flags.hlvx)) + if (!pmp_ok(paddr, len, access_info.flags.ss_access ? STORE : type, mode, + access_info.flags.hlvx, access_info.flags.ss_access)) throw_access_exception(virt, addr, access_info.flags.ss_access ? STORE : type); return paddr; } @@ -484,8 +485,7 @@ tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_ return entry; } -bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx) -{ +bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx, bool ss_access) { if (!proc || proc->n_pmp == 0) return true; @@ -508,7 +508,7 @@ bool mmu_t::pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlv if (!all_match) return false; - return proc->state.pmpaddr[i]->access_ok(type, mode, hlvx); + return proc->state.pmpaddr[i]->access_ok(type, mode, hlvx, ss_access); } } @@ -671,7 +671,10 @@ reg_t mmu_t::walk(mem_access_info_t access_info) bool ss_access = access_info.flags.ss_access; - if (ss_access) { + if (ss_access && + ((virt == 1) || (mode == PRV_S) || + (mode == PRV_M && !proc->extension_enabled(EXT_SMCFISS)) || + (mode == PRV_U && !proc->extension_enabled(EXT_SMUCFISS)))) { if (vm.levels == 0) throw trap_store_access_fault(virt, addr, 0, 0); type = STORE; diff --git a/riscv/mmu.h b/riscv/mmu.h index 5ba0854eb3..ecf0c98b54 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -467,7 +467,7 @@ class mmu_t const size_t ptesize = sizeof(T); - if (!pmp_ok(pte_paddr, ptesize, LOAD, PRV_S, false)) + if (!pmp_ok(pte_paddr, ptesize, LOAD, PRV_S, false, false)) throw_access_exception(virt, addr, trap_type); void* host_pte_addr = sim->addr_to_mem(pte_paddr); @@ -487,7 +487,7 @@ class mmu_t { const size_t ptesize = sizeof(T); - if (!pmp_ok(pte_paddr, ptesize, STORE, PRV_S, false)) + if (!pmp_ok(pte_paddr, ptesize, STORE, PRV_S, false, false)) throw_access_exception(virt, addr, trap_type); void* host_pte_addr = sim->addr_to_mem(pte_paddr); @@ -529,7 +529,7 @@ class mmu_t } reg_t pmp_homogeneous(reg_t addr, reg_t len); - bool pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx); + bool pmp_ok(reg_t addr, reg_t len, access_type type, reg_t mode, bool hlvx, bool ss_access); #ifdef RISCV_ENABLE_DUAL_ENDIAN bool target_big_endian; diff --git a/riscv/zicfiss.h b/riscv/zicfiss.h index c7aef64b9a..83489d54f2 100644 --- a/riscv/zicfiss.h +++ b/riscv/zicfiss.h @@ -3,11 +3,27 @@ #ifndef _RISCV_ZICFISS_H #define _RISCV_ZICFISS_H -#define xSSE() \ - ((STATE.prv != PRV_M) && get_field(STATE.menvcfg->read(), MENVCFG_SSE) && \ - p->extension_enabled('S') && \ - ((STATE.v && get_field(STATE.henvcfg->read(), HENVCFG_SSE)) || !STATE.v) && \ - (((STATE.prv == PRV_U) && get_field(STATE.senvcfg->read(), SENVCFG_SSE)) || (STATE.prv != PRV_U))) +#define xSSE() \ + ( \ + /* M-mode: xSSE = mseccfg.MSSE (RO-0 if Smcfiss not implemented) */ \ + ((STATE.prv == PRV_M) && \ + get_field(STATE.mseccfg->read(), MSECCFG_MSSE)) || \ + \ + /* U-mode w/o S-mode: Smucfiss uses menvcfg.SSE */ \ + ((STATE.prv == PRV_U) && \ + !p->extension_enabled('S') && \ + p->extension_enabled(EXT_SMUCFISS) && \ + get_field(STATE.menvcfg->read(), MENVCFG_SSE)) || \ + \ + /* Otherwise (< M): original S-mode based gating */ \ + ((STATE.prv != PRV_M) && \ + p->extension_enabled('S') && \ + get_field(STATE.menvcfg->read(), MENVCFG_SSE) && \ + ((STATE.v && get_field(STATE.henvcfg->read(), HENVCFG_SSE)) || !STATE.v) && \ + (((STATE.prv == PRV_U) && \ + get_field(STATE.senvcfg->read(), SENVCFG_SSE)) || \ + (STATE.prv != PRV_U))) \ + ) #define PUSH_VALUE_TO_SS(value) ({ \ reg_t push_value = (value); \