Determine whether or not to enable the MMU during setup with an auxinfo flag. This gives unit tests that need to start cpu0 at main() with the MMU off, and no page tables constructed, the option to do so. The physical page allocator is now used as the basis for alloc_ops, allowing both malloc() and page_alloc() to work without a setup_vm() call. The unit test can still call setup_vm() itself later. Secondaries will also start in their entry points with the MMU off. If page tables have already been constructed by another CPU, and are pointed to by e.g. 'pgtable', then the secondary can easily enable the MMU with mmu_enable(pgtable). Naturally unit tests that start multiple CPUs with the MMU off need to keep track of each CPU's MMU enable status and which set of ops are pointed to by alloc_ops. Also note, spinlocks may not work as expected with the MMU off. IOW, this option gives a unit test plenty of rope to shoot itself with. Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> --- arm/cstart.S | 19 ++++++++++++++++++- arm/cstart64.S | 17 ++++++++++++++++- lib/arm/setup.c | 16 +++++++++++----- lib/arm/smp.c | 8 ++++++-- lib/auxinfo.h | 5 +++++ 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/arm/cstart.S b/arm/cstart.S index 86d879ec7b35..114726feab82 100644 --- a/arm/cstart.S +++ b/arm/cstart.S @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2. */ #define __ASSEMBLY__ +#include <auxinfo.h> #include <asm/thread_info.h> #include <asm/asm-offsets.h> #include <asm/ptrace.h> @@ -57,7 +58,12 @@ start: /* complete setup */ pop {r0-r1} bl setup + bl get_mmu_off + cmp r0, #0 + bne 1f + bl setup_vm +1: /* run the test */ ldr r0, =__argc ldr r0, [r0] @@ -96,14 +102,25 @@ exceptions_init: .text +.global get_mmu_off +get_mmu_off: + ldr r0, =auxinfo + ldr r0, [r0, #4] + and r0, #AUXINFO_MMU_OFF + mov pc, lr + .global secondary_entry secondary_entry: - /* enable the MMU */ + /* enable the MMU unless requested off */ + bl get_mmu_off + cmp r0, #0 + bne 1f mov r1, #0 ldr r0, =mmu_idmap ldr r0, [r0] bl asm_mmu_enable +1: /* * Set the stack, and set up vector table * and exception stacks. Exception stacks diff --git a/arm/cstart64.S b/arm/cstart64.S index 0a2658746a4d..cbb4fb65683d 100644 --- a/arm/cstart64.S +++ b/arm/cstart64.S @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU GPL, version 2. */ #define __ASSEMBLY__ +#include <auxinfo.h> #include <asm/asm-offsets.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -38,7 +39,11 @@ start: /* complete setup */ ldp x0, x1, [sp], #16 bl setup + bl get_mmu_off + cbnz x0, 1f + bl setup_vm +1: /* run the test */ adrp x0, __argc ldr x0, [x0, :lo12:__argc] @@ -59,6 +64,13 @@ exceptions_init: .text +.globl get_mmu_off +get_mmu_off: + adrp x0, auxinfo + ldr x0, [x0, :lo12:auxinfo + 8] + and x0, x0, #AUXINFO_MMU_OFF + ret + .globl secondary_entry secondary_entry: /* Enable FP/ASIMD */ @@ -68,11 +80,14 @@ secondary_entry: /* set up exception handling */ bl exceptions_init - /* enable the MMU */ + /* enable the MMU unless requested off */ + bl get_mmu_off + cbnz x0, 1f adrp x0, mmu_idmap ldr x0, [x0, :lo12:mmu_idmap] bl asm_mmu_enable +1: /* set the stack */ adrp x0, secondary_data ldr x0, [x0, :lo12:secondary_data] diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 04169da179bc..d9458a888b55 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -15,11 +15,11 @@ #include <devicetree.h> #include <alloc.h> #include <alloc_phys.h> +#include <alloc_page.h> #include <argv.h> #include <asm/thread_info.h> #include <asm/setup.h> #include <asm/page.h> -#include <asm/mmu.h> #include <asm/smp.h> extern unsigned long stacktop; @@ -70,6 +70,7 @@ static void mem_init(phys_addr_t freemem_start) struct mem_region primary, mem = { .start = (phys_addr_t)-1, }; + phys_addr_t base, top; int nr_regs, i; nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS); @@ -108,7 +109,14 @@ static void mem_init(phys_addr_t freemem_start) phys_alloc_init(freemem_start, primary.end - freemem_start); phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); - setup_vm(); + phys_alloc_get_unused(&base, &top); + base = PAGE_ALIGN(base); + top = top & PAGE_MASK; + assert(sizeof(long) == 8 || !(base >> 32)); + if (sizeof(long) != 8 && (top >> 32) != 0) + top = ((uint64_t)1 << 32); + free_pages((void *)(unsigned long)base, top - base); + page_alloc_ops_enable(); } void setup(const void *fdt) @@ -156,14 +164,12 @@ void setup(const void *fdt) } /* call init functions */ + mem_init(PAGE_ALIGN((unsigned long)freemem)); cpu_init(); /* cpu_init must be called before thread_info_init */ thread_info_init(current_thread_info(), 0); - /* thread_info_init must be called before mem_init */ - mem_init(PAGE_ALIGN((unsigned long)freemem)); - /* mem_init must be called before io_init */ io_init(); diff --git a/lib/arm/smp.c b/lib/arm/smp.c index 27f6fcd07109..3a4151e2da12 100644 --- a/lib/arm/smp.c +++ b/lib/arm/smp.c @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2. */ #include <libcflat.h> +#include <auxinfo.h> #include <asm/thread_info.h> #include <asm/spinlock.h> #include <asm/cpumask.h> @@ -33,8 +34,11 @@ secondary_entry_fn secondary_cinit(void) secondary_entry_fn entry; thread_info_init(ti, 0); - ti->pgtable = mmu_idmap; - mmu_mark_enabled(ti->cpu); + + if (!(auxinfo.flags & AUXINFO_MMU_OFF)) { + ti->pgtable = mmu_idmap; + mmu_mark_enabled(ti->cpu); + } /* * Save secondary_data.entry locally to avoid opening a race diff --git a/lib/auxinfo.h b/lib/auxinfo.h index c074f43a0b83..08b96f8ece4c 100644 --- a/lib/auxinfo.h +++ b/lib/auxinfo.h @@ -4,6 +4,10 @@ */ #ifndef _AUXINFO_H_ #define _AUXINFO_H_ + +#define AUXINFO_MMU_OFF (1 << 0) + +#ifndef __ASSEMBLY__ struct auxinfo { const char *progname; unsigned long flags; @@ -12,3 +16,4 @@ struct auxinfo { /* No extern! Define a common symbol. */ struct auxinfo auxinfo; #endif +#endif -- 2.13.6