|
|
|
@ -53,8 +53,8 @@ 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; |
|
|
|
if (type != FETCH) { |
|
|
|
if (!proc->state.debug_mode && get_field(proc->state.mstatus, MSTATUS_MPRV)) { |
|
|
|
@ -62,16 +62,13 @@ reg_t mmu_t::translate(reg_t addr, reg_t len, access_type type, uint32_t xlate_f |
|
|
|
if (get_field(proc->state.mstatus, MSTATUS_MPV) && mode != PRV_M) |
|
|
|
virt = true; |
|
|
|
} |
|
|
|
if (!proc->state.debug_mode && (xlate_flags & RISCV_XLATE_VIRT)) { |
|
|
|
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, hlvx) | (addr & (PGSIZE-1)); |
|
|
|
if (!pmp_ok(paddr, len, type, mode)) |
|
|
|
throw_access_exception(virt, addr, type); |
|
|
|
return paddr; |
|
|
|
@ -150,7 +147,7 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes, uint32_t xlate |
|
|
|
memcpy(bytes, host_addr, len); |
|
|
|
if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) |
|
|
|
tracer.trace(paddr, len, LOAD); |
|
|
|
else |
|
|
|
else if (xlate_flags == 0) |
|
|
|
refill_tlb(addr, paddr, host_addr, LOAD); |
|
|
|
} else if (!mmio_load(paddr, len, bytes)) { |
|
|
|
throw trap_load_access_fault((proc) ? proc->state.v : false, addr, 0, 0); |
|
|
|
@ -179,7 +176,7 @@ void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes, uint32_ |
|
|
|
memcpy(host_addr, bytes, len); |
|
|
|
if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) |
|
|
|
tracer.trace(paddr, len, STORE); |
|
|
|
else |
|
|
|
else if (xlate_flags == 0) |
|
|
|
refill_tlb(addr, paddr, host_addr, STORE); |
|
|
|
} else if (!mmio_store(paddr, len, bytes)) { |
|
|
|
throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0); |
|
|
|
@ -305,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) |
|
|
|
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; |
|
|
|
@ -314,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; |
|
|
|
@ -338,9 +337,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,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) |
|
|
|
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) & ~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; |
|
|
|
@ -420,9 +420,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 +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) & ~page_mask; |
|
|
|
return s2xlate(addr, phys, type, type, virt, hlvx) & ~page_mask; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|