DF-5358 / fix.diff
diff --git a/sys/platform/pc64/x86_64/pmap.c b/sys/platform/pc64/x86_64/pmap.c index a301274..bcd8164 100644 --- a/sys/platform/pc64/x86_64/pmap.c +++ b/sys/platform/pc64/x86_64/pmap.c @@ -1864,15 +1864,46 @@ pmap_fault_page_quick(pmap_t pmap, vm_offset_t va, vm_prot_t prot, int *busyp) vm_paddr_t pmap_kextract(vm_offset_t va) { - pd_entry_t pt; /* pt entry in pd */ + pml4_entry_t pdp; /* pml4e value */ + pdp_entry_t pdpe; /* pdp entry value */ + pd_entry_t pde; /* pd entry value */ vm_paddr_t pa; if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) { pa = DMAP_TO_PHYS(va); } else { - pt = *vtopt(va); - if (pt & kernel_pmap->pmap_bits[PG_PS_IDX]) { - pa = (pt & PG_PS_FRAME) | (va & PDRMASK); + /* + * Walk the kernel page tables through the DMAP instead of + * dereferencing the recursive map. Kernel page table pages + * are allocated on demand (pmap_growkernel()), so for a KVA + * whose upper levels have not been allocated yet the + * recursive-map address of the PDE slot is itself unmapped: + * *vtopt(va) took an unrecoverable kernel page fault with + * no onfault (reachable from /dev/kmem through + * kvm_access_check(), vm_machdep.c). + * + * Also require PG_V at each level so an unmapped VA returns + * 0 instead of a bogus (va & PAGE_MASK)-based physical + * address; that is what makes kvm_access_check()'s per-page + * residency test meaningful. + */ + pdp = *pmap_pdp(kernel_pmap, va); + if ((pdp & kernel_pmap->pmap_bits[PG_V_IDX]) == 0) + return 0; + pdpe = *pmap_pdp_to_pd(pdp, va); + if ((pdpe & kernel_pmap->pmap_bits[PG_V_IDX]) == 0) + return 0; + if (pdpe & kernel_pmap->pmap_bits[PG_PS_IDX]) { + /* 1GB page (not used by the kernel pmap today) */ + pa = (pdpe & 0x000FFFFFC0000000UL) | + (va & ((1UL << PDPSHIFT) - 1)); + return pa; + } + pde = *pmap_pd_to_pt(pdpe, va); + if ((pde & kernel_pmap->pmap_bits[PG_V_IDX]) == 0) + return 0; + if (pde & kernel_pmap->pmap_bits[PG_PS_IDX]) { + pa = (pde & PG_PS_FRAME) | (va & PDRMASK); } else { /* * Beware of a concurrent promotion that changes the @@ -1882,7 +1913,9 @@ pmap_kextract(vm_offset_t va) * because the page table page is preserved by the * promotion. */ - pa = *pmap_pt_to_pte(pt, va); + pa = *pmap_pt_to_pte(pde, va); + if ((pa & kernel_pmap->pmap_bits[PG_V_IDX]) == 0) + return 0; pa = (pa & PG_FRAME) | (va & PAGE_MASK); } } |