diff options
-rw-r--r-- | riscv/csrs.cc | 48 | ||||
-rw-r--r-- | riscv/csrs.h | 25 | ||||
-rw-r--r-- | riscv/mmu.cc | 2 | ||||
-rw-r--r-- | riscv/processor.cc | 38 | ||||
-rw-r--r-- | riscv/processor.h | 8 |
5 files changed, 81 insertions, 40 deletions
diff --git a/riscv/csrs.cc b/riscv/csrs.cc index a7a3e13..e376f6d 100644 --- a/riscv/csrs.cc +++ b/riscv/csrs.cc @@ -725,3 +725,51 @@ counteren_csr_t::counteren_csr_t(processor_t* const proc, const reg_t addr): bool counteren_csr_t::unlogged_write(const reg_t val) noexcept { return basic_csr_t::unlogged_write(val & 0xffffffffULL); } + + +// implement class base_atp_csr_t and family +base_atp_csr_t::base_atp_csr_t(processor_t* const proc, const reg_t addr): + basic_csr_t(proc, addr, 0) { +} + + +bool base_atp_csr_t::unlogged_write(const reg_t val) noexcept { + const reg_t newval = proc->supports_impl(IMPL_MMU) ? proc->compute_new_satp(val, read()) : 0; + if (newval != read()) + proc->get_mmu()->flush_tlb(); + return basic_csr_t::unlogged_write(newval); +} + +satp_csr_t::satp_csr_t(processor_t* const proc, const reg_t addr): + base_atp_csr_t(proc, addr) { +} + +void satp_csr_t::verify_permissions(insn_t insn, bool write) const { + base_atp_csr_t::verify_permissions(insn, write); + if (get_field(state->mstatus->read(), MSTATUS_TVM)) + require(state->prv >= PRV_M); +} + +virtualized_satp_csr_t::virtualized_satp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt): + virtualized_csr_t(proc, orig, virt) { +} + +void virtualized_satp_csr_t::verify_permissions(insn_t insn, bool write) const { + virtualized_csr_t::verify_permissions(insn, write); + + // If satp is accessed from VS mode, it's really accessing vsatp, + // and the hstatus.VTVM bit controls. + if (state->v) { + if (get_field(state->hstatus->read(), HSTATUS_VTVM)) + throw trap_virtual_instruction(insn.bits()); + } + else { + orig_csr->verify_permissions(insn, write); + } +} + +void virtualized_satp_csr_t::write(const reg_t val) noexcept { + // If unsupported Mode field: no change to contents + const reg_t newval = proc->satp_valid(val) ? val : read(); + return virtualized_csr_t::write(newval); +} diff --git a/riscv/csrs.h b/riscv/csrs.h index 6cb60ff..e78a612 100644 --- a/riscv/csrs.h +++ b/riscv/csrs.h @@ -143,6 +143,7 @@ class virtualized_csr_t: public csr_t { csr_t_p virt_csr; }; +typedef std::shared_ptr<virtualized_csr_t> virtualized_csr_t_p; // For mepc, sepc, and vsepc class epc_csr_t: public logged_csr_t { @@ -390,4 +391,28 @@ class counteren_csr_t: public basic_csr_t { virtual bool unlogged_write(const reg_t val) noexcept override; }; + +// For satp and vsatp +// These are three classes in order to handle the [V]TVM bits permission checks +class base_atp_csr_t: public basic_csr_t { + public: + base_atp_csr_t(processor_t* const proc, const reg_t addr); + protected: + virtual bool unlogged_write(const reg_t val) noexcept override; +}; + +class satp_csr_t: public base_atp_csr_t { + public: + satp_csr_t(processor_t* const proc, const reg_t addr); + virtual void verify_permissions(insn_t insn, bool write) const override; +}; + +class virtualized_satp_csr_t: public virtualized_csr_t { + public: + virtualized_satp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt); + virtual void verify_permissions(insn_t insn, bool write) const override; + virtual void write(const reg_t val) noexcept override; +}; + + #endif diff --git a/riscv/mmu.cc b/riscv/mmu.cc index b880739..8cedd44 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -340,7 +340,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx) { reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; - reg_t satp = (virt) ? proc->get_state()->vsatp : proc->get_state()->satp; + reg_t satp = proc->get_state()->satp->readvirt(virt); vm_info vm = decode_vm_info(proc->get_const_xlen(), false, mode, satp); if (vm.levels == 0) return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx) & ~page_mask; // zero-extend from xlen diff --git a/riscv/processor.cc b/riscv/processor.cc index 3fc4580..a1f219d 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -411,7 +411,9 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) auto nonvirtual_stvec = std::make_shared<tvec_csr_t>(proc, CSR_STVEC); csrmap[CSR_VSTVEC] = vstvec = std::make_shared<tvec_csr_t>(proc, CSR_VSTVEC); csrmap[CSR_STVEC] = stvec = std::make_shared<virtualized_csr_t>(proc, nonvirtual_stvec, vstvec); - satp = 0; + auto nonvirtual_satp = std::make_shared<satp_csr_t>(proc, CSR_SATP); + csrmap[CSR_VSATP] = vsatp = std::make_shared<base_atp_csr_t>(proc, CSR_VSATP); + csrmap[CSR_SATP] = satp = std::make_shared<virtualized_satp_csr_t>(proc, nonvirtual_satp, vsatp); auto nonvirtual_scause = std::make_shared<cause_csr_t>(proc, CSR_SCAUSE); csrmap[CSR_VSCAUSE] = vscause = std::make_shared<cause_csr_t>(proc, CSR_VSCAUSE); csrmap[CSR_SCAUSE] = scause = std::make_shared<virtualized_csr_t>(proc, nonvirtual_scause, vscause); @@ -427,7 +429,6 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) auto nonvirtual_sstatus = std::make_shared<sstatus_proxy_csr_t>(proc, CSR_SSTATUS, mstatus); csrmap[CSR_VSSTATUS] = vsstatus = std::make_shared<vsstatus_csr_t>(proc, CSR_VSSTATUS); csrmap[CSR_SSTATUS] = sstatus = std::make_shared<sstatus_csr_t>(proc, nonvirtual_sstatus, vsstatus); - vsatp = 0; dpc = 0; dscratch0 = 0; @@ -986,19 +987,6 @@ void processor_t::set_csr(int which, reg_t val) state.minstret = (val << 32) | (state.minstret << 32 >> 32); state.minstret--; // See comment above. break; - case CSR_SATP: - if (!supports_impl(IMPL_MMU)) - val = 0; - - if (satp_valid(val)) { - mmu->flush_tlb(); - - if (state.v) - state.vsatp = compute_new_satp(val, state.vsatp); - else - state.satp = compute_new_satp(val, state.satp); - } - break; case CSR_MTVAL2: state.mtval2 = val; break; case CSR_MTINST: state.mtinst = val; break; case CSR_HEDELEG: { @@ -1051,13 +1039,6 @@ void processor_t::set_csr(int which, reg_t val) state.hgatp = val & mask; break; } - case CSR_VSATP: - if (!supports_impl(IMPL_MMU)) - val = 0; - - mmu->flush_tlb(); - state.vsatp = compute_new_satp(val, state.vsatp); - break; case CSR_TSELECT: if (val < state.num_triggers) { state.tselect = val; @@ -1162,7 +1143,6 @@ void processor_t::set_csr(int which, reg_t val) case CSR_MCYCLE: case CSR_MINSTRETH: case CSR_MCYCLEH: - case CSR_SATP: case CSR_TSELECT: case CSR_TDATA1: case CSR_TDATA2: @@ -1299,17 +1279,6 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) } break; case CSR_MCOUNTINHIBIT: ret(0); - case CSR_SATP: { - if (state.v) { - if (get_field(state.hstatus->read(), HSTATUS_VTVM)) - goto throw_virtual; - ret(state.vsatp); - } else { - if (get_field(state.mstatus->read(), MSTATUS_TVM)) - require_privilege(PRV_M); - ret(state.satp); - } - } case CSR_MSTATUSH: if (xlen == 32) ret((state.mstatus->read() >> 32) & (MSTATUSH_SBE | MSTATUSH_MBE)); @@ -1337,7 +1306,6 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek) ret(state.hgatp); } case CSR_HGEIP: ret(0); - case CSR_VSATP: ret(state.vsatp); case CSR_TSELECT: ret(state.tselect); case CSR_TDATA1: if (state.tselect < state.num_triggers) { diff --git a/riscv/processor.h b/riscv/processor.h index 4c87bb4..33c6869 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -184,7 +184,7 @@ struct state_t csr_t_p sepc; csr_t_p stval; csr_t_p stvec; - reg_t satp; + virtualized_csr_t_p satp; csr_t_p scause; reg_t mtval2; @@ -202,7 +202,7 @@ struct state_t csr_t_p vsepc; csr_t_p vscause; csr_t_p vstval; - reg_t vsatp; + csr_t_p vsatp; reg_t dpc; reg_t dscratch0, dscratch1; @@ -502,12 +502,12 @@ private: void build_opcode_map(); void register_base_instructions(); insn_func_t decode_insn(insn_t insn); - bool satp_valid(reg_t val) const; - reg_t compute_new_satp(reg_t val, reg_t old) const; // Track repeated executions for processor_t::disasm() uint64_t last_pc, last_bits, executions; public: + bool satp_valid(reg_t val) const; + reg_t compute_new_satp(reg_t val, reg_t old) const; reg_t n_pmp; reg_t lg_pmp_granularity; reg_t pmp_tor_mask() { return -(reg_t(1) << (lg_pmp_granularity - PMP_SHIFT)); } |