From 6f3963a473824ec0851fa85456ba363dc8454e29 Mon Sep 17 00:00:00 2001 From: Stanislaw Kaushanski Date: Mon, 7 Sep 2020 11:54:45 +0200 Subject: [PATCH] Strip down privileged modes. Only machine mode is supported --- incl/iss/arch/riscv_hart_m_p.h | 253 ++++++--------------------------- 1 file changed, 40 insertions(+), 213 deletions(-) diff --git a/incl/iss/arch/riscv_hart_m_p.h b/incl/iss/arch/riscv_hart_m_p.h index b4d6051..7077506 100644 --- a/incl/iss/arch/riscv_hart_m_p.h +++ b/incl/iss/arch/riscv_hart_m_p.h @@ -174,8 +174,6 @@ enum riscv_csr { namespace { -std::array lvl = {{'U', 'S', 'H', 'M'}}; - std::array trap_str = {{"" "Instruction address misaligned", // 0 "Instruction access fault", // 1 @@ -326,8 +324,8 @@ public: static const reg_t mstatus_reset_val = 0; - void write_mstatus(T val, unsigned priv_lvl) { - auto mask = get_mask(priv_lvl); + void write_mstatus(T val) { + auto mask = get_mask(); auto new_val = (mstatus.st.value & ~mask) | (val & mask); mstatus = new_val; } @@ -336,41 +334,19 @@ public: static constexpr T get_misa() { return (1UL << 30) | ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M; } - static constexpr uint32_t get_mask(unsigned priv_lvl) { -#if __cplusplus < 201402L - return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL; -#else - switch (priv_lvl) { - case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001 - case PRIV_S: return 0x800de133UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011 - default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 - } -#endif + static constexpr uint32_t get_mask() { + return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 // only machine mode is supported } - static inline vm_info decode_vm_info(uint32_t state, T sptbr) { - if (state == PRIV_M) return {0, 0, 0, 0}; - if (state <= PRIV_S) - switch (bit_sub<31, 1>(sptbr)) { - case 0: return {0, 0, 0, 0}; // off - case 1: return {2, 10, 4, bit_sub<0, 22>(sptbr) << PGSHIFT}; // SV32 - default: abort(); - } - abort(); - return {0, 0, 0, 0}; // dummy + static inline vm_info decode_vm_info() { + return {0, 0, 0, 0}; } }; const typename super::reg_t PGSIZE = 1 << PGSHIFT; const typename super::reg_t PGMASK = PGSIZE - 1; - constexpr reg_t get_irq_mask(size_t mode) { - std::array m = {{ - 0b000100010001, // U mode - 0b001100110011, // S mode - 0, - 0b101110111011 // M mode - }}; - return m[mode]; + constexpr reg_t get_irq_mask() { + return 0b101110111011; // only machine mode is supported } riscv_hart_m_p(); @@ -396,8 +372,8 @@ public: void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; void disass_output(uint64_t pc, const std::string instr) override { - CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", - pc, instr, lvl[this->reg.machine_state], (reg_t)state.mstatus, this->reg.icount); + CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", + pc, instr, (reg_t)state.mstatus, this->reg.icount); }; iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } @@ -497,22 +473,10 @@ riscv_hart_m_p::riscv_hart_m_p() csr_rd_cb[minstreth] = &riscv_hart_m_p::read_cycle; csr_rd_cb[mstatus] = &riscv_hart_m_p::read_status; csr_wr_cb[mstatus] = &riscv_hart_m_p::write_status; - csr_rd_cb[sstatus] = &riscv_hart_m_p::read_status; - csr_wr_cb[sstatus] = &riscv_hart_m_p::write_status; - csr_rd_cb[ustatus] = &riscv_hart_m_p::read_status; - csr_wr_cb[ustatus] = &riscv_hart_m_p::write_status; csr_rd_cb[mip] = &riscv_hart_m_p::read_ip; csr_wr_cb[mip] = &riscv_hart_m_p::write_ip; - csr_rd_cb[sip] = &riscv_hart_m_p::read_ip; - csr_wr_cb[sip] = &riscv_hart_m_p::write_ip; - csr_rd_cb[uip] = &riscv_hart_m_p::read_ip; - csr_wr_cb[uip] = &riscv_hart_m_p::write_ip; csr_rd_cb[mie] = &riscv_hart_m_p::read_ie; csr_wr_cb[mie] = &riscv_hart_m_p::write_ie; - csr_rd_cb[sie] = &riscv_hart_m_p::read_ie; - csr_wr_cb[sie] = &riscv_hart_m_p::write_ie; - csr_rd_cb[uie] = &riscv_hart_m_p::read_ie; - csr_wr_cb[uie] = &riscv_hart_m_p::write_ie; csr_rd_cb[mhartid] = &riscv_hart_m_p::read_hartid; } @@ -583,7 +547,7 @@ iss::status riscv_hart_m_p::read(const address_type type, const access_typ } try { if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary - vm_info vm = hart_state::decode_vm_info(this->reg.machine_state, state.satp); + vm_info vm = hart_state::decode_vm_info(); if (vm.levels != 0) { // VM is active auto split_addr = (addr + length) & ~PGMASK; auto len1 = split_addr - addr; @@ -609,18 +573,7 @@ iss::status riscv_hart_m_p::read(const address_type type, const access_typ } break; case traits::FENCE: { if ((addr + length) > mem.size()) return iss::Err; - switch (addr) { - case 2: // SFENCE:VMA lower - case 3: { // SFENCE:VMA upper - auto tvm = state.mstatus.TVM; - if (this->reg.machine_state == PRIV_S & tvm != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - return iss::Err; - } - return iss::Ok; - } - } + return iss::Ok; } break; case traits::RES: { auto it = atomic_reservation.find(addr); @@ -677,7 +630,7 @@ iss::status riscv_hart_m_p::write(const address_type type, const access_ty } try { if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary - vm_info vm = hart_state::decode_vm_info(this->reg.machine_state, state.satp); + vm_info vm = hart_state::decode_vm_info(); if (vm.levels != 0) { // VM is active auto split_addr = (addr + length) & ~PGMASK; auto len1 = split_addr - addr; @@ -741,11 +694,6 @@ iss::status riscv_hart_m_p::write(const address_type type, const access_ty case 3: { ptw.clear(); auto tvm = state.mstatus.TVM; - if (this->reg.machine_state == PRIV_S & tvm != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - return iss::Err; - } return iss::Ok; } } @@ -817,14 +765,12 @@ template iss::status riscv_hart_m_p::read_time(unsigned ad } template iss::status riscv_hart_m_p::read_status(unsigned addr, reg_t &val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - val = state.mstatus & hart_state::get_mask(req_priv_lvl); + val = state.mstatus & hart_state::get_mask(); return iss::Ok; } template iss::status riscv_hart_m_p::write_status(unsigned addr, reg_t val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - state.write_mstatus(val, req_priv_lvl); + state.write_mstatus(val); check_interrupt(); update_vm_info(); return iss::Ok; @@ -832,8 +778,7 @@ template iss::status riscv_hart_m_p::write_status(unsigned template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t &val) { val = csr[mie]; - if (addr < mie) val &= csr[mideleg]; - if (addr < sie) val &= csr[sideleg]; + val &= csr[mideleg]; return iss::Ok; } @@ -843,8 +788,7 @@ template iss::status riscv_hart_m_p::read_hartid(unsigned } template iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - auto mask = get_irq_mask(req_priv_lvl); + auto mask = get_irq_mask(); csr[mie] = (csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; @@ -852,76 +796,18 @@ template iss::status riscv_hart_m_p::write_ie(unsigned add template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t &val) { val = csr[mip]; - if (addr < mip) val &= csr[mideleg]; - if (addr < sip) val &= csr[sideleg]; + val &= csr[mideleg]; return iss::Ok; } template iss::status riscv_hart_m_p::write_ip(unsigned addr, reg_t val) { - auto req_priv_lvl = (addr >> 8) & 0x3; - auto mask = get_irq_mask(req_priv_lvl); + auto mask = get_irq_mask(); mask &= ~(1 << 7); // MTIP is read only csr[mip] = (csr[mip] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } -template iss::status riscv_hart_m_p::read_satp(unsigned addr, reg_t &val) { - reg_t tvm = state.mstatus.TVM; - if (this->reg.machine_state == PRIV_S & tvm != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - return iss::Err; - } - val = state.satp; - return iss::Ok; -} - -template iss::status riscv_hart_m_p::write_satp(unsigned addr, reg_t val) { - reg_t tvm = state.mstatus.TVM; - if (this->reg.machine_state == PRIV_S & tvm != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - return iss::Err; - } - state.satp = val; - update_vm_info(); - return iss::Ok; -} -template iss::status riscv_hart_m_p::read_fcsr(unsigned addr, reg_t &val) { - switch (addr) { - case 1: // fflags, 4:0 - val = bit_sub<0, 5>(this->get_fcsr()); - break; - case 2: // frm, 7:5 - val = bit_sub<5, 3>(this->get_fcsr()); - break; - case 3: // fcsr - val = this->get_fcsr(); - break; - default: - return iss::Err; - } - return iss::Ok; -} - -template iss::status riscv_hart_m_p::write_fcsr(unsigned addr, reg_t val) { - switch (addr) { - case 1: // fflags, 4:0 - this->set_fcsr((this->get_fcsr() & 0xffffffe0) | (val & 0x1f)); - break; - case 2: // frm, 7:5 - this->set_fcsr((this->get_fcsr() & 0xffffff1f) | ((val & 0x7) << 5)); - break; - case 3: // fcsr - this->set_fcsr(val & 0xff); - break; - default: - return iss::Err; - } - return iss::Ok; -} - template iss::status riscv_hart_m_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { if ((paddr.val + length) > mem.size()) return iss::Err; @@ -1032,10 +918,10 @@ template inline void riscv_hart_m_p::reset(uint64_t addres } template inline void riscv_hart_m_p::update_vm_info() { - vm[1] = hart_state::decode_vm_info(this->reg.machine_state, state.satp); + vm[1] = hart_state::decode_vm_info(); BASE::addr_mode[3]=BASE::addr_mode[2] = vm[1].is_active()? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; if (state.mstatus.MPRV) - vm[0] = hart_state::decode_vm_info(state.mstatus.MPP, state.satp); + vm[0] = hart_state::decode_vm_info(); else vm[0] = vm[1]; BASE::addr_mode[1] = BASE::addr_mode[0]=vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; @@ -1057,11 +943,6 @@ template void riscv_hart_m_p::check_interrupt() { auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie); auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0; - if (enabled_interrupts == 0) { - auto sie = state.mstatus.SIE; - auto s_enabled = this->reg.machine_state < PRIV_S || (this->reg.machine_state == PRIV_S && sie); - enabled_interrupts = s_enabled ? ena_irq & ideleg : 0; - } if (enabled_interrupts != 0) { int res = 0; while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++; @@ -1094,7 +975,6 @@ typename riscv_hart_m_p::phys_addr_t riscv_hart_m_p::virt2phys(const const vm_info &vm = this->vm[static_cast(type) / 2]; - const bool s_mode = mode == PRIV_S; const bool sum = state.mstatus.SUM; const bool mxr = state.mstatus.MXR; @@ -1118,7 +998,7 @@ typename riscv_hart_m_p::phys_addr_t riscv_hart_m_p::virt2phys(const if (PTE_TABLE(pte)) { // next level of page table base = ppn << PGSHIFT; - } else if ((pte & PTE_U) ? s_mode && (type == iss::access_type::FETCH || !sum) : !s_mode) { + } else if (!(pte & PTE_U)) { break; } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { break; @@ -1163,36 +1043,22 @@ typename riscv_hart_m_p::phys_addr_t riscv_hart_m_p::virt2phys(const } template uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t addr) { - auto cur_priv = this->reg.machine_state; // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // calculate and write mcause val auto trap_id = bit_sub<0, 16>(flags); auto cause = bit_sub<16, 15>(flags); - if (trap_id == 0 && cause == 11) cause = 0x8 + cur_priv; // adjust environment call cause + if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause // calculate effective privilege level - auto new_priv = PRIV_M; if (trap_id == 0) { // exception - if (cur_priv != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0) - new_priv = (csr[sedeleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; // store ret addr in xepc register - csr[uepc | (new_priv << 8)] = static_cast(addr); // store actual address instruction of exception - /* - * write mtval if new_priv=M_MODE, spec says: - * When a hardware breakpoint is triggered, or an instruction-fetch, load, - * or store address-misaligned, - * access, or page-fault exception occurs, mtval is written with the - * faulting effective address. - */ - csr[utval | (new_priv << 8)] = fault_data; + csr[mepc] = static_cast(addr); // store actual address instruction of exception + csr[mtval] = fault_data; fault_data = 0; } else { - if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) - new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; - csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt + csr[mepc] = this->reg.NEXT_PC; // store next address if interrupt this->reg.pending_trap = 0; } - size_t adr = ucause | (new_priv << 8); - csr[adr] = (trap_id << 31) + cause; + csr[mcause] = (trap_id << 31) + cause; // update mstatus // xPP field of mstatus is written with the active privilege mode at the time // of the trap; the x PIE field of mstatus @@ -1200,41 +1066,25 @@ template uint64_t riscv_hart_m_p::enter_trap(uint64_t flag // the trap; and the x IE field of mstatus // is cleared // store the actual privilege level in yPP and store interrupt enable flags - switch (new_priv) { - case PRIV_M: - state.mstatus.MPP = cur_priv; - state.mstatus.MPIE = state.mstatus.MIE; - state.mstatus.MIE = false; - break; - case PRIV_S: - state.mstatus.SPP = cur_priv; - state.mstatus.SPIE = state.mstatus.SIE; - state.mstatus.SIE = false; - break; - case PRIV_U: - state.mstatus.UPIE = state.mstatus.UIE; - state.mstatus.UIE = false; - break; - default: - break; - } + state.mstatus.MPP = PRIV_M; + state.mstatus.MPIE = state.mstatus.MIE; + state.mstatus.MIE = false; // get trap vector - auto ivec = csr[utvec | (new_priv << 8)]; + auto ivec = csr[mtvec]; // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // bits in mtvec this->reg.NEXT_PC = ivec & ~0x1UL; if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause; // reset trap state - this->reg.machine_state = new_priv; + this->reg.machine_state = PRIV_M; this->reg.trap_state = 0; std::array buffer; sprintf(buffer.data(), "0x%016lx", addr); if((flags&0xffffffff) != 0xffffffff) CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")" - << " at address " << buffer.data() << " occurred, changing privilege level from " - << lvl[cur_priv] << " to " << lvl[new_priv]; + << " at address " << buffer.data() << " occurred"; update_vm_info(); return this->reg.NEXT_PC; } @@ -1244,47 +1094,24 @@ template uint64_t riscv_hart_m_p::leave_trap(uint64_t flag auto inst_priv = flags & 0x3; auto status = state.mstatus; - auto tsr = state.mstatus.TSR; - if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - return this->reg.PC; - } - // pop the relevant lower-privilege interrupt enable and privilege mode stack // clear respective yIE - switch (inst_priv) { - case PRIV_M: + if (inst_priv == PRIV_M) { this->reg.machine_state = state.mstatus.MPP; state.mstatus.MPP = 0; // clear mpp to U mode state.mstatus.MIE = state.mstatus.MPIE; - break; - case PRIV_S: - this->reg.machine_state = state.mstatus.SPP; - state.mstatus.SPP = 0; // clear spp to U mode - state.mstatus.SIE = state.mstatus.SPIE; - break; - case PRIV_U: - this->reg.machine_state = 0; - state.mstatus.UIE = state.mstatus.UPIE; - break; + } else { + CLOG(ERROR, disass) << "Unsupported mode:" << inst_priv; } + // sets the pc to the value stored in the x epc register. - this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; - CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " - << lvl[this->reg.machine_state]; + this->reg.NEXT_PC = csr[mepc]; + CLOG(INFO, disass) << "Executing xRET"; update_vm_info(); return this->reg.NEXT_PC; } -template void riscv_hart_m_p::wait_until(uint64_t flags) { - auto status = state.mstatus; - auto tw = status.TW; - if (this->reg.machine_state == PRIV_S && tw != 0) { - this->reg.trap_state = (1 << 31) | (2 << 16); - this->fault_data = this->reg.PC; - } -} +template void riscv_hart_m_p::wait_until(uint64_t flags) {} } // namespace arch } // namespace iss