summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2013-07-23 22:26:04 +0200
committerRichard Braun <rbraun@sceen.net>2013-07-23 22:26:04 +0200
commit70c2461661ac7f4bd8ad877af8bcaec1abd0c645 (patch)
tree4f7cb7a15992484e342dde9b3cb898f2b1d57c77 /arch
parent64a32afa728931bec0dc5189bab945b94369b474 (diff)
x86/pmap: count PTEs per PTP at initialization
This is required in order to properly release page table pages when removing mappings from the kernel physical map.
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/machine/pmap.c45
-rw-r--r--arch/x86/machine/pmap.h12
2 files changed, 57 insertions, 0 deletions
diff --git a/arch/x86/machine/pmap.c b/arch/x86/machine/pmap.c
index 396edb4..3d53ef2 100644
--- a/arch/x86/machine/pmap.c
+++ b/arch/x86/machine/pmap.c
@@ -776,9 +776,54 @@ error_page:
}
#endif /* X86_PAE */
+static void __init
+pmap_setup_count_ptes(void)
+{
+ const struct pmap_pt_level *pt_level;
+ struct vm_page *page;
+ unsigned long va;
+ unsigned int level;
+ pmap_pte_t *pte;
+
+ va = 0;
+
+ /*
+ * Only count entries at lowest level. Accounting on upper PTPs is done
+ * when walking the recursive mapping.
+ */
+ do {
+#ifdef __LP64__
+ /* Handle long mode canonical form */
+ if (va == ((PMAP_VA_MASK >> 1) + 1))
+ va = ~(PMAP_VA_MASK >> 1);
+#endif /* __LP64__ */
+
+ for (level = PMAP_NR_LEVELS; level > 0; level--) {
+ pt_level = &pmap_pt_levels[level - 1];
+ pte = &pt_level->ptes[PMAP_PTEMAP_INDEX(va, pt_level->shift)];
+
+ if (*pte == 0) {
+ pte = NULL;
+ va = P2END(va, 1UL << pt_level->shift);
+ break;
+ }
+ }
+
+ if (pte == NULL)
+ continue;
+
+ page = vm_kmem_lookup_page(vm_page_trunc((unsigned long)pte));
+ assert(page != NULL);
+ page->pmap_page.nr_ptes++;
+ va += PAGE_SIZE;
+ } while (va != 0);
+}
+
void __init
pmap_setup(void)
{
+ pmap_setup_count_ptes();
+
kmem_cache_init(&pmap_cache, "pmap", sizeof(struct pmap),
0, NULL, NULL, NULL, 0);
diff --git a/arch/x86/machine/pmap.h b/arch/x86/machine/pmap.h
index 8a03e19..5d51480 100644
--- a/arch/x86/machine/pmap.h
+++ b/arch/x86/machine/pmap.h
@@ -128,6 +128,18 @@ struct pmap {
extern struct pmap *kernel_pmap;
/*
+ * Per physical page data specific to the pmap module.
+ *
+ * On this architecture, the number of page table entries is stored in page
+ * table page descriptors.
+ */
+struct pmap_page {
+ unsigned short nr_ptes;
+};
+
+#define PMAP_DEFINE_PAGE
+
+/*
* Early initialization of the MMU.
*
* This function is called before paging is enabled by the boot module. It