diff options
author | Andrew Waterman <andrew@sifive.com> | 2021-07-21 18:51:41 -0700 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2021-07-21 18:51:41 -0700 |
commit | 9cfc3e7fef7b29f6b53879d7c91c35459d9b493d (patch) | |
tree | 4b0ea1a2eef02a95d583715bdfe96158b9b48952 | |
parent | 4deb3750337d93663333ca5f643004120b7d9c7d (diff) | |
download | spike-9cfc3e7fef7b29f6b53879d7c91c35459d9b493d.zip spike-9cfc3e7fef7b29f6b53879d7c91c35459d9b493d.tar.gz spike-9cfc3e7fef7b29f6b53879d7c91c35459d9b493d.tar.bz2 |
Fix hypervisor MXR and SUM
When V=1, vsstatus.MXR applies to the first stage of translation,
and mstatus.MXR applies to both.
mstatus.SUM doesn't apply when V=1, but vsstatus.SUM does.
-rw-r--r-- | riscv/mmu.cc | 18 | ||||
-rw-r--r-- | riscv/mmu.h | 4 |
2 files changed, 12 insertions, 10 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 2d8e283..19f1902 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -53,7 +53,6 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f if (!proc) return addr; - bool mxr = get_field(proc->state.mstatus, MSTATUS_MXR); bool virt = (proc) ? proc->state.v : false; bool hlvx = xlate_flags & RISCV_XLATE_VIRT_HLVX; reg_t mode = proc->state.prv; @@ -69,7 +68,7 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f } } - reg_t paddr = walk(addr, type, mode, virt, mxr, hlvx) | (addr & (PGSIZE-1)); + reg_t paddr = walk(addr, type, mode, virt, hlvx) | (addr & (PGSIZE-1)); if (!pmp_ok(paddr, len, type, mode)) throw_access_exception(virt, addr, type); return paddr; @@ -303,7 +302,7 @@ reg_t mmu_t::pmp_homogeneous(reg_t addr, reg_t len) return true; } -reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool mxr, bool hlvx) +reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool hlvx) { if (!virt) return gpa; @@ -312,6 +311,8 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty if (vm.levels == 0) return gpa; + bool mxr = proc->state.mstatus & MSTATUS_MXR; + reg_t base = vm.ptbase; for (int i = vm.levels - 1; i >= 0; i--) { int ptshift = i * vm.idxbits; @@ -378,16 +379,17 @@ 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 mxr, bool hlvx) +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; vm_info vm = decode_vm_info(proc->max_xlen, false, mode, satp); if (vm.levels == 0) - return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, mxr, hlvx) & ~page_mask; // zero-extend from xlen + return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, hlvx) & ~page_mask; // zero-extend from xlen bool s_mode = mode == PRV_S; - bool sum = get_field(proc->state.mstatus, MSTATUS_SUM); + bool sum = (virt ? proc->state.vsstatus : proc->state.mstatus) & MSTATUS_SUM; + bool mxr = (proc->state.mstatus | (virt ? proc->state.vsstatus : 0)) & MSTATUS_MXR; // verify bits xlen-1:va_bits-1 are all equal int va_bits = PGSHIFT + vm.levels * vm.idxbits; @@ -402,7 +404,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr, reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1); // check that physical address of PTE is legal - auto pte_paddr = s2xlate(addr, base + idx * vm.ptesize, LOAD, type, virt, false, false); + 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); @@ -449,7 +451,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr, | (vpn & ((reg_t(1) << napot_bits) - 1)) | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; reg_t phys = page_base | (addr & page_mask); - return s2xlate(addr, phys, type, type, virt, mxr, hlvx) & ~page_mask; + return s2xlate(addr, phys, type, type, virt, hlvx) & ~page_mask; } } diff --git a/riscv/mmu.h b/riscv/mmu.h index 3e44002..a43b17e 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -414,10 +414,10 @@ private: const char* fill_from_mmio(reg_t vaddr, reg_t paddr); // perform a stage2 translation for a given guest address - reg_t s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool mxr, bool hlvx); + reg_t s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool hlvx); // perform a page table walk for a given VA; set referenced/dirty bits - reg_t walk(reg_t addr, access_type type, reg_t prv, bool virt, bool mxr, bool hlvx); + reg_t walk(reg_t addr, access_type type, reg_t prv, bool virt, bool hlvx); // handle uncommon cases: TLB misses, page faults, MMIO tlb_entry_t fetch_slow_path(reg_t addr); |