|
|
@ -267,65 +267,70 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty |
|
|
if (vm.levels == 0) |
|
|
if (vm.levels == 0) |
|
|
return gpa; |
|
|
return gpa; |
|
|
|
|
|
|
|
|
|
|
|
int maxgpabits = vm.levels * vm.idxbits + vm.widenbits + PGSHIFT; |
|
|
|
|
|
reg_t maxgpa = (1ULL << maxgpabits) - 1; |
|
|
|
|
|
|
|
|
bool mxr = proc->state.sstatus->readvirt(false) & MSTATUS_MXR; |
|
|
bool mxr = proc->state.sstatus->readvirt(false) & MSTATUS_MXR; |
|
|
|
|
|
|
|
|
reg_t base = vm.ptbase; |
|
|
reg_t base = vm.ptbase; |
|
|
for (int i = vm.levels - 1; i >= 0; i--) { |
|
|
if ((gpa & ~maxgpa) == 0) { |
|
|
int ptshift = i * vm.idxbits; |
|
|
for (int i = vm.levels - 1; i >= 0; i--) { |
|
|
int idxbits = (i == (vm.levels - 1)) ? vm.idxbits + vm.widenbits : vm.idxbits; |
|
|
int ptshift = i * vm.idxbits; |
|
|
reg_t idx = (gpa >> (PGSHIFT + ptshift)) & ((reg_t(1) << idxbits) - 1); |
|
|
int idxbits = (i == (vm.levels - 1)) ? vm.idxbits + vm.widenbits : vm.idxbits; |
|
|
|
|
|
reg_t idx = (gpa >> (PGSHIFT + ptshift)) & ((reg_t(1) << idxbits) - 1); |
|
|
// check that physical address of PTE is legal
|
|
|
|
|
|
auto pte_paddr = base + idx * vm.ptesize; |
|
|
// check that physical address of PTE is legal
|
|
|
auto ppte = sim->addr_to_mem(pte_paddr); |
|
|
auto pte_paddr = base + idx * vm.ptesize; |
|
|
if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S)) { |
|
|
auto ppte = sim->addr_to_mem(pte_paddr); |
|
|
throw_access_exception(virt, gva, trap_type); |
|
|
if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S)) { |
|
|
} |
|
|
throw_access_exception(virt, gva, trap_type); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte); |
|
|
reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian<uint32_t>*)ppte) : from_target(*(target_endian<uint64_t>*)ppte); |
|
|
reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; |
|
|
reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; |
|
|
|
|
|
|
|
|
if (pte & PTE_RSVD) { |
|
|
if (pte & PTE_RSVD) { |
|
|
break; |
|
|
|
|
|
} else if (PTE_TABLE(pte)) { // next level of page table
|
|
|
|
|
|
if (pte & (PTE_D | PTE_A | PTE_U | PTE_N | PTE_PBMT)) |
|
|
|
|
|
break; |
|
|
break; |
|
|
base = ppn << PGSHIFT; |
|
|
} else if (PTE_TABLE(pte)) { // next level of page table
|
|
|
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { |
|
|
if (pte & (PTE_D | PTE_A | PTE_U | PTE_N | PTE_PBMT)) |
|
|
break; |
|
|
break; |
|
|
} else if (!(pte & PTE_U)) { |
|
|
base = ppn << PGSHIFT; |
|
|
break; |
|
|
} else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { |
|
|
} else if (type == FETCH || hlvx ? !(pte & PTE_X) : |
|
|
break; |
|
|
type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : |
|
|
} else if (!(pte & PTE_U)) { |
|
|
!((pte & PTE_R) && (pte & PTE_W))) { |
|
|
break; |
|
|
break; |
|
|
} else if (type == FETCH || hlvx ? !(pte & PTE_X) : |
|
|
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { |
|
|
type == LOAD ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : |
|
|
break; |
|
|
!((pte & PTE_R) && (pte & PTE_W))) { |
|
|
} else { |
|
|
break; |
|
|
reg_t ad = PTE_A | ((type == STORE) * PTE_D); |
|
|
} else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { |
|
|
|
|
|
break; |
|
|
|
|
|
} else { |
|
|
|
|
|
reg_t ad = PTE_A | ((type == STORE) * PTE_D); |
|
|
#ifdef RISCV_ENABLE_DIRTY |
|
|
#ifdef RISCV_ENABLE_DIRTY |
|
|
// set accessed and possibly dirty bits.
|
|
|
// set accessed and possibly dirty bits.
|
|
|
if ((pte & ad) != ad) { |
|
|
if ((pte & ad) != ad) { |
|
|
if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) |
|
|
if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) |
|
|
throw_access_exception(virt, gva, trap_type); |
|
|
throw_access_exception(virt, gva, trap_type); |
|
|
*(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad); |
|
|
*(target_endian<uint32_t>*)ppte |= to_target((uint32_t)ad); |
|
|
} |
|
|
} |
|
|
#else |
|
|
#else |
|
|
// take exception if access or possibly dirty bit is not set.
|
|
|
// take exception if access or possibly dirty bit is not set.
|
|
|
if ((pte & ad) != ad) |
|
|
if ((pte & ad) != ad) |
|
|
break; |
|
|
break; |
|
|
#endif |
|
|
#endif |
|
|
reg_t vpn = gpa >> PGSHIFT; |
|
|
reg_t vpn = gpa >> PGSHIFT; |
|
|
reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; |
|
|
reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; |
|
|
|
|
|
|
|
|
int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); |
|
|
int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); |
|
|
if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) |
|
|
if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) |
|
|
reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) |
|
|
| (vpn & ((reg_t(1) << napot_bits) - 1)) |
|
|
| (vpn & ((reg_t(1) << napot_bits) - 1)) |
|
|
| (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; |
|
|
| (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; |
|
|
return page_base | (gpa & page_mask); |
|
|
return page_base | (gpa & page_mask); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|