@@ -10,6 +10,7 @@ extern void mmu_mark_enabled(int cpu);
extern void mmu_mark_disabled(int cpu);
extern void mmu_enable(pgd_t *pgtable);
extern void mmu_disable(void);
+extern void mmu_setup_early(phys_addr_t unused0, void *unused1);
extern void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset,
phys_addr_t phys_start, phys_addr_t phys_end,
@@ -41,10 +41,21 @@
#define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr))
#define pgd_free(pgd) free(pgd)
+static inline pgd_t *pgd_alloc_early(void)
+{
+ pgd_t *pgd = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pgd, 0, PAGE_SIZE);
+ return pgd;
+}
static inline pgd_t *pgd_alloc(void)
{
+ pgd_t *pgd;
+
assert(PTRS_PER_PGD * sizeof(pgd_t) <= PAGE_SIZE);
- pgd_t *pgd = alloc_page();
+ if (page_alloc_initialized())
+ pgd = alloc_page();
+ else
+ pgd = pgd_alloc_early();
return pgd;
}
@@ -71,11 +82,23 @@ static inline pmd_t *pmd_alloc_one(void)
pmd_t *pmd = alloc_page();
return pmd;
}
+static inline pmd_t *pmd_alloc_one_early(void)
+{
+ assert(PTRS_PER_PMD * sizeof(pmd_t) == PAGE_SIZE);
+ pmd_t *pmd = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pmd, 0, PAGE_SIZE);
+ return pmd;
+}
static inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long addr)
{
if (pgd_none(*pgd)) {
pgd_t entry;
- pgd_val(entry) = pgtable_pa(pmd_alloc_one()) | PMD_TYPE_TABLE;
+ pmd_t *pmd;
+ if (page_alloc_initialized())
+ pmd = pmd_alloc_one();
+ else
+ pmd = pmd_alloc_one_early();
+ pgd_val(entry) = pgtable_pa(pmd) | PMD_TYPE_TABLE;
WRITE_ONCE(*pgd, entry);
}
return pmd_offset(pgd, addr);
@@ -98,12 +121,25 @@ static inline pte_t *pte_alloc_one(void)
pte_t *pte = alloc_page();
return pte;
}
+static inline pte_t *pte_alloc_one_early(void)
+{
+ assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE);
+ pte_t *pte = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pte, 0, PAGE_SIZE);
+ return pte;
+}
static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr)
{
if (pmd_none(*pmd)) {
pmd_t entry;
- pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE;
+ pte_t *pte;
+ if (page_alloc_initialized())
+ pte = pte_alloc_one();
+ else
+ pte = pte_alloc_one_early();
+ pmd_val(entry) = pgtable_pa(pte) | PMD_TYPE_TABLE;
WRITE_ONCE(*pmd, entry);
+
}
return pte_offset(pmd, addr);
}
@@ -12,11 +12,10 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/pgtable-hwdef.h>
-#include "alloc_page.h"
#include "vmalloc.h"
-#include <asm/pgtable-hwdef.h>
-#include <asm/pgtable.h>
#include <linux/compiler.h>
@@ -153,19 +152,18 @@ void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset,
}
}
-void *setup_mmu(phys_addr_t unused0, void *unused1)
+void mmu_setup_early(phys_addr_t unused0, void *unused1)
{
struct mem_region *r;
-#ifdef __aarch64__
- init_alloc_vpage((void*)(4ul << 30));
+ assert(!mmu_enabled() && !page_alloc_initialized());
+#ifdef __aarch64__
assert_msg(system_supports_granule(PAGE_SIZE),
"Unsupported translation granule %ld\n", PAGE_SIZE);
#endif
- if (!mmu_idmap)
- mmu_idmap = pgd_alloc();
+ mmu_idmap = pgd_alloc();
for (r = mem_regions; r->end; ++r) {
if (r->flags & MR_F_IO) {
@@ -180,7 +178,21 @@ void *setup_mmu(phys_addr_t unused0, void *unused1)
}
}
- mmu_enable(mmu_idmap);
+ asm_mmu_enable((phys_addr_t)(unsigned long)mmu_idmap);
+}
+
+void *setup_mmu(phys_addr_t unused0, void *unused1)
+{
+ struct thread_info *info = current_thread_info();
+
+ assert(mmu_idmap);
+
+#ifdef __aarch64__
+ init_alloc_vpage((void*)(4ul << 30));
+#endif
+
+ mmu_mark_enabled(info->cpu);
+
return mmu_idmap;
}
@@ -189,17 +201,10 @@ void __iomem *__ioremap(phys_addr_t phys_addr, size_t size)
phys_addr_t paddr_aligned = phys_addr & PAGE_MASK;
phys_addr_t paddr_end = PAGE_ALIGN(phys_addr + size);
pgprot_t prot = __pgprot(PTE_UNCACHED | PTE_USER | PTE_UXN | PTE_PXN);
- pgd_t *pgtable;
+ pgd_t *pgtable = current_thread_info()->pgtable;
assert(sizeof(long) == 8 || !(phys_addr >> 32));
-
- if (mmu_enabled()) {
- pgtable = current_thread_info()->pgtable;
- } else {
- if (!mmu_idmap)
- mmu_idmap = pgd_alloc();
- pgtable = mmu_idmap;
- }
+ assert(pgtable);
mmu_set_range_ptes(pgtable, paddr_aligned, paddr_aligned,
paddr_end, prot);
@@ -209,8 +214,9 @@ void __iomem *__ioremap(phys_addr_t phys_addr, size_t size)
phys_addr_t __virt_to_phys(unsigned long addr)
{
- if (mmu_enabled()) {
- pgd_t *pgtable = current_thread_info()->pgtable;
+ pgd_t *pgtable = current_thread_info()->pgtable;
+
+ if (mmu_enabled() && pgtable) {
return virt_to_pte_phys(pgtable, (void *)addr);
}
return addr;
@@ -5,7 +5,10 @@
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
+#include <auxinfo.h>
#include <libcflat.h>
+
+#include <asm/mmu.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
@@ -119,6 +122,8 @@ void thread_info_init(struct thread_info *ti, unsigned int flags)
{
ti->cpu = mpidr_to_cpu(get_mpidr());
ti->flags = flags;
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
+ ti->pgtable = mmu_idmap;
}
void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr)
@@ -26,6 +26,7 @@
#include <asm/smp.h>
#include <asm/timer.h>
#include <asm/psci.h>
+#include <asm/mmu.h>
#include "io.h"
@@ -189,6 +190,9 @@ static void mem_init(phys_addr_t freemem_start)
phys_alloc_init(freemem_start, freemem->end - freemem_start);
phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES);
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
+ mmu_setup_early(0, NULL);
+
phys_alloc_get_unused(&base, &top);
base = PAGE_ALIGN(base);
top = top & PAGE_MASK;
@@ -38,10 +38,8 @@ secondary_entry_fn secondary_cinit(void)
thread_info_init(ti, 0);
- if (!(auxinfo.flags & AUXINFO_MMU_OFF)) {
- ti->pgtable = mmu_idmap;
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
mmu_mark_enabled(ti->cpu);
- }
/*
* Save secondary_data.entry locally to avoid opening a race
@@ -47,10 +47,21 @@
#define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr))
#define pgd_free(pgd) free(pgd)
+static inline pgd_t *pgd_alloc_early(void)
+{
+ pgd_t *pgd = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pgd, 0, PAGE_SIZE);
+ return pgd;
+}
static inline pgd_t *pgd_alloc(void)
{
+ pgd_t *pgd;
+
assert(PTRS_PER_PGD * sizeof(pgd_t) <= PAGE_SIZE);
- pgd_t *pgd = alloc_page();
+ if (page_alloc_initialized())
+ pgd = alloc_page();
+ else
+ pgd = pgd_alloc_early();
return pgd;
}
@@ -81,11 +92,23 @@ static inline pmd_t *pmd_alloc_one(void)
pmd_t *pmd = alloc_page();
return pmd;
}
+static inline pmd_t *pmd_alloc_one_early(void)
+{
+ assert(PTRS_PER_PMD * sizeof(pmd_t) == PAGE_SIZE);
+ pmd_t *pmd = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pmd, 0, PAGE_SIZE);
+ return pmd;
+}
static inline pmd_t *pmd_alloc(pud_t *pud, unsigned long addr)
{
if (pud_none(*pud)) {
pud_t entry;
- pud_val(entry) = pgtable_pa(pmd_alloc_one()) | PMD_TYPE_TABLE;
+ pmd_t *pmd;
+ if (page_alloc_initialized())
+ pmd = pmd_alloc_one();
+ else
+ pmd = pmd_alloc_one_early();
+ pud_val(entry) = pgtable_pa(pmd) | PMD_TYPE_TABLE;
WRITE_ONCE(*pud, entry);
}
return pmd_offset(pud, addr);
@@ -108,11 +131,23 @@ static inline pud_t *pud_alloc_one(void)
pud_t *pud = alloc_page();
return pud;
}
+static inline pud_t *pud_alloc_one_early(void)
+{
+ assert(PTRS_PER_PUD * sizeof(pud_t) == PAGE_SIZE);
+ pud_t *pud = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pud, 0, PAGE_SIZE);
+ return pud;
+}
static inline pud_t *pud_alloc(pgd_t *pgd, unsigned long addr)
{
if (pgd_none(*pgd)) {
pgd_t entry;
- pgd_val(entry) = pgtable_pa(pud_alloc_one()) | PMD_TYPE_TABLE;
+ pud_t *pud;
+ if (page_alloc_initialized())
+ pud = pud_alloc_one();
+ else
+ pud = pud_alloc_one_early();
+ pgd_val(entry) = pgtable_pa(pud) | PMD_TYPE_TABLE;
WRITE_ONCE(*pgd, entry);
}
return pud_offset(pgd, addr);
@@ -135,11 +170,23 @@ static inline pte_t *pte_alloc_one(void)
pte_t *pte = alloc_page();
return pte;
}
+static inline pte_t *pte_alloc_one_early(void)
+{
+ assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE);
+ pte_t *pte = memalign(PAGE_SIZE, PAGE_SIZE);
+ memset(pte, 0, PAGE_SIZE);
+ return pte;
+}
static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr)
{
if (pmd_none(*pmd)) {
pmd_t entry;
- pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE;
+ pte_t *pte;
+ if (page_alloc_initialized())
+ pte = pte_alloc_one();
+ else
+ pte = pte_alloc_one_early();
+ pmd_val(entry) = pgtable_pa(pte) | PMD_TYPE_TABLE;
WRITE_ONCE(*pmd, entry);
}
return pte_offset(pmd, addr);
@@ -5,7 +5,9 @@
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
+#include <auxinfo.h>
#include <libcflat.h>
+#include <asm/mmu.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
@@ -234,6 +236,8 @@ static void __thread_info_init(struct thread_info *ti, unsigned int flags)
{
ti->cpu = mpidr_to_cpu(get_mpidr());
ti->flags = flags;
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
+ ti->pgtable = mmu_idmap;
}
void thread_info_init(struct thread_info *ti, unsigned int flags)
Enable the MMU immediately after the physical allocator is initialized, to make reasoning about what cache maintenance operations are needed a lot easier. Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com> --- lib/arm/asm/mmu-api.h | 1 + lib/arm/asm/pgtable.h | 42 ++++++++++++++++++++++++++++--- lib/arm/mmu.c | 46 +++++++++++++++++++--------------- lib/arm/processor.c | 5 ++++ lib/arm/setup.c | 4 +++ lib/arm/smp.c | 4 +-- lib/arm64/asm/pgtable.h | 55 ++++++++++++++++++++++++++++++++++++++--- lib/arm64/processor.c | 4 +++ 8 files changed, 131 insertions(+), 30 deletions(-)