summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-10-22 20:56:25 +0200
committerRichard Braun <rbraun@sceen.net>2017-10-22 20:56:25 +0200
commit622208a4b3c0458bbb1bfb6dfe9560d879c023bc (patch)
treef07f7b9d5a811ac38de6e7187c008d83f7ca49e5
parenta70741cdec17094276e9aa59bebe5cf4a0ef812b (diff)
Rework the vm_ptable boot interface
-rw-r--r--arch/arm/machine/pmap.c10
-rw-r--r--vm/vm_ptable.c86
-rw-r--r--vm/vm_ptable.h9
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);