aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Johnson <scott.johnson@arilinc.com>2021-03-02 00:02:57 -0800
committerAndrew Waterman <aswaterman@gmail.com>2021-09-08 07:59:02 -0700
commit14219453156c573caa9dfc0936e1bdfd71138ea3 (patch)
treea67f9631ae7d71330fd6adf523438e0a5829c83c
parent4f008be2f747265d092e6a5fff2b046484d18625 (diff)
downloadspike-14219453156c573caa9dfc0936e1bdfd71138ea3.zip
spike-14219453156c573caa9dfc0936e1bdfd71138ea3.tar.gz
spike-14219453156c573caa9dfc0936e1bdfd71138ea3.tar.bz2
Use virtualized_csr_t for satp and vsatp
This was much more complicated than the others because of the mstatus.TVM and hstatus.VTVM bits, and because of the special WARL-ness of satp that doesn't apply to vsatp. It appears (based on reading the code) that the commitlog for these two was problematic. CSRW to satp when V=1 was reporting a write to satp instead of vsatp which was actually written. Also a CSRW to vsatp looks like it was not being logged at all. Both problems should be fixed now.
-rw-r--r--riscv/csrs.cc48
-rw-r--r--riscv/csrs.h25
-rw-r--r--riscv/mmu.cc2
-rw-r--r--riscv/processor.cc38
-rw-r--r--riscv/processor.h8
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)); }