aboutsummaryrefslogtreecommitdiff
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
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).
-rw-r--r--riscv/mmu.cc28
-rw-r--r--riscv/mmu.h10
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);