From 9ba5bd3171e97560bc28fe555ff7b8404272a3bb Mon Sep 17 00:00:00 2001 From: SuHsien Ho Date: Wed, 4 Oct 2023 15:00:49 +0800 Subject: Add Zicfiss extension from CFI extension, v0.4.0 1. Add EXT_ZICFISS for enable Zicfiss with zicfiss extension name. 2. Add new software exception with tval 3 for shadow stack. 3. Implement sspush_x1/sspush_x5/sspopchk_x1/sspopchk_x5/ssrdp/ssamoswap_w/ssamoswap_d. 4. Implement c_sspush_x1/c_sspopchk_x5 in c_lui.h which has same encoding. 5. Add new special access type ss_access in xlate_flags_t for checking special read/write permission in SS(Shadow Stack) page. 6. Add new ss_load/ss_store/ssamoswap to enable ss_access flag. 7. Check special pte(xwr=010) of SS page. --- disasm/disasm.cc | 62 ++++++++++++++++++++++++++++++++++++++++++--- disasm/isa_parser.cc | 12 +++++++++ riscv/csrs.cc | 10 ++++++++ riscv/csrs.h | 7 +++++ riscv/decode.h | 1 + riscv/encoding.h | 1 + riscv/insns/c_lui.h | 8 +++++- riscv/insns/c_sspopchk_x5.h | 5 ++++ riscv/insns/c_sspush_x1.h | 5 ++++ riscv/insns/ssamoswap_d.h | 7 +++++ riscv/insns/ssamoswap_w.h | 7 +++++ riscv/insns/sspopchk_x1.h | 7 +++++ riscv/insns/sspopchk_x5.h | 1 + riscv/insns/sspush_x1.h | 7 +++++ riscv/insns/sspush_x5.h | 1 + riscv/insns/ssrdp.h | 7 +++++ riscv/isa_parser.h | 1 + riscv/mmu.cc | 29 ++++++++++++++++++--- riscv/mmu.h | 32 ++++++++++++++++++++++- riscv/overlap_list.h | 7 +++++ riscv/processor.cc | 14 +++++++--- riscv/processor.h | 2 ++ riscv/riscv.mk.in | 12 +++++++++ riscv/zicfiss.h | 31 +++++++++++++++++++++++ 24 files changed, 265 insertions(+), 11 deletions(-) create mode 100644 riscv/insns/c_sspopchk_x5.h create mode 100644 riscv/insns/c_sspush_x1.h create mode 100644 riscv/insns/ssamoswap_d.h create mode 100644 riscv/insns/ssamoswap_w.h create mode 100644 riscv/insns/sspopchk_x1.h create mode 100644 riscv/insns/sspopchk_x5.h create mode 100644 riscv/insns/sspush_x1.h create mode 100644 riscv/insns/sspush_x5.h create mode 100644 riscv/insns/ssrdp.h create mode 100644 riscv/zicfiss.h diff --git a/disasm/disasm.cc b/disasm/disasm.cc index a33cb71..187a1d5 100644 --- a/disasm/disasm.cc +++ b/disasm/disasm.cc @@ -267,6 +267,18 @@ struct : public arg_t { } rvc_sp; struct : public arg_t { + std::string to_string(insn_t UNUSED insn) const { + return xpr_name[X_RA]; + } +} rvc_ra; + +struct : public arg_t { + std::string to_string(insn_t UNUSED insn) const { + return xpr_name[X_T0]; + } +} rvc_t0; + +struct : public arg_t { std::string to_string(insn_t insn) const { return std::to_string((int)insn.rvc_imm()); } @@ -2184,6 +2196,13 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) } if (isa->extension_enabled(EXT_ZIMOP)) { + #define DISASM_MOP_R(name, rs1, rd) \ + add_insn(new disasm_insn_t(#name, match_##name | (rs1 << 15) | (rd << 7), \ + 0xFFFFFFFF, {&xrd, &xrs1})); + + #define DISASM_MOP_RR(name, rs1, rd, rs2) \ + add_insn(new disasm_insn_t(#name, match_##name | (rs1 << 15) | (rd << 7) | (rs2 << 20), \ + 0xFFFFFFFF, {&xrd, &xrs1, &xrs2})); DEFINE_R1TYPE(mop_r_0); DEFINE_R1TYPE(mop_r_1); DEFINE_R1TYPE(mop_r_2); @@ -2212,7 +2231,15 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_R1TYPE(mop_r_25); DEFINE_R1TYPE(mop_r_26); DEFINE_R1TYPE(mop_r_27); - DEFINE_R1TYPE(mop_r_28); + if (!isa->extension_enabled(EXT_ZICFISS)) { + DEFINE_R1TYPE(mop_r_28); + } else { + // Add code points of mop_r_28 not used by Zicfiss + for (unsigned rd_val = 0; rd_val <= 31; ++rd_val) + for (unsigned rs1_val = 0; rs1_val <= 31; ++rs1_val) + if ((rd_val != 0 && rs1_val !=0) || (rd_val == 0 && !(rs1_val == 1 || rs1_val == 5))) + DISASM_MOP_R(mop_r_28, rs1_val, rd_val); + } DEFINE_R1TYPE(mop_r_29); DEFINE_R1TYPE(mop_r_30); DEFINE_R1TYPE(mop_r_31); @@ -2224,12 +2251,24 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_RTYPE(mop_rr_5); DEFINE_RTYPE(mop_rr_6); DEFINE_RTYPE(mop_rr_7); + if (!isa->extension_enabled(EXT_ZICFISS)) { + DEFINE_RTYPE(mop_rr_7); + } else { + // Add code points of mop_rr_7 not used by Zicfiss + for (unsigned rd_val = 0; rd_val <= 31; ++rd_val) + for (unsigned rs1_val = 0; rs1_val <= 31; ++rs1_val) + for (unsigned rs2_val = 0; rs2_val <= 31; ++rs2_val) + if ((rs2_val != 1 && rs2_val != 5) || rd_val != 0 || rs1_val != 0) + DISASM_MOP_RR(mop_rr_7, rs1_val, rd_val, rs2_val); + } } if (isa->extension_enabled(EXT_ZCMOP)) { - DISASM_INSN("c.mop.1", c_mop_1, 0, {}); + if (!isa->extension_enabled(EXT_ZICFISS)) + DISASM_INSN("c.mop.1", c_mop_1, 0, {}); DISASM_INSN("c.mop.3", c_mop_3, 0, {}); - DISASM_INSN("c.mop.5", c_mop_5, 0, {}); + if (!isa->extension_enabled(EXT_ZICFISS)) + DISASM_INSN("c.mop.5", c_mop_5, 0, {}); DISASM_INSN("c.mop.7", c_mop_7, 0, {}); DISASM_INSN("c.mop.9", c_mop_9, 0, {}); DISASM_INSN("c.mop.11", c_mop_11, 0, {}); @@ -2392,6 +2431,23 @@ void disassembler_t::add_instructions(const isa_parser_t* isa) DEFINE_XSTORE_BASE(sw_rl); DEFINE_XSTORE_BASE(sd_rl); } + + if(isa->extension_enabled(EXT_ZICFISS)) { + DISASM_INSN("sspush", sspush_x1, 0, {&xrs2}); + DISASM_INSN("sspush", sspush_x5, 0, {&xrs2}); + DISASM_INSN("sspopchk", sspopchk_x1, 0, {&xrs1}); + DISASM_INSN("sspopchk", sspopchk_x5, 0, {&xrs1}); + DISASM_INSN("ssrdp", ssrdp, 0, {&xrd}); + DEFINE_XAMO(ssamoswap_w); + + if(isa->get_max_xlen() == 64) + DEFINE_XAMO(ssamoswap_d) + + if (isa->extension_enabled(EXT_ZCA)) { + DISASM_INSN("c.sspush", c_sspush_x1, 0, {&rvc_ra}); + DISASM_INSN("c.sspopchk", c_sspopchk_x5, 0, {&rvc_t0}); + } + } } disassembler_t::disassembler_t(const isa_parser_t *isa) diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc index 3a99d0a..e0bebec 100644 --- a/disasm/isa_parser.cc +++ b/disasm/isa_parser.cc @@ -308,6 +308,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) extension_table[EXT_SSQOSID] = true; } else if (ext_str == "zicfilp") { extension_table[EXT_ZICFILP] = true; + } else if (ext_str == "zicfiss") { + extension_table[EXT_ZICFISS] = true; } else if (ext_str[0] == 'x') { extension_table['X'] = true; if (ext_str.size() == 1) { @@ -393,6 +395,16 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv) (extension_table[EXT_ZVKG] || extension_table[EXT_ZVKNED] || extension_table[EXT_ZVKSH])) { bad_isa_string(str, "'Zvkg', 'Zvkned', and 'Zvksh' extensions are incompatible with 'Zpn' extension in rv64"); } + + // When SSE is 0, Zicfiss behavior is defined by Zicmop + if (extension_table[EXT_ZICFISS] && !extension_table[EXT_ZIMOP]) { + bad_isa_string(str, "'Zicfiss' extension requires 'Zimop' extension"); + } + + if (extension_table[EXT_ZICFISS] && extension_table[EXT_ZCA] && + !extension_table[EXT_ZCMOP]) { + bad_isa_string(str, "'Zicfiss' extension requires 'Zcmop' extension when `Zca` is supported"); + } #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] || diff --git a/riscv/csrs.cc b/riscv/csrs.cc index 4a612e5..2bd8b0d 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -1757,3 +1757,13 @@ bool hvip_csr_t::unlogged_write(const reg_t val) noexcept { state->mip->write_with_mask(MIP_VSSIP, val); // hvip.VSSIP is an alias of mip.VSSIP return basic_csr_t::unlogged_write(val & (MIP_VSEIP | MIP_VSTIP)); } + +ssp_csr_t::ssp_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 ssp_csr_t::verify_permissions(insn_t insn, bool write) const { + masked_csr_t::verify_permissions(insn, write); + DECLARE_XENVCFG_VARS(SSE); + require_envcfg(SSE); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 2595243..0920544 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -871,4 +871,11 @@ class hvip_csr_t : public basic_csr_t { }; typedef std::shared_ptr hvip_csr_t_p; + +// ssp CSR provided by CFI Zicfiss extension +class ssp_csr_t final : public masked_csr_t { + public: + ssp_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; +}; #endif diff --git a/riscv/decode.h b/riscv/decode.h index cd1c0a1..f36c04e 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -26,6 +26,7 @@ const int NCSR = 4096; #define X_RA 1 #define X_SP 2 +#define X_T0 5 #define X_S0 8 #define X_A0 10 #define X_A1 11 diff --git a/riscv/encoding.h b/riscv/encoding.h index ff3f743..d600fa2 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -348,6 +348,7 @@ /* software check exception xtval codes */ #define LANDING_PAD_FAULT 2 +#define SHADOW_STACK_FAULT 3 #ifdef __riscv diff --git a/riscv/insns/c_lui.h b/riscv/insns/c_lui.h index 7a82c13..98a8898 100644 --- a/riscv/insns/c_lui.h +++ b/riscv/insns/c_lui.h @@ -5,7 +5,13 @@ if (insn.rvc_rd() == 2) { // c.addi16sp } else if (insn.rvc_imm() != 0) { // c.lui WRITE_RD(insn.rvc_imm() << 12); } else if ((insn.rvc_rd() & 0x11) == 1) { // c.mop.N - #include "c_mop_N.h" + if (insn.rvc_rd() == 5 && p->extension_enabled(EXT_ZICFISS)) { + #include "c_sspopchk_x5.h" + } else if (insn.rvc_rd() == 1 && p->extension_enabled(EXT_ZICFISS)) { + #include "c_sspush_x1.h" + } else { + #include "c_mop_N.h" + } } else { require(false); } diff --git a/riscv/insns/c_sspopchk_x5.h b/riscv/insns/c_sspopchk_x5.h new file mode 100644 index 0000000..d379f2c --- /dev/null +++ b/riscv/insns/c_sspopchk_x5.h @@ -0,0 +1,5 @@ +#include "zicfiss.h" + +if (xSSE()) { + POP_VALUE_FROM_SS_AND_CHECK(READ_REG(X_T0)); +} diff --git a/riscv/insns/c_sspush_x1.h b/riscv/insns/c_sspush_x1.h new file mode 100644 index 0000000..3645a9e --- /dev/null +++ b/riscv/insns/c_sspush_x1.h @@ -0,0 +1,5 @@ +#include "zicfiss.h" + +if (xSSE()) { + PUSH_VALUE_TO_SS(RA); +} diff --git a/riscv/insns/ssamoswap_d.h b/riscv/insns/ssamoswap_d.h new file mode 100644 index 0000000..10ea5ef --- /dev/null +++ b/riscv/insns/ssamoswap_d.h @@ -0,0 +1,7 @@ +require_extension(EXT_ZICFISS); +require_extension('A'); +require_rv64; + +DECLARE_XENVCFG_VARS(SSE); +require_envcfg(SSE); +WRITE_RD(MMU.ssamoswap(RS1, RS2)); diff --git a/riscv/insns/ssamoswap_w.h b/riscv/insns/ssamoswap_w.h new file mode 100644 index 0000000..3cdefc7 --- /dev/null +++ b/riscv/insns/ssamoswap_w.h @@ -0,0 +1,7 @@ +require_extension(EXT_ZICFISS); +require_extension('A'); + +DECLARE_XENVCFG_VARS(SSE); +require_envcfg(SSE); +WRITE_RD(sext32(MMU.ssamoswap(RS1, RS2))); + diff --git a/riscv/insns/sspopchk_x1.h b/riscv/insns/sspopchk_x1.h new file mode 100644 index 0000000..6ea4c22 --- /dev/null +++ b/riscv/insns/sspopchk_x1.h @@ -0,0 +1,7 @@ +#include "zicfiss.h" + +if (xSSE()) { + POP_VALUE_FROM_SS_AND_CHECK(RS1); +} else { + #include "mop_r_N.h" +} diff --git a/riscv/insns/sspopchk_x5.h b/riscv/insns/sspopchk_x5.h new file mode 100644 index 0000000..78218b3 --- /dev/null +++ b/riscv/insns/sspopchk_x5.h @@ -0,0 +1 @@ +#include "sspopchk_x1.h" diff --git a/riscv/insns/sspush_x1.h b/riscv/insns/sspush_x1.h new file mode 100644 index 0000000..67ad9bb --- /dev/null +++ b/riscv/insns/sspush_x1.h @@ -0,0 +1,7 @@ +#include "zicfiss.h" + +if (xSSE()) { + PUSH_VALUE_TO_SS(RS2); +} else { + #include "mop_rr_N.h" +} diff --git a/riscv/insns/sspush_x5.h b/riscv/insns/sspush_x5.h new file mode 100644 index 0000000..235333d --- /dev/null +++ b/riscv/insns/sspush_x5.h @@ -0,0 +1 @@ +#include "sspush_x1.h" diff --git a/riscv/insns/ssrdp.h b/riscv/insns/ssrdp.h new file mode 100644 index 0000000..20b0856 --- /dev/null +++ b/riscv/insns/ssrdp.h @@ -0,0 +1,7 @@ +#include "zicfiss.h" + +if (xSSE()) { + WRITE_RD(STATE.ssp->read()); +} else { + #include "mop_r_N.h" +} diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h index f02b55d..72e8211 100644 --- a/riscv/isa_parser.h +++ b/riscv/isa_parser.h @@ -88,6 +88,7 @@ typedef enum { EXT_ZALASR, EXT_SSQOSID, EXT_ZICFILP, + EXT_ZICFISS, NUM_ISA_EXTENSIONS } isa_extension_t; diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 1a0c830..8660b71 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -63,7 +63,7 @@ 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, type, mode)) + if (!pmp_ok(paddr, len, access_info.flags.ss_access ? STORE : type, mode)) throw_access_exception(virt, addr, type); return paddr; } @@ -491,6 +491,15 @@ reg_t mmu_t::walk(mem_access_info_t access_info) reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; reg_t satp = proc->get_state()->satp->readvirt(virt); vm_info vm = decode_vm_info(proc->get_const_xlen(), false, mode, satp); + + bool ss_access = access_info.flags.ss_access; + + if (ss_access) { + if (vm.levels == 0) + trap_store_access_fault(virt, addr, 0, 0); + type = STORE; + } + if (vm.levels == 0) return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx, false) & ~page_mask; // zero-extend from xlen @@ -516,6 +525,7 @@ reg_t mmu_t::walk(mem_access_info_t access_info) reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; bool pbmte = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_PBMTE) : (proc->get_state()->menvcfg->read() & MENVCFG_PBMTE); bool hade = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_ADUE) : (proc->get_state()->menvcfg->read() & MENVCFG_ADUE); + bool sse = virt ? (proc->get_state()->henvcfg->read() & HENVCFG_SSE) : (proc->get_state()->menvcfg->read() & MENVCFG_SSE); if (pte & PTE_RSVD) { break; @@ -531,11 +541,24 @@ reg_t mmu_t::walk(mem_access_info_t access_info) base = ppn << PGSHIFT; } else if ((pte & PTE_U) ? s_mode && (type == FETCH || !sum) : !s_mode) { break; - } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { + } else if (!(pte & PTE_V) || + (!(pte & PTE_R) && (pte & PTE_W) && ((!sse && !(pte & PTE_X)) || (pte & PTE_X)))) { + // invalid + // not shadow stack access xwr=110 or xwr=010 page cause page fault + // shadow stack access with PTE_X moved to following check break; + } else if ((!(pte & PTE_R) && (pte & PTE_W) && !(pte & PTE_X)) && (type == STORE && !ss_access)) { + // not shadow stack store and xwr = 010 cause access-fault + throw trap_store_access_fault(virt, addr, 0, 0); + } else if ((!(pte & PTE_R) && (pte & PTE_W) && !(pte & PTE_X)) && type == FETCH) { + // fetch from shadow stack pages cause instruction access-fault + throw trap_instruction_access_fault(virt, addr, 0, 0); + } else if ((((pte & PTE_R) && (pte & PTE_W)) || (pte & PTE_X)) && ss_access) { + // shadow stack access cause store access fault if xwr!=010 and xwr!=001 + throw trap_store_access_fault(virt, addr, 0, 0); } else if (type == FETCH || hlvx ? !(pte & PTE_X) : type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : - !((pte & PTE_R) && (pte & PTE_W))) { + !(pte & PTE_W)) { break; } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { break; diff --git a/riscv/mmu.h b/riscv/mmu.h index 4404e4c..b218bf6 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -42,9 +42,10 @@ struct xlate_flags_t { const bool forced_virt : 1 {false}; const bool hlvx : 1 {false}; const bool lr : 1 {false}; + const bool ss_access : 1 {false}; bool is_special_access() const { - return forced_virt || hlvx || lr; + return forced_virt || hlvx || lr || ss_access; } }; @@ -127,6 +128,14 @@ public: return load(addr, {.forced_virt=true, .hlvx=true}); } + // shadow stack load + template + T ss_load(reg_t addr) { + if ((addr & (sizeof(T) - 1)) != 0) + throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0); + return load(addr, {.forced_virt=false, .hlvx=false, .lr=false, .ss_access=true}); + } + template void ALWAYS_INLINE store(reg_t addr, T val, xlate_flags_t xlate_flags = {}) { reg_t vpn = addr >> PGSHIFT; @@ -149,6 +158,14 @@ public: store(addr, val, {.forced_virt=true}); } + // shadow stack store + template + void ss_store(reg_t addr, T val) { + if ((addr & (sizeof(T) - 1)) != 0) + throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0); + store(addr, val, {.forced_virt=false, .hlvx=false, .lr=false, .ss_access=true}); + } + // AMO/Zicbom faults should be reported as store faults #define convert_load_traps_to_store_traps(BODY) \ try { \ @@ -175,6 +192,19 @@ public: }) } + // for shadow stack amoswap + template + T ssamoswap(reg_t addr, reg_t value) { + bool forced_virt = false; + bool hlvx = false; + bool lr = false; + bool ss_access = true; + store_slow_path(addr, sizeof(T), nullptr, {forced_virt, hlvx, lr, ss_access}, false, true); + auto data = load(addr, {forced_virt, hlvx, lr, ss_access}); + store(addr, value, {forced_virt, hlvx, lr, ss_access}); + return data; + } + template T amo_compare_and_swap(reg_t addr, T comp, T swap) { convert_load_traps_to_store_traps({ diff --git a/riscv/overlap_list.h b/riscv/overlap_list.h index 3084c36..6c943bd 100644 --- a/riscv/overlap_list.h +++ b/riscv/overlap_list.h @@ -22,3 +22,10 @@ DECLARE_OVERLAP_INSN(rstsa32, EXT_ZPN) DECLARE_OVERLAP_INSN(srli32_u, EXT_ZPN) DECLARE_OVERLAP_INSN(umax32, EXT_ZPN) DECLARE_OVERLAP_INSN(lpad, EXT_ZICFILP) +DECLARE_OVERLAP_INSN(mop_r_28, EXT_ZIMOP) +DECLARE_OVERLAP_INSN(mop_r_N, EXT_ZIMOP) +DECLARE_OVERLAP_INSN(mop_rr_7, EXT_ZIMOP) +DECLARE_OVERLAP_INSN(mop_rr_N, EXT_ZIMOP) +DECLARE_OVERLAP_INSN(c_sspush_x1, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(c_sspopchk_x5, EXT_ZICFISS) +DECLARE_OVERLAP_INSN(c_mop_N, EXT_ZCMOP) diff --git a/riscv/processor.cc b/riscv/processor.cc index 3a1eadb..7a63f3c 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -453,7 +453,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) (proc->extension_enabled(EXT_SVADU) ? MENVCFG_ADUE: 0) | (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) | (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0); + (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? MENVCFG_SSE : 0); const reg_t menvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0); menvcfg = std::make_shared(proc, CSR_MENVCFG, menvcfg_mask, menvcfg_init); if (xlen == 32) { @@ -464,14 +465,16 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) } const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE : 0) | (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0); + (proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? SENVCFG_SSE : 0); csrmap[CSR_SENVCFG] = senvcfg = std::make_shared(proc, CSR_SENVCFG, senvcfg_mask, 0); const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE : 0) | (proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE : 0) | (proc->extension_enabled(EXT_SVADU) ? HENVCFG_ADUE: 0) | (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) | (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0) | - (proc->extension_enabled(EXT_ZICFILP) ? HENVCFG_LPE : 0); + (proc->extension_enabled(EXT_ZICFILP) ? HENVCFG_LPE : 0) | + (proc->extension_enabled(EXT_ZICFISS) ? HENVCFG_SSE : 0); const reg_t henvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0); henvcfg = std::make_shared(proc, CSR_HENVCFG, henvcfg_mask, henvcfg_init, menvcfg); if (xlen == 32) { @@ -536,6 +539,11 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) if (proc->extension_enabled(EXT_ZCMT)) csrmap[CSR_JVT] = jvt = std::make_shared(proc, CSR_JVT, 0); + if (proc->extension_enabled(EXT_ZICFISS)) { + reg_t ssp_mask = -reg_t(xlen / 8); + csrmap[CSR_SSP] = ssp = std::make_shared(proc, CSR_SSP, ssp_mask, 0); + } + // Smcsrind / Sscsrind sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg[6]; diff --git a/riscv/processor.h b/riscv/processor.h index ec42418..f3e5294 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -173,6 +173,8 @@ struct state_t csr_t_p srmcfg; + csr_t_p ssp; + bool serialized; // whether timer CSRs are in a well-defined state // When true, execute a single instruction and then enter debug mode. This diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 0c4a14b..f388426 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -1395,6 +1395,17 @@ riscv_insn_ext_zimop = \ riscv_insn_ext_zicfilp = \ lpad +riscv_insn_ext_zicfiss = \ + sspush_x1 \ + sspush_x5 \ + sspopchk_x1 \ + sspopchk_x5 \ + ssrdp \ + ssamoswap_w \ + ssamoswap_d \ + c_sspush_x1 \ + c_sspopchk_x5 \ + riscv_insn_ext_zvk = \ $(riscv_insn_ext_zvbb) \ $(riscv_insn_ext_zvbc) \ @@ -1435,6 +1446,7 @@ riscv_insn_list = \ $(riscv_insn_svinval) \ $(riscv_insn_ext_zimop) \ $(riscv_insn_ext_zicfilp) \ + $(riscv_insn_ext_zicfiss) \ riscv_gen_srcs = $(addsuffix .cc,$(riscv_insn_list)) diff --git a/riscv/zicfiss.h b/riscv/zicfiss.h new file mode 100644 index 0000000..83c166d --- /dev/null +++ b/riscv/zicfiss.h @@ -0,0 +1,31 @@ +// See LICENSE for license details. + +#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 PUSH_VALUE_TO_SS(value) ({ \ + reg_t push_value = (value); \ + reg_t push_ssp_addr = STATE.ssp->read() - xlen / 8; \ + if (xlen == 32) \ + MMU.ss_store(push_ssp_addr, push_value); \ + else \ + MMU.ss_store(push_ssp_addr, push_value); \ + STATE.ssp->write(push_ssp_addr); \ + }) + +#define POP_VALUE_FROM_SS_AND_CHECK(value) \ + reg_t shadow_return_addr; \ + if (xlen == 32) \ + shadow_return_addr = MMU.ss_load(STATE.ssp->read()); \ + else \ + shadow_return_addr = MMU.ss_load(STATE.ssp->read()); \ + software_check(value == shadow_return_addr, SHADOW_STACK_FAULT); \ + STATE.ssp->write(STATE.ssp->read() + xlen / 8); + +#endif -- cgit v1.1