diff options
author | Richard Braun <rbraun@sceen.net> | 2014-12-06 13:00:05 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2014-12-06 13:00:05 +0100 |
commit | 48361587af2ddbd92cb84c0465bd797be65436e7 (patch) | |
tree | e0bf6f2fefe8afeb5c7f774c227771594214dfc7 | |
parent | 70c2a5282f86a0c57232c012229fe606a573ee43 (diff) |
x86/pmap: remove page table accounting
This kind of strict accounting can lead to a kind of thrashing where one
or more tables can get allocated and released very frequently. For now,
take the naive approach of not freeing page table pages until the complete
tree is torn down.
Remove the now irrelevant x86_pmap_remove_ptp test module.
-rw-r--r-- | Makefrag.am | 4 | ||||
-rw-r--r-- | arch/x86/machine/pmap.c | 76 | ||||
-rw-r--r-- | arch/x86/machine/pmap.h | 12 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | test/test_x86_pmap_remove_ptp.c | 128 | ||||
-rw-r--r-- | vm/vm_page.h | 8 |
6 files changed, 4 insertions, 230 deletions
diff --git a/Makefrag.am b/Makefrag.am index cdcdd1c8..4ae58796 100644 --- a/Makefrag.am +++ b/Makefrag.am @@ -96,10 +96,6 @@ if TEST_X86_DOUBLE_FAULT x15_SOURCES += test/test_x86_double_fault.c endif TEST_X86_DOUBLE_FAULT -if TEST_X86_PMAP_REMOVE_PTP -x15_SOURCES += test/test_x86_pmap_remove_ptp.c -endif TEST_X86_PMAP_REMOVE_PTP - if TEST_XCALL x15_SOURCES += test/test_xcall.c endif TEST_XCALL diff --git a/arch/x86/machine/pmap.c b/arch/x86/machine/pmap.c index f88d85a4..95b267e9 100644 --- a/arch/x86/machine/pmap.c +++ b/arch/x86/machine/pmap.c @@ -942,16 +942,6 @@ pmap_unmap_ptp(struct pmap_tmp_mapping *ptp_mapping, unsigned int nr_pages) } static void __init -pmap_setup_inc_nr_ptes(pmap_pte_t *pte) -{ - struct vm_page *page; - - page = vm_kmem_lookup_page(pte); - assert(page != NULL); - page->pmap_page.nr_ptes++; -} - -static void __init pmap_setup_set_ptp_type(pmap_pte_t *pte) { struct vm_page *page; @@ -968,13 +958,10 @@ pmap_setup_set_ptp_type(pmap_pte_t *pte) static void __init pmap_setup_count_ptes(void) { - pmap_walk_vas(0, pmap_boot_heap, 1, pmap_setup_inc_nr_ptes); pmap_walk_vas(0, pmap_boot_heap, 1, pmap_setup_set_ptp_type); /* Account for the reserved mappings, whether they exist or not */ pmap_walk_vas(pmap_boot_heap, pmap_boot_heap_end, 0, - pmap_setup_inc_nr_ptes); - pmap_walk_vas(pmap_boot_heap, pmap_boot_heap_end, 0, pmap_setup_set_ptp_type); } @@ -1010,7 +997,6 @@ pmap_copy_cpu_table_recursive(struct vm_page *page, phys_addr_t pa, orig_page = vm_kmem_lookup_page(spt); assert(orig_page != NULL); - page->pmap_page.nr_ptes = orig_page->pmap_page.nr_ptes; if (level == PMAP_NR_LEVELS - 1) { is_root = 1; @@ -1177,20 +1163,6 @@ pmap_create(struct pmap **pmapp) } static void -pmap_enter_ptemap_inc_nr_ptes(const pmap_pte_t *pte) -{ - struct vm_page *page; - - if (!pmap_ready) - return; - - page = vm_kmem_lookup_page(pte); - assert(page != NULL); - assert(vm_page_type(page) == VM_PAGE_PMAP); - page->pmap_page.nr_ptes++; -} - -static void pmap_enter_ptemap(struct pmap *pmap, unsigned long va, phys_addr_t pa, int prot) { const struct pmap_pt_level *pt_level; @@ -1226,13 +1198,11 @@ pmap_enter_ptemap(struct pmap *pmap, unsigned long va, phys_addr_t pa, int prot) ptp_pa = vm_page_to_pa(page); } - pmap_enter_ptemap_inc_nr_ptes(pte); pmap_zero_page(ptp_pa); pmap_pte_set(pte, ptp_pa, pte_bits, level); } pte = PMAP_PTEMAP_BASE + PMAP_PTEMAP_INDEX(va, PMAP_L0_SKIP); - pmap_enter_ptemap_inc_nr_ptes(pte); pte_bits = ((pmap == kernel_pmap) ? PMAP_PTE_G : PMAP_PTE_US) | pmap_prot_table[prot & VM_PROT_ALL]; pmap_pte_set(pte, pa, pte_bits, 0); @@ -1286,53 +1256,13 @@ pmap_enter(struct pmap *pmap, unsigned long va, phys_addr_t pa, static void pmap_remove_ptemap(unsigned long va) { - const struct pmap_pt_level *pt_level; - struct vm_page *page; - pmap_pte_t *pte, *prev_pte; - unsigned long index; - unsigned int level; + pmap_pte_t *pte; if (!pmap_ready) return; - page = NULL; - prev_pte = NULL; - - for (level = 0; level != PMAP_NR_LEVELS; level++) { - pt_level = &pmap_pt_levels[level]; - index = PMAP_PTEMAP_INDEX(va, pt_level->skip); - pte = &pt_level->ptemap_base[index]; - pmap_pte_clear(pte); - - /* - * Although the caller takes care of flushing the TLB for level 0 - * entries, it is mandatory to immediately flush entries for addresses - * inside the recursive mapping because, following the removal of a - * PTP, new PTPs, with different physical addresses, may be inserted - * as a result of mapping creation. Unconditionally flushing TLB - * entries referring to PTPs guarantees complete consistency of the - * page table structure. - * - * Note that this isn't needed when inserting PTPs because the TLB - * caches valid translations only. - */ - if (prev_pte != NULL) - cpu_tlb_flush_va((unsigned long)prev_pte); - - if (page != NULL) - vm_page_free(page, 0); - - page = vm_kmem_lookup_page(pte); - assert(page != NULL); - assert(vm_page_type(page) == VM_PAGE_PMAP); - assert(page->pmap_page.nr_ptes != 0); - page->pmap_page.nr_ptes--; - - if (page->pmap_page.nr_ptes != 0) - return; - - prev_pte = pte; - } + pte = PMAP_PTEMAP_BASE + PMAP_PTEMAP_INDEX(va, PMAP_L0_SKIP); + pmap_pte_clear(pte); } static void diff --git a/arch/x86/machine/pmap.h b/arch/x86/machine/pmap.h index 6bce8869..3df9219c 100644 --- a/arch/x86/machine/pmap.h +++ b/arch/x86/machine/pmap.h @@ -127,18 +127,6 @@ 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 diff --git a/configure.ac b/configure.ac index 5118972c..15ecbaea 100644 --- a/configure.ac +++ b/configure.ac @@ -49,10 +49,6 @@ m4_define([ENABLE_TEST_MODULE], [sref_dirty_zeroes], [test_sref_dirty_zeroes=yes], [sref_noref], [test_sref_noref=yes], [x86_double_fault], [test_x86_double_fault=yes], - [x86_pmap_remove_ptp], - [test_x86_pmap_remove_ptp=yes - AC_MSG_NOTICE([forcing max_cpus to 1]) - opt_max_cpus=1], [xcall], [test_xcall=yes], [AC_MSG_ERROR([invalid test module])]) AC_DEFINE([RUN_TEST_MODULE], [1], @@ -70,8 +66,6 @@ AM_CONDITIONAL([TEST_SREF_NOREF], [test x"$test_sref_noref" = xyes]) AM_CONDITIONAL([TEST_X86_DOUBLE_FAULT], [test x"$test_x86_double_fault" = xyes]) -AM_CONDITIONAL([TEST_X86_PMAP_REMOVE_PTP], - [test x"$test_x86_pmap_remove_ptp" = xyes]) AM_CONDITIONAL([TEST_XCALL], [test x"$test_xcall" = xyes]) diff --git a/test/test_x86_pmap_remove_ptp.c b/test/test_x86_pmap_remove_ptp.c deleted file mode 100644 index 88acc969..00000000 --- a/test/test_x86_pmap_remove_ptp.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2014 Richard Braun. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * - * This test module checks whether the TLB is correctly invalidated when - * the structure of page table pages change. It is specifically tailored - * for the x86 pmap module. It starts by allocating a physical page and - * a region of virtual memory. This region is aligned so that creating - * a physical mapping at its address involves the allocation of PTPs. - * It then creates the physical mapping and writes the page, causing the - * processor to cache page table entries. It then removes the physical - * mapping. After that, it allocates one dummy physical page. The purpose - * of this allocation is to force the pmap module to use pages at different - * physical addresses when allocating new PTPs. Finally, it recreates the - * same physical mapping as at the beginning, and attempts another write - * access. If the TLB isn't correctly handled, the second physical mapping - * creation fails because of stale entries when accessing intermediate PTPs. - * - * Note that, because of the complex optimizations around translation caching - * in modern processors, this test may report false positives. So far, best - * results are achieved with QEMU (without KVM), which seems to have reliable - * behaviour. - */ - -#include <kern/cpumap.h> -#include <kern/error.h> -#include <kern/panic.h> -#include <kern/param.h> -#include <kern/printk.h> -#include <kern/stddef.h> -#include <kern/string.h> -#include <kern/thread.h> -#include <machine/pmap.h> -#include <test/test.h> -#include <vm/vm_kmem.h> -#include <vm/vm_map.h> -#include <vm/vm_page.h> - -static void -test_run(void *arg) -{ - struct vm_page *page, *dummy; - unsigned long va; - int error, flags; - - (void)arg; - - printk("creating mapping\n"); - page = vm_page_alloc(0, VM_PAGE_KMEM); - - if (page == NULL) - panic("vm_page_alloc: %s", error_str(ERROR_NOMEM)); - - va = 0; - flags = VM_MAP_FLAGS(VM_PROT_ALL, VM_PROT_ALL, VM_INHERIT_NONE, - VM_ADV_DEFAULT, 0); - error = vm_map_enter(kernel_map, &va, (1UL << 22), (1UL << 22), flags, - NULL, 0); - error_check(error, "vm_map_enter"); - pmap_enter(kernel_pmap, va, vm_page_to_pa(page), - VM_PROT_READ | VM_PROT_WRITE, PMAP_PEF_GLOBAL); - pmap_update(kernel_pmap); - - printk("writing page, va:%p\n", (void *)va); - memset((void *)va, 'a', PAGE_SIZE); - - printk("removing mapping\n"); - pmap_remove(kernel_pmap, va, cpumap_all()); - pmap_update(kernel_pmap); - - printk("allocating dummy physical page\n"); - dummy = vm_page_alloc(0, VM_PAGE_KMEM); - - if (dummy == NULL) - panic("vm_page_alloc: %s", error_str(ERROR_NOMEM)); - - printk("recreating mapping\n"); - pmap_enter(kernel_pmap, va, vm_page_to_pa(page), - VM_PROT_READ | VM_PROT_WRITE, PMAP_PEF_GLOBAL); - pmap_update(kernel_pmap); - - printk("rewriting page\n"); - memset((void *)va, 'a', PAGE_SIZE); - - printk("done\n"); -} - -void -test_setup(void) -{ - struct thread_attr attr; - struct thread *thread; - struct cpumap *cpumap; - int error; - - /* - * Bind to BSP and run at maximum priority to prevent anything else - * from doing a complete TLB flush, meddling with the test. - */ - - error = cpumap_create(&cpumap); - error_check(error, "cpumap_create"); - - cpumap_zero(cpumap); - cpumap_set(cpumap, 0); - thread_attr_init(&attr, "x15_test_run"); - thread_attr_set_detached(&attr); - thread_attr_set_cpumap(&attr, cpumap); - thread_attr_set_policy(&attr, THREAD_SCHED_POLICY_FIFO); - thread_attr_set_priority(&attr, THREAD_SCHED_RT_PRIO_MAX); - error = thread_create(&thread, &attr, test_run, NULL); - error_check(error, "thread_create"); - - cpumap_destroy(cpumap); -} diff --git a/vm/vm_page.h b/vm/vm_page.h index 84ba2449..f2254498 100644 --- a/vm/vm_page.h +++ b/vm/vm_page.h @@ -62,13 +62,7 @@ struct vm_page { unsigned short seg_index; unsigned short order; phys_addr_t phys_addr; - - union { -#ifdef PMAP_DEFINE_PAGE - struct pmap_page pmap_page; -#endif /* PMAP_DEFINE_PAGE */ - void *slab_priv; - }; + void *slab_priv; }; static inline unsigned short |