aboutsummaryrefslogtreecommitdiff
path: root/riscv/mmu.cc
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2021-07-21 18:29:20 -0700
committerAndrew Waterman <andrew@sifive.com>2021-07-21 18:29:20 -0700
commit4deb3750337d93663333ca5f643004120b7d9c7d (patch)
treef976a23e0ac9bee39fb7603444551229ecf0519e /riscv/mmu.cc
parentcea9eb4a138590b9204c593e9ee61a6e1a6c6753 (diff)
downloadriscv-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).
Diffstat (limited to 'riscv/mmu.cc')
-rw-r--r--riscv/mmu.cc28
1 files changed, 13 insertions, 15 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;
}
}