summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2008-07-12 21:24:42 +0000
committeralc <alc@FreeBSD.org>2008-07-12 21:24:42 +0000
commita761fe4f10a3e7eb9b8dfd16197e8375c6fb89b9 (patch)
tree08925218a3d1653d5a32b9c1be7a34055a35784c /sys/amd64
parentf280e5ed8fedcc2d5929eec2250ed602d207c807 (diff)
downloadFreeBSD-src-a761fe4f10a3e7eb9b8dfd16197e8375c6fb89b9.zip
FreeBSD-src-a761fe4f10a3e7eb9b8dfd16197e8375c6fb89b9.tar.gz
Refine the changes made in SVN rev 180430. Specifically, instantiate a new
page table page only if the 2MB page mapping has been used. Also, refactor some assertions.
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/pmap.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index c137cbc..92227b1 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -2213,7 +2213,8 @@ pmap_fill_ptp(pt_entry_t *firstpte, pt_entry_t newpte)
}
/*
- * Tries to demote a 2MB page mapping.
+ * Tries to demote a 2MB page mapping. If demotion fails, the 2MB page
+ * mapping is invalidated.
*/
static boolean_t
pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
@@ -2224,32 +2225,41 @@ pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
vm_page_t free, mpte;
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ oldpde = *pde;
+ KASSERT((oldpde & (PG_PS | PG_V)) == (PG_PS | PG_V),
+ ("pmap_demote_pde: oldpde is missing PG_PS and/or PG_V"));
mpte = pmap_lookup_pt_page(pmap, va);
if (mpte != NULL)
pmap_remove_pt_page(pmap, mpte);
- else if ((mpte = vm_page_alloc(NULL, pmap_pde_pindex(va),
- VM_ALLOC_NOOBJ | VM_ALLOC_NORMAL | VM_ALLOC_WIRED)) == NULL) {
- KASSERT((*pde & PG_W) == 0,
+ else {
+ KASSERT((oldpde & PG_W) == 0,
("pmap_demote_pde: page table page for a wired mapping"
" is missing"));
- free = NULL;
- pmap_remove_pde(pmap, pde, trunc_2mpage(va), &free);
- pmap_invalidate_page(pmap, trunc_2mpage(va));
- pmap_free_zero_pages(free);
- CTR2(KTR_PMAP, "pmap_demote_pde: failure for va %#lx"
- " in pmap %p", va, pmap);
- return (FALSE);
+
+ /*
+ * Invalidate the 2MB page mapping and return "failure" if the
+ * mapping was never accessed or the allocation of the new
+ * page table page fails.
+ */
+ if ((oldpde & PG_A) == 0 || (mpte = vm_page_alloc(NULL,
+ pmap_pde_pindex(va), VM_ALLOC_NOOBJ | VM_ALLOC_NORMAL |
+ VM_ALLOC_WIRED)) == NULL) {
+ free = NULL;
+ pmap_remove_pde(pmap, pde, trunc_2mpage(va), &free);
+ pmap_invalidate_page(pmap, trunc_2mpage(va));
+ pmap_free_zero_pages(free);
+ CTR2(KTR_PMAP, "pmap_demote_pde: failure for va %#lx"
+ " in pmap %p", va, pmap);
+ return (FALSE);
+ }
}
mptepa = VM_PAGE_TO_PHYS(mpte);
firstpte = (pt_entry_t *)PHYS_TO_DMAP(mptepa);
- oldpde = *pde;
newpde = mptepa | PG_M | PG_A | (oldpde & PG_U) | PG_RW | PG_V;
- KASSERT((oldpde & (PG_A | PG_V)) == (PG_A | PG_V),
- ("pmap_demote_pde: oldpde is missing PG_A and/or PG_V"));
+ KASSERT((oldpde & PG_A) != 0,
+ ("pmap_demote_pde: oldpde is missing PG_A"));
KASSERT((oldpde & (PG_M | PG_RW)) != PG_RW,
("pmap_demote_pde: oldpde is missing PG_M"));
- KASSERT((oldpde & PG_PS) != 0,
- ("pmap_demote_pde: oldpde is missing PG_PS"));
newpte = oldpde & ~PG_PS;
if ((newpte & PG_PDE_PAT) != 0)
newpte ^= PG_PDE_PAT | PG_PTE_PAT;
OpenPOWER on IntegriCloud