Browse Source

Merge pull request #869 from scottj97/badgpa

Take guest page fault if guest PA out of bounds
pull/870/head
Andrew Waterman 4 years ago
committed by GitHub
parent
commit
2b261c9782
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 101
      riscv/mmu.cc

101
riscv/mmu.cc

@ -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);
}
} }
} }

Loading…
Cancel
Save