summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm/armv7/mmu.c26
-rw-r--r--src/arch/arm/include/armv7/arch/cache.h3
2 files changed, 21 insertions, 8 deletions
diff --git a/src/arch/arm/armv7/mmu.c b/src/arch/arm/armv7/mmu.c
index 727da5cf72..8c2f78c4d0 100644
--- a/src/arch/arm/armv7/mmu.c
+++ b/src/arch/arm/armv7/mmu.c
@@ -97,13 +97,17 @@ typedef uint64_t pte_t;
typedef uint32_t pte_t;
#endif /* CONFIG_ARM_LPAE */
+/* We set the first PTE to a sentinel value that cannot occur naturally (has
+ * attributes set but bits [1:0] are 0 -> unmapped) to mark unused subtables. */
+#define ATTR_UNUSED 0xBADbA6E0
+#define SUBTABLE_PTES (1 << (BLOCK_SHIFT - PAGE_SHIFT))
+
/*
* mask/shift/size for pages and blocks
*/
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define BLOCK_SIZE (1UL << BLOCK_SHIFT)
-#define SUBTABLE_SIZE ((1 << (BLOCK_SHIFT - PAGE_SHIFT)) * sizeof(pte_t))
/*
* MAIR Index
@@ -113,7 +117,6 @@ typedef uint32_t pte_t;
#define MAIR_INDX_WB 2
static pte_t *const ttb_buff = (void *)_ttb;
-static int used_tables = 0;
/* Not all boards want to use subtables and declare them in memlayout.ld. This
* outputs two 0x00000000 symbols if they don't, making _ttb_subtables_size 0.
@@ -156,12 +159,17 @@ static void mmu_fill_table(pte_t *table, u32 start_idx, u32 end_idx,
static pte_t *mmu_create_subtable(pte_t *pgd_entry)
{
- if (used_tables >= _ttb_subtables_size / SUBTABLE_SIZE)
- die("Not enough room for another sub-pagetable!");
+ pte_t *table = (pte_t *)_ttb_subtables;
+
+ /* Find unused subtable (first PTE == ATTR_UNUSED). */
+ while (table[0] != ATTR_UNUSED) {
+ table += SUBTABLE_PTES;
+ if ((pte_t *)_ettb_subtables - table <= 0)
+ die("Not enough room for another sub-pagetable!");
+ }
/* We assume that *pgd_entry must already be a valid block mapping. */
uintptr_t start_addr = (uintptr_t)(*pgd_entry & BLOCK_MASK);
- pte_t *table = (void *)(_ttb_subtables + used_tables++ * SUBTABLE_SIZE);
printk(BIOS_DEBUG, "Creating new subtable @%p for [%#.8x:%#.8lx)\n",
table, start_addr, start_addr + BLOCK_SIZE);
@@ -172,8 +180,7 @@ static pte_t *mmu_create_subtable(pte_t *pgd_entry)
attr = ((attr & ~(1 << 4)) | (1 << 0));
if (attr & ATTR_BLOCK)
attr = (attr & ~ATTR_BLOCK) | ATTR_PAGE;
- mmu_fill_table(table, 0, SUBTABLE_SIZE / sizeof(pte_t),
- start_addr, PAGE_SHIFT, attr);
+ mmu_fill_table(table, 0, SUBTABLE_PTES, start_addr, PAGE_SHIFT, attr);
/* Replace old entry in upper level table to point at subtable. */
*pgd_entry = (pte_t)(uintptr_t)table | ATTR_NEXTLEVEL;
@@ -265,6 +272,11 @@ void mmu_config_range(u32 start_mb, u32 size_mb, enum dcache_policy policy)
*/
void mmu_init(void)
{
+ /* Initially mark all subtables as unused (first PTE == ATTR_UNUSED). */
+ pte_t *table = (pte_t *)_ttb_subtables;
+ for (; (pte_t *)_ettb_subtables - table > 0; table += SUBTABLE_PTES)
+ table[0] = ATTR_UNUSED;
+
if (CONFIG_ARM_LPAE) {
pte_t *const pgd_buff = (pte_t*)(_ttb + 16*KiB);
pte_t *pmd = ttb_buff;
diff --git a/src/arch/arm/include/armv7/arch/cache.h b/src/arch/arm/include/armv7/arch/cache.h
index df44c47f21..1e6477768c 100644
--- a/src/arch/arm/include/armv7/arch/cache.h
+++ b/src/arch/arm/include/armv7/arch/cache.h
@@ -384,7 +384,8 @@ void tlb_invalidate_all(void);
* Generalized setup/init functions
*/
-/* mmu initialization (set page table address, set permissions, etc) */
+/* MMU initialization (set page table base, permissions, initialize subtable
+ * buffer, etc.). Must only be called ONCE PER BOOT, before any mappings. */
void mmu_init(void);
enum dcache_policy {