Patchwork [kvm-unit-tests,10/11] arm/arm64: allow setup_vm to be skipped

login
register
mail settings
Submitter Andrew Jones
Date Jan. 16, 2018, 6:53 p.m.
Message ID <20180116185312.7257-11-drjones@redhat.com>
Download mbox | patch
Permalink /patch/429131/
State New
Headers show

Comments

Andrew Jones - Jan. 16, 2018, 6:53 p.m.
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@redhat.com>
---
 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(-)

Patch

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