Browse Source

Merge pull request #1200 from riscv-software-src/mmio_pte

Support accessing PTEs through mmio_load/mmio_store
pull/1209/head
Andrew Waterman 4 years ago
committed by GitHub
parent
commit
07647a9b53
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      riscv/mmu.cc
  2. 49
      riscv/mmu.h

23
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.

49
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;

Loading…
Cancel
Save