diff options
author | Andrew Waterman <andrew@sifive.com> | 2021-07-21 18:29:20 -0700 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2021-07-21 18:29:20 -0700 |
commit | 4deb3750337d93663333ca5f643004120b7d9c7d (patch) | |
tree | f976a23e0ac9bee39fb7603444551229ecf0519e | |
parent | cea9eb4a138590b9204c593e9ee61a6e1a6c6753 (diff) | |
download | riscv-isa-sim-4deb3750337d93663333ca5f643004120b7d9c7d.zip riscv-isa-sim-4deb3750337d93663333ca5f643004120b7d9c7d.tar.gz riscv-isa-sim-4deb3750337d93663333ca5f643004120b7d9c7d.tar.bz2 |
Fix HLVX permissions check
It should require X permissions, rather than (R || X).
-rw-r--r-- | riscv/mmu.cc | 28 | ||||
-rw-r--r-- | riscv/mmu.h | 10 |
2 files changed, 18 insertions, 20 deletions
diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 3c62295..2d8e283 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -55,6 +55,7 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f 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; if (type != FETCH) { if (!proc->state.debug_mode && get_field(proc->state.mstatus, MSTATUS_MPRV)) { @@ -65,13 +66,10 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f if (xlate_flags & RISCV_XLATE_VIRT) { virt = true; mode = get_field(proc->state.hstatus, HSTATUS_SPVP); - if (type == LOAD && (xlate_flags & RISCV_XLATE_VIRT_MXR)) { - mxr = true; - } } } - reg_t paddr = walk(addr, type, mode, virt, mxr) | (addr & (PGSIZE-1)); + reg_t paddr = walk(addr, type, mode, virt, mxr, hlvx) | (addr & (PGSIZE-1)); if (!pmp_ok(paddr, len, type, mode)) throw_access_exception(virt, addr, type); return paddr; @@ -305,7 +303,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) +reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool mxr, bool hlvx) { if (!virt) return gpa; @@ -338,9 +336,9 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty break; } else if (!(pte & PTE_U)) { break; - } else if (type == FETCH ? !(pte & PTE_X) : - type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : - !((pte & PTE_R) && (pte & PTE_W))) { + } else if (type == FETCH || hlvx ? !(pte & PTE_X) : + type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : + !((pte & PTE_R) && (pte & PTE_W))) { break; } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { break; @@ -380,13 +378,13 @@ 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) +reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr, 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) & ~page_mask; // zero-extend from xlen + return s2xlate(addr, addr & ((reg_t(2) << (proc->xlen-1))-1), type, type, virt, mxr, hlvx) & ~page_mask; // zero-extend from xlen bool s_mode = mode == PRV_S; bool sum = get_field(proc->state.mstatus, MSTATUS_SUM); @@ -404,7 +402,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); + auto pte_paddr = s2xlate(addr, base + idx * vm.ptesize, LOAD, type, virt, false, 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); @@ -420,9 +418,9 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode, bool virt, bool mxr) break; } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { break; - } else if (type == FETCH ? !(pte & PTE_X) : - type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : - !((pte & PTE_R) && (pte & PTE_W))) { + } else if (type == FETCH || hlvx ? !(pte & PTE_X) : + type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : + !((pte & PTE_R) && (pte & PTE_W))) { break; } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { break; @@ -451,7 +449,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) & ~page_mask; + return s2xlate(addr, phys, type, type, virt, mxr, hlvx) & ~page_mask; } } diff --git a/riscv/mmu.h b/riscv/mmu.h index 74e162b..3e44002 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -62,7 +62,7 @@ public: ~mmu_t(); #define RISCV_XLATE_VIRT (1U << 0) -#define RISCV_XLATE_VIRT_MXR (1U << 1) +#define RISCV_XLATE_VIRT_HLVX (1U << 1) inline reg_t misaligned_load(reg_t addr, size_t size, uint32_t xlate_flags) { @@ -135,8 +135,8 @@ public: load_func(uint16, guest_load, RISCV_XLATE_VIRT) load_func(uint32, guest_load, RISCV_XLATE_VIRT) load_func(uint64, guest_load, RISCV_XLATE_VIRT) - load_func(uint16, guest_load_x, RISCV_XLATE_VIRT|RISCV_XLATE_VIRT_MXR) - load_func(uint32, guest_load_x, RISCV_XLATE_VIRT|RISCV_XLATE_VIRT_MXR) + load_func(uint16, guest_load_x, RISCV_XLATE_VIRT|RISCV_XLATE_VIRT_HLVX) + load_func(uint32, guest_load_x, RISCV_XLATE_VIRT|RISCV_XLATE_VIRT_HLVX) // load value from memory at aligned address; sign extend to register width load_func(int8, load, 0) @@ -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); + reg_t s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool mxr, 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); + reg_t walk(reg_t addr, access_type type, reg_t prv, bool virt, bool mxr, bool hlvx); // handle uncommon cases: TLB misses, page faults, MMIO tlb_entry_t fetch_slow_path(reg_t addr); |