summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2013-08-05 00:28:03 +0000
committerjeff <jeff@FreeBSD.org>2013-08-05 00:28:03 +0000
commitbaea70e2d240e48edbd021981532b9d16f16589b (patch)
tree198c60f2a696d008cea3389a370600c5aecf6df2
parent598e23d2ea39e4526a2c2ba5e99a952645a9e3b0 (diff)
downloadFreeBSD-src-baea70e2d240e48edbd021981532b9d16f16589b.zip
FreeBSD-src-baea70e2d240e48edbd021981532b9d16f16589b.tar.gz
- Introduce a specific function, pmap_remove_kernel_pde, for removing
huge pages in the kernel's address space. This works around several asserts from pmap_demote_pde_locked that did not apply and gave false warnings. Discovered by: pho Reviewed by: alc Sponsored by: EMC / Isilon Storage Division
-rw-r--r--sys/amd64/amd64/pmap.c41
-rw-r--r--sys/i386/i386/pmap.c41
2 files changed, 78 insertions, 4 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index d7e125b..46112b5 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -2795,6 +2795,44 @@ pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
}
/*
+ * pmap_remove_kernel_pde: Remove a kernel superpage mapping.
+ */
+static void
+pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
+{
+ pd_entry_t newpde;
+ vm_paddr_t mptepa;
+ vm_page_t mpte;
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ mpte = pmap_lookup_pt_page(pmap, va);
+ if (mpte == NULL)
+ panic("pmap_remove_kernel_pde: Missing pt page.");
+
+ pmap_remove_pt_page(pmap, mpte);
+ mptepa = VM_PAGE_TO_PHYS(mpte);
+ newpde = mptepa | PG_M | PG_A | PG_RW | PG_V;
+
+ /*
+ * Initialize the page table page.
+ */
+ pagezero((void *)PHYS_TO_DMAP(mptepa));
+
+ /*
+ * Demote the mapping.
+ */
+ if (workaround_erratum383)
+ pmap_update_pde(pmap, va, pde, newpde);
+ else
+ pde_store(pde, newpde);
+
+ /*
+ * Invalidate a stale recursive mapping of the page table page.
+ */
+ pmap_invalidate_page(pmap, (vm_offset_t)vtopte(va));
+}
+
+/*
* pmap_remove_pde: do the things to unmap a superpage in a process
*/
static int
@@ -2837,8 +2875,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
}
}
if (pmap == kernel_pmap) {
- if (!pmap_demote_pde_locked(pmap, pdq, sva, lockp))
- panic("pmap_remove_pde: failed demotion");
+ pmap_remove_kernel_pde(pmap, pdq, sva);
} else {
mpte = pmap_lookup_pt_page(pmap, sva);
if (mpte != NULL) {
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 9556458..77b0235 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -2773,6 +2773,44 @@ pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
}
/*
+ * Removes a 2- or 4MB page mapping from the kernel pmap.
+ */
+static void
+pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
+{
+ pd_entry_t newpde;
+ vm_paddr_t mptepa;
+ vm_page_t mpte;
+
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ mpte = pmap_lookup_pt_page(pmap, va);
+ if (mpte == NULL)
+ panic("pmap_remove_kernel_pde: Missing pt page.");
+
+ pmap_remove_pt_page(pmap, mpte);
+ mptepa = VM_PAGE_TO_PHYS(mpte);
+ newpde = mptepa | PG_M | PG_A | PG_RW | PG_V;
+
+ /*
+ * Initialize the page table page.
+ */
+ pagezero((void *)&KPTmap[i386_btop(trunc_4mpage(va))]);
+
+ /*
+ * Remove the mapping.
+ */
+ if (workaround_erratum383)
+ pmap_update_pde(pmap, va, pde, newpde);
+ else
+ pmap_kenter_pde(va, newpde);
+
+ /*
+ * Invalidate the recursive mapping of the page table page.
+ */
+ pmap_invalidate_page(pmap, (vm_offset_t)vtopte(va));
+}
+
+/*
* pmap_remove_pde: do the things to unmap a superpage in a process
*/
static void
@@ -2814,8 +2852,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
}
}
if (pmap == kernel_pmap) {
- if (!pmap_demote_pde(pmap, pdq, sva))
- panic("pmap_remove_pde: failed demotion");
+ pmap_remove_kernel_pde(pmap, pdq, sva);
} else {
mpte = pmap_lookup_pt_page(pmap, sva);
if (mpte != NULL) {
OpenPOWER on IntegriCloud