diff options
author | Richard Braun <rbraun@sceen.net> | 2017-10-22 20:56:25 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-10-22 20:56:25 +0200 |
commit | 622208a4b3c0458bbb1bfb6dfe9560d879c023bc (patch) | |
tree | f07f7b9d5a811ac38de6e7187c008d83f7ca49e5 | |
parent | a70741cdec17094276e9aa59bebe5cf4a0ef812b (diff) |
Rework the vm_ptable boot interface
-rw-r--r-- | arch/arm/machine/pmap.c | 10 | ||||
-rw-r--r-- | vm/vm_ptable.c | 86 | ||||
-rw-r--r-- | vm/vm_ptable.h | 9 |
3 files changed, 61 insertions, 44 deletions
diff --git a/arch/arm/machine/pmap.c b/arch/arm/machine/pmap.c index 390faf57..4943286f 100644 --- a/arch/arm/machine/pmap.c +++ b/arch/arm/machine/pmap.c @@ -105,7 +105,7 @@ pmap_make_section_pte(phys_addr_t pa, int prot) /* * Table of properties per page table level. */ -static const struct vm_ptable_level pmap_pt_levels[] = { +static struct vm_ptable_level pmap_boot_pt_levels[] __bootdata = { { PMAP_L0_SKIP, PMAP_L0_BITS, @@ -157,23 +157,23 @@ pmap_boot_get_large_pgsize(void) pmap_pte_t * __boot pmap_setup_paging(void) { - const struct vm_ptable_level *pt_levels; unsigned long i, size, pgsize; phys_addr_t pa, directmap_end; struct vm_ptable *ptable; struct pmap *kernel_pmap; uintptr_t va; - pt_levels = (void *)BOOT_VTOP((uintptr_t)&pmap_pt_levels); kernel_pmap = (void *)BOOT_VTOP((uintptr_t)&pmap_kernel_pmap); - ptable = &kernel_pmap->ptable; /* Use large pages for the direct physical mapping when possible */ pgsize = pmap_boot_get_large_pgsize(); /* TODO LPAE */ - vm_ptable_init(ptable, pt_levels, ARRAY_SIZE(pmap_pt_levels)); + vm_ptable_bootstrap(pmap_boot_pt_levels, ARRAY_SIZE(pmap_boot_pt_levels)); + + ptable = &kernel_pmap->ptable; + vm_ptable_build(ptable); /* * Create the initial mappings. The first is for the .boot section diff --git a/vm/vm_ptable.c b/vm/vm_ptable.c index 7b6d230a..73ed18bf 100644 --- a/vm/vm_ptable.c +++ b/vm/vm_ptable.c @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * * + * TODO Define "page table". * TODO Review locking. */ @@ -50,6 +51,9 @@ #include <vm/vm_ptable.h> #include <vm/vm_prot.h> +static const struct vm_ptable_level *vm_ptable_boot_pt_levels __bootdata; +static unsigned int vm_ptable_boot_nr_levels __bootdata; + static struct vm_ptable_cpu_pt vm_ptable_boot_cpu_pt __bootdata; /* @@ -195,53 +199,67 @@ static int vm_ptable_do_remote_updates __read_mostly; static char vm_ptable_panic_inval_msg[] __bootdata = "vm_ptable: invalid physical address"; -static __always_inline unsigned long -vm_ptable_pte_index(uintptr_t va, const struct vm_ptable_level *pt_level) -{ - return ((va >> pt_level->skip) & ((1UL << pt_level->bits) - 1)); -} - void __boot -vm_ptable_init(struct vm_ptable *ptable, - const struct vm_ptable_level *pt_levels, - unsigned int nr_levels) +vm_ptable_bootstrap(const struct vm_ptable_level *pt_levels, + unsigned int nr_levels) { - const struct vm_ptable_level *pt_level; - struct vm_ptable_cpu_pt *pt; - + assert(pt_levels); assert(nr_levels != 0); - pt_level = &pt_levels[nr_levels - 1]; - pt = &vm_ptable_boot_cpu_pt; - pt->root = bootmem_alloc(pt_level->ptes_per_pt * sizeof(pmap_pte_t)); - ptable->cpu_pts[0] = pt; + vm_ptable_boot_pt_levels = pt_levels; + vm_ptable_boot_nr_levels = nr_levels; +} - for (size_t i = 1; i < ARRAY_SIZE(ptable->cpu_pts); i++) { - ptable->cpu_pts[i] = NULL; - } +static const struct vm_ptable_level * __boot +vm_ptable_boot_get_pt_level(unsigned int level) +{ + assert(level < vm_ptable_boot_nr_levels); + return &vm_ptable_boot_pt_levels[level]; +} - ptable->pt_levels = pt_levels; - ptable->nr_levels = nr_levels; +static __always_inline unsigned long +vm_ptable_level_pte_index(const struct vm_ptable_level *pt_level, uintptr_t va) +{ + return ((va >> pt_level->skip) & ((1UL << pt_level->bits) - 1)); } static __always_inline phys_addr_t -vm_ptable_pa_mask(const struct vm_ptable *ptable, unsigned int level) +vm_ptable_level_pa_mask(const struct vm_ptable_level *pt_level) { phys_addr_t size; - if (level == 0) { + if (pt_level == vm_ptable_boot_pt_levels) { return ~PAGE_MASK; } else { - size = ((phys_addr_t)1 << ptable->pt_levels[level - 1].bits) - * sizeof(pmap_pte_t); + pt_level--; + size = ((phys_addr_t)1 << pt_level->bits) * sizeof(pmap_pte_t); return ~(size - 1); } } static __always_inline bool -vm_ptable_pa_aligned(const struct vm_ptable *ptable, phys_addr_t pa) +vm_ptable_pa_aligned(phys_addr_t pa) { - return pa == (pa & vm_ptable_pa_mask(ptable, 0)); + phys_addr_t mask; + + mask = vm_ptable_level_pa_mask(vm_ptable_boot_get_pt_level(0)); + return pa == (pa & mask); +} + +void __boot +vm_ptable_build(struct vm_ptable *ptable) +{ + const struct vm_ptable_level *pt_level; + struct vm_ptable_cpu_pt *pt; + + pt_level = vm_ptable_boot_get_pt_level(vm_ptable_boot_nr_levels - 1); + pt = &vm_ptable_boot_cpu_pt; + pt->root = bootmem_alloc(pt_level->ptes_per_pt * sizeof(pmap_pte_t)); + ptable->cpu_pts[0] = pt; + + for (size_t i = 1; i < ARRAY_SIZE(ptable->cpu_pts); i++) { + ptable->cpu_pts[i] = NULL; + } } void __boot @@ -253,7 +271,7 @@ vm_ptable_boot_enter(struct vm_ptable *ptable, uintptr_t va, pmap_pte_t *pt, *next_pt, *pte; phys_addr_t mask; - if (!vm_ptable_pa_aligned(ptable, pa)) { + if (!vm_ptable_pa_aligned(pa)) { boot_panic(vm_ptable_panic_inval_msg); } @@ -267,12 +285,12 @@ vm_ptable_boot_enter(struct vm_ptable *ptable, uintptr_t va, last_level = 0; pt = ptable->cpu_pts[0]->root; - for (level = ptable->nr_levels - 1; level != last_level; level--) { - pt_level = &ptable->pt_levels[level]; - pte = &pt[vm_ptable_pte_index(va, pt_level)]; + for (level = vm_ptable_boot_nr_levels - 1; level != last_level; level--) { + pt_level = vm_ptable_boot_get_pt_level(level); + pte = &pt[vm_ptable_level_pte_index(pt_level, va)]; if (pmap_pte_valid(*pte)) { - mask = vm_ptable_pa_mask(ptable, level); + mask = vm_ptable_level_pa_mask(pt_level); next_pt = (void *)(uintptr_t)(*pte & mask); } else { next_pt = bootmem_alloc(pt_level->ptes_per_pt * sizeof(pmap_pte_t)); @@ -282,8 +300,8 @@ vm_ptable_boot_enter(struct vm_ptable *ptable, uintptr_t va, pt = next_pt; } - pt_level = &ptable->pt_levels[last_level]; - pte = &pt[vm_ptable_pte_index(va, pt_level)]; + pt_level = vm_ptable_boot_get_pt_level(last_level); + pte = &pt[vm_ptable_level_pte_index(pt_level, va)]; *pte = pt_level->make_ll_pte_fn(pa, VM_PROT_ALL); } diff --git a/vm/vm_ptable.h b/vm/vm_ptable.h index 0818864c..a6ba5902 100644 --- a/vm/vm_ptable.h +++ b/vm/vm_ptable.h @@ -43,13 +43,12 @@ struct vm_ptable_level { struct vm_ptable { struct vm_ptable_cpu_pt *cpu_pts[CONFIG_MAX_CPUS]; - const struct vm_ptable_level *pt_levels; - unsigned int nr_levels; }; -void vm_ptable_init(struct vm_ptable *ptable, - const struct vm_ptable_level *pt_levels, - unsigned int nr_levels); +void vm_ptable_bootstrap(const struct vm_ptable_level *pt_levels, + unsigned int nr_levels); + +void vm_ptable_build(struct vm_ptable *ptable); void vm_ptable_boot_enter(struct vm_ptable *ptable, uintptr_t va, phys_addr_t pa, size_t pgsize); |