diff options
author | Richard Braun <rbraun@sceen.net> | 2013-07-23 22:26:04 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2013-07-23 22:26:04 +0200 |
commit | 70c2461661ac7f4bd8ad877af8bcaec1abd0c645 (patch) | |
tree | 4f7cb7a15992484e342dde9b3cb898f2b1d57c77 /arch | |
parent | 64a32afa728931bec0dc5189bab945b94369b474 (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.c | 45 | ||||
-rw-r--r-- | arch/x86/machine/pmap.h | 12 |
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 |