From 22e97db4c45231a8abd5d05273c77144e8ee026c Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 29 Nov 2021 12:33:11 -0800 Subject: [PATCH 1/2] Raise guest page fault if GPA is out of range Based on this statement from priv spec 5.5.1 (regarding Sv39x4): "Address bits 63:41 must all be zeros, or else a guest-page-fault exception occurs." --- riscv/mmu.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 906694cd..73a36f81 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -267,9 +267,13 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty if (vm.levels == 0) 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; reg_t base = vm.ptbase; + if ((gpa & ~maxgpa) == 0) { for (int i = vm.levels - 1; i >= 0; i--) { int ptshift = i * vm.idxbits; int idxbits = (i == (vm.levels - 1)) ? vm.idxbits + vm.widenbits : vm.idxbits; @@ -328,6 +332,7 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty return page_base | (gpa & page_mask); } } + } switch (trap_type) { case FETCH: throw trap_instruction_guest_page_fault(gva, gpa >> 2, 0); From f5dd47acbf7d49ceff8974883a94c7b72c837c08 Mon Sep 17 00:00:00 2001 From: Scott Johnson Date: Mon, 29 Nov 2021 12:48:04 -0800 Subject: [PATCH 2/2] Reindent s2xlate() --- riscv/mmu.cc | 98 ++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 73a36f81..eed656a0 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -274,65 +274,65 @@ reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_ty reg_t base = vm.ptbase; if ((gpa & ~maxgpa) == 0) { - for (int i = vm.levels - 1; i >= 0; i--) { - int ptshift = i * vm.idxbits; - 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; - auto ppte = sim->addr_to_mem(pte_paddr); - if (!ppte || !pmp_ok(pte_paddr, vm.ptesize, LOAD, PRV_S)) { - throw_access_exception(virt, gva, trap_type); - } + for (int i = vm.levels - 1; i >= 0; i--) { + int ptshift = i * vm.idxbits; + 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; + auto ppte = sim->addr_to_mem(pte_paddr); + 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*)ppte) : from_target(*(target_endian*)ppte); - reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; + reg_t pte = vm.ptesize == 4 ? from_target(*(target_endian*)ppte) : from_target(*(target_endian*)ppte); + reg_t ppn = (pte & ~reg_t(PTE_ATTR)) >> PTE_PPN_SHIFT; - 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)) + if (pte & PTE_RSVD) { break; - base = ppn << PGSHIFT; - } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { - break; - } else if (!(pte & PTE_U)) { - break; - } 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; - } else { - reg_t ad = PTE_A | ((type == STORE) * PTE_D); + } else if (PTE_TABLE(pte)) { // next level of page table + if (pte & (PTE_D | PTE_A | PTE_U | PTE_N | PTE_PBMT)) + break; + base = ppn << PGSHIFT; + } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { + break; + } else if (!(pte & PTE_U)) { + break; + } 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; + } else { + reg_t ad = PTE_A | ((type == STORE) * PTE_D); #ifdef RISCV_ENABLE_DIRTY - // set accessed and possibly dirty bits. - if ((pte & ad) != ad) { - if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) - throw_access_exception(virt, gva, trap_type); - *(target_endian*)ppte |= to_target((uint32_t)ad); - } + // set accessed and possibly dirty bits. + if ((pte & ad) != ad) { + if (!pmp_ok(pte_paddr, vm.ptesize, STORE, PRV_S)) + throw_access_exception(virt, gva, trap_type); + *(target_endian*)ppte |= to_target((uint32_t)ad); + } #else - // take exception if access or possibly dirty bit is not set. - if ((pte & ad) != ad) - break; + // take exception if access or possibly dirty bit is not set. + if ((pte & ad) != ad) + break; #endif - reg_t vpn = gpa >> PGSHIFT; - reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; + reg_t vpn = gpa >> PGSHIFT; + reg_t page_mask = (reg_t(1) << PGSHIFT) - 1; - int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); - if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) - break; + int napot_bits = ((pte & PTE_N) ? (ctz(ppn) + 1) : 0); + if (((pte & PTE_N) && (ppn == 0 || i != 0)) || (napot_bits != 0 && napot_bits != 4)) + break; - reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) - | (vpn & ((reg_t(1) << napot_bits) - 1)) - | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; - return page_base | (gpa & page_mask); + reg_t page_base = ((ppn & ~((reg_t(1) << napot_bits) - 1)) + | (vpn & ((reg_t(1) << napot_bits) - 1)) + | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; + return page_base | (gpa & page_mask); + } } } - } switch (trap_type) { case FETCH: throw trap_instruction_guest_page_fault(gva, gpa >> 2, 0);