aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2023-01-03 16:42:42 -0800
committerGitHub <noreply@github.com>2023-01-03 16:42:42 -0800
commit07647a9b53f482bb299ab783090af53995b4817e (patch)
tree26ccaf640ac85260490942c7b36c3968a36429a9
parent85f7869bf58a4d9b3d4a09f9f312c2deb7b3c81a (diff)
parent43474ddc63ff52ef6a92e32889312609a770941c (diff)
downloadspike-07647a9b53f482bb299ab783090af53995b4817e.zip
spike-07647a9b53f482bb299ab783090af53995b4817e.tar.gz
spike-07647a9b53f482bb299ab783090af53995b4817e.tar.bz2
Merge pull request #1200 from riscv-software-src/mmio_pte
Support accessing PTEs through mmio_load/mmio_store
-rw-r--r--riscv/mmu.cc23
-rw-r--r--riscv/mmu.h49
2 files changed, 54 insertions, 18 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc
index ce3e5ca..b33e383 100644
--- a/riscv/mmu.cc
+++ b/riscv/mmu.cc
@@ -42,7 +42,7 @@ void mmu_t::flush_tlb()
flush_icache();
}
-static void throw_access_exception(bool virt, reg_t addr, access_type type)
+void throw_access_exception(bool virt, reg_t addr, access_type type)
{
switch (type) {
case FETCH: throw trap_instruction_access_fault(virt, addr, 0, 0);
@@ -387,12 +387,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty
// check that physical address of PTE is legal
auto pte_paddr = base + idx * vm.ptesize;
- auto ppte = sim->addr_to_mem(pte_paddr);
- if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S)) {
- throw_access_exception(virt, gva, trap_type);
- }
-
- reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte);
+ reg_t pte = pte_load(pte_paddr, gva, virt, trap_type, vm.ptesize);
reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT;
bool pbmte = proc->get_state()->menvcfg->read() & MENVCFG_PBMTE;
@@ -423,9 +418,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty
#ifdef RISCV_ENABLE_DIRTY
// set accessed and possibly dirty bits.
if ((pte & ad) != ad) {
- if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S))
- throw_access_exception(virt, gva, trap_type);
- *(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad);
+ pte_store(pte_paddr, pte | ad, gva, virt, type, vm.ptesize);
}
#else
// take exception if access or possibly dirty bit is not set.
@@ -481,11 +474,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx
// check that physical address of PTE is legal
auto pte_paddr = s2xlate(addr, base + idx * vm.ptesize, LOAD, type, virt, false);
- auto ppte = sim->addr_to_mem(pte_paddr);
- if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S))
- throw_access_exception(virt, addr, type);
-
- reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte);
+ reg_t pte = pte_load(pte_paddr, addr, virt, type, vm.ptesize);
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);
@@ -516,9 +505,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool hlvx
#ifdef RISCV_ENABLE_DIRTY
// set accessed and possibly dirty bits.
if ((pte & ad) != ad) {
- if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S))
- throw_access_exception(virt, addr, type);
- *(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad);
+ pte_store(pte_paddr, pte | ad, addr, virt, type, vm.ptesize);
}
#else
// take exception if access or possibly dirty bit is not set.
diff --git a/riscv/mmu.h b/riscv/mmu.h
index 723b08e..4cc141f 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -38,6 +38,8 @@ struct tlb_entry_t {
reg_t target_offset;
};
+void throw_access_exception(bool virt, reg_t addr, access_type type);
+
// this class implements a processor's port into the virtual memory system.
// an MMU and instruction cache are maintained for simulator performance.
class mmu_t
@@ -354,6 +356,53 @@ private:
void check_triggers(triggers::operation_t operation, reg_t address, std::optional<reg_t> data = std::nullopt);
reg_t translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_flags);
+ reg_t pte_load(reg_t pte_paddr, reg_t addr, bool virt, access_type trap_type, size_t ptesize) {
+ if (ptesize == 4)
+ return pte_load<uint32_t>(pte_paddr, addr, virt, trap_type);
+ else
+ return pte_load<uint64_t>(pte_paddr, addr, virt, trap_type);
+ }
+
+ void pte_store(reg_t pte_paddr, reg_t new_pte, reg_t addr, bool virt, access_type trap_type, size_t ptesize) {
+ if (ptesize == 4)
+ return pte_store<uint32_t>(pte_paddr, new_pte, addr, virt, trap_type);
+ else
+ return pte_store<uint64_t>(pte_paddr, new_pte, addr, virt, trap_type);
+ }
+
+ template<typename T> inline reg_t pte_load(reg_t pte_paddr, reg_t addr, bool virt, access_type trap_type)
+ {
+ const size_t ptesize = sizeof(T);
+
+ if (!pmp_ok(pte_paddr, ptesize, LOAD, PRV_S))
+ throw_access_exception(virt, addr, trap_type);
+
+ void* host_pte_paddr = sim->addr_to_mem(pte_paddr);
+ target_endian<T> target_pte;
+ if (host_pte_paddr) {
+ memcpy(&target_pte, host_pte_paddr, ptesize);
+ } else if (!mmio_load(pte_paddr, ptesize, (uint8_t*)&target_pte)) {
+ throw_access_exception(virt, addr, trap_type);
+ }
+ return from_target(target_pte);
+ }
+
+ template<typename T> inline void pte_store(reg_t pte_paddr, reg_t new_pte, reg_t addr, bool virt, access_type trap_type)
+ {
+ const size_t ptesize = sizeof(T);
+
+ if (!pmp_ok(pte_paddr, ptesize, STORE, PRV_S))
+ throw_access_exception(virt, addr, trap_type);
+
+ void* host_pte_paddr = sim->addr_to_mem(pte_paddr);
+ target_endian<T> target_pte = to_target((T)new_pte);
+ if (host_pte_paddr) {
+ memcpy(host_pte_paddr, &target_pte, ptesize);
+ } else if (!mmio_store(pte_paddr, ptesize, (uint8_t*)&target_pte)) {
+ throw_access_exception(virt, addr, trap_type);
+ }
+ }
+
// ITLB lookup
inline tlb_entry_t translate_insn_addr(reg_t addr) {
reg_t vpn = addr >> PGSHIFT;