[coreboot-gerrit] New patch to review for coreboot: arm64: Implement generic stage transitions for non-Tegra SoCs

Julius Werner (jwerner@chromium.org) gerrit at coreboot.org
Sat Oct 17 09:35:42 CEST 2015


Julius Werner (jwerner at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/12077

-gerrit

commit 10d0813f105a40e6f51cd7f8f1378e8f83504c81
Author: Julius Werner <jwerner at chromium.org>
Date:   Mon Oct 12 16:45:21 2015 -0700

    arm64: Implement generic stage transitions for non-Tegra SoCs
    
    The existing arm64 architecture code has been developed for the Tegra132
    and Tegra210 SoCs, which only start their ARM64 cores in ramstage. It
    interweaves the stage entry point with code that initializes a CPU (and
    should not be run again if that CPU already ran a previous stage). It
    also still contains some vestiges of SMP/secmon support (such as setting
    up stacks in the BSS instead of using the stage-peristent one from
    memlayout).
    
    This patch splits those functions apart and makes the code layout
    similar to how things work on ARM32. The default stage_entry() symbol is
    a no-op wrapper that just calls main() for the current stage, for the
    normal case where a stage ran on the same core as the last one. It can
    be overridden by SoC code to support special cases like Tegra.
    
    The CPU initialization code is split out into armv8/cpu.S (similar to
    what arm_init_caches() does for ARM32) and called by the default
    bootblock entry code. SoCs where a CPU starts up in a later stage can
    call the same code from a stage_entry() override instead.
    
    The Tegra132 and Tegra210 code is not touched by this patch to make it
    easier to review and validate. A follow-up patch will bring those SoCs
    in line with the model.
    
    BRANCH=None
    BUG=None
    TEST=Booted Oak with a single mmu_init()/mmu_enable(). Built Ryu and
    Smaug.
    
    Change-Id: I28302a6ace47e8ab7a736e089f64922cef1a2f93
    Signed-off-by: Julius Werner <jwerner at chromium.org>
---
 src/Kconfig                             |  4 +--
 src/arch/arm64/Makefile.inc             | 22 +++---------
 src/arch/arm64/armv8/Makefile.inc       |  3 ++
 src/arch/arm64/armv8/bootblock.S        | 45 +++++++++++++++---------
 src/arch/arm64/armv8/cpu.S              | 61 ++++++++++++++-------------------
 src/arch/arm64/armv8/exception.c        | 33 ------------------
 src/arch/arm64/boot.c                   |  8 +++++
 src/arch/arm64/include/arch/header.ld   |  6 +---
 src/arch/arm64/include/arch/memlayout.h |  7 ++--
 src/arch/arm64/stages.c                 | 48 --------------------------
 src/soc/nvidia/tegra132/Kconfig         |  5 +++
 src/soc/nvidia/tegra210/Kconfig         |  5 +++
 12 files changed, 86 insertions(+), 161 deletions(-)

diff --git a/src/Kconfig b/src/Kconfig
index 0830912..092fe51 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -422,8 +422,8 @@ config HEAP_SIZE
 
 config STACK_SIZE
 	hex
-	default 0x0 if (ARCH_RAMSTAGE_ARM || ARCH_RAMSTAGE_MIPS || ARCH_RAMSTAGE_RISCV)
-	default 0x1000
+	default 0x1000 if ARCH_X86
+	default 0x0
 
 config MAX_CPUS
 	int
diff --git a/src/arch/arm64/Makefile.inc b/src/arch/arm64/Makefile.inc
index 94c22dc..c63786f 100644
--- a/src/arch/arm64/Makefile.inc
+++ b/src/arch/arm64/Makefile.inc
@@ -37,16 +37,6 @@ ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM64),y)
 CBFSTOOL_PRE1_OPTS = -m arm64 -s $(CONFIG_CBFS_SIZE)
 endif
 
-ifeq ($(CONFIG_ARCH_ARM64),y)
-stages_c = $(src)/arch/arm64/stages.c
-stages_o = $(obj)/arch/arm64/stages.o
-
-$(stages_o): $(stages_c) $(obj)/config.h
-	@printf "    CC         $(subst $(obj)/,,$(@))\n"
-	$(CC_arm) -I. $(CPPFLAGS_arm) -c -o $@ $< -marm
-
-endif
-
 ################################################################################
 # bootblock
 ################################################################################
@@ -59,9 +49,7 @@ $(obj)/arch/arm64/id.bootblock.o: $(obj)/build.h
 
 bootblock-y += boot.c
 bootblock-y += c_entry.c
-bootblock-y += stage_entry.S
 bootblock-y += cpu-stubs.c
-bootblock-y += stages.c
 bootblock-y += eabi_compat.c
 bootblock-y += transition.c transition_asm.S
 
@@ -93,7 +81,6 @@ verstage-y += eabi_compat.c
 verstage-y += ../../lib/memset.c
 verstage-y += ../../lib/memcpy.c
 verstage-y += ../../lib/memmove.c
-verstage-y += stages.c
 
 endif # CONFIG_ARCH_VERSTAGE_ARM64
 
@@ -105,9 +92,7 @@ ifeq ($(CONFIG_ARCH_ROMSTAGE_ARM64),y)
 
 romstage-y += boot.c
 romstage-y += c_entry.c
-romstage-y += stage_entry.S
 romstage-y += cpu-stubs.c
-romstage-y += stages.c
 romstage-y += div0.c
 romstage-y += eabi_compat.c
 romstage-y += memset.S
@@ -133,7 +118,6 @@ endif # CONFIG_ARCH_ROMSTAGE_ARM64
 ifeq ($(CONFIG_ARCH_RAMSTAGE_ARM64),y)
 
 ramstage-y += c_entry.c
-ramstage-y += stages.c
 ramstage-y += startup.c
 ramstage-y += div0.c
 ramstage-y += eabi_compat.c
@@ -142,11 +126,15 @@ ramstage-y += tables.c
 ramstage-y += memset.S
 ramstage-y += memcpy.S
 ramstage-y += memmove.S
-ramstage-y += stage_entry.S
 ramstage-y += cpu-stubs.c
 ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += arm_tf.c
 ramstage-y += transition.c transition_asm.S
 
+# TODO: Replace this with a simpler ramstage entry point in soc/nvidia/tegra*
+ifeq ($(CONFIG_SOC_NVIDIA_TEGRA132)$(CONFIG_SOC_NVIDIA_TEGRA210),y)
+ramstage-y += stage_entry.S
+endif
+
 rmodules_arm64-y += memset.S
 rmodules_arm64-y += memcpy.S
 rmodules_arm64-y += memmove.S
diff --git a/src/arch/arm64/armv8/Makefile.inc b/src/arch/arm64/armv8/Makefile.inc
index a1d0046..0b3fe71 100644
--- a/src/arch/arm64/armv8/Makefile.inc
+++ b/src/arch/arm64/armv8/Makefile.inc
@@ -30,6 +30,9 @@ armv8_asm_flags = $(armv8_flags)
 ################################################################################
 ifeq ($(CONFIG_ARCH_BOOTBLOCK_ARMV8_64),y)
 
+ifneq ($(CONFIG_BOOTBLOCK_CUSTOM),y)
+bootblock-y += bootblock.S
+endif
 bootblock-y += cache.c
 bootblock-y += cache_helpers.S
 bootblock-y += cpu.S
diff --git a/src/arch/arm64/armv8/bootblock.S b/src/arch/arm64/armv8/bootblock.S
index b49f769..9cff9ea 100644
--- a/src/arch/arm64/armv8/bootblock.S
+++ b/src/arch/arm64/armv8/bootblock.S
@@ -1,7 +1,7 @@
 /*
  * Early initialization code for aarch64 (a.k.a. armv8)
  *
- * Copyright 2013  Google Inc.
+ * Copyright 2015 Google Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -18,21 +18,32 @@
  * Foundation, Inc.
  */
 
-	.section ".id", "a", %progbits
+#include <arch/asm.h>
 
-	.globl __id_start
-__id_start:
-ver:
-	.asciz COREBOOT_VERSION
-vendor:
-	.asciz CONFIG_MAINBOARD_VENDOR
-part:
-	.asciz CONFIG_MAINBOARD_PART_NUMBER
-.long __id_end - ver  /* Reverse offset to the vendor id */
-.long __id_end - vendor  /* Reverse offset to the vendor id */
-.long __id_end - part    /* Reverse offset to the part number */
-.long CONFIG_ROM_SIZE    /* Size of this romimage */
-	.globl __id_end
+ENTRY(_start)
+	/* Initialize PSTATE, SCTLR and caches to clean state. */
+	bl	arm64_init_cpu
 
-__id_end:
-.previous
+	/* Initialize stack with sentinel value to later check overflow. */
+	ldr	x0, =_stack
+	ldr	x1, =_estack
+	ldr	x2, =0xdeadbeefdeadbeef
+stack_init_loop:
+	stp	x2, x2, [x0], #16
+	cmp	x0, x1
+	bne	stack_init_loop
+
+	/* Leave a line of beef dead for easier visibility in stack dumps. */
+	sub	sp, x0, #16
+
+	/* HACK: Initialize SP_EL3 (exceptions) to use same stack as main code.
+	 * This is a temporary work-around which is fine as long as exceptions
+	 * are always fatal. Full exception support (for GDB) should probably
+	 * be implemented with a way to swap out the exception stack at runtime
+	 * for limited reentrancy support, like on ARM32 in libpayload. */
+	msr SPSel, #1
+	sub	sp, x0, #16
+	msr SPSel, #0
+
+	bl	main
+ENDPROC(_start)
diff --git a/src/arch/arm64/armv8/cpu.S b/src/arch/arm64/armv8/cpu.S
index 9319ff0..d574b78 100644
--- a/src/arch/arm64/armv8/cpu.S
+++ b/src/arch/arm64/armv8/cpu.S
@@ -23,27 +23,39 @@
 
 /*
  * Bring an ARMv8 processor we just gained control of (e.g. from IROM) into a
- * known state regarding caches/SCTLR. Completely cleans and invalidates
+ * known state regarding caches/SCTLR/PSTATE. Completely cleans and invalidates
  * icache/dcache, disables MMU and dcache (if active), and enables unaligned
- * accesses, icache and branch prediction (if inactive). Clobbers x4 and x5.
+ * accesses, icache and branch prediction (if inactive).
  */
-ENTRY(arm_init_caches)
-	/* w4: SCTLR, return address: x8 (stay valid for the whole function) */
-	mov	x8, x30
-	/* XXX: Assume that we always start running at EL3 */
-	mrs	x4, sctlr_el3
+ENTRY(arm64_init_cpu)
+	/* Initialize PSTATE (unmask all exceptions, select SP_EL0). */
+	msr	SPSel, #0
+	msr	DAIFClr, #0xf
 
-	/* FIXME: How to enable branch prediction on ARMv8? */
+	/* TODO: This is where we'd put non-boot CPUs into WFI if needed. */
+
+	/* x12: SCTLR, return address: x13 (must not get clobbered by subrtn) */
+	mov	x13, x30
+	/* TODO: Assert that we always start running at EL3 */
+	mrs	x12, sctlr_el3
+
+	/* Activate ICache (12) already for speed during cache flush. */
+	orr	x12, x12, #(1 << 12)
+	msr	sctlr_el3, x12
 
 	/* Flush and invalidate dcache */
 	mov	x0, #DCCISW
 	bl	flush_dcache_all
 
 	/* Deactivate MMU (0), Alignment Check (1) and DCache (2) */
-	and	x4, x4, # ~(1 << 0) & ~(1 << 1) & ~(1 << 2)
-	/* Activate ICache (12) already for speed */
-	orr	x4, x4, #(1 << 12)
-	msr	sctlr_el3, x4
+	and	x12, x12, # ~(1 << 0) & ~(1 << 1) & ~(1 << 2)
+	/* Activate Stack Alignment (3) because why not */
+	orr	x12, x12, #(1 << 3)
+	/* Set to little-endian (25) */
+	and	x12, x12, # ~(1 << 25)
+	/* Deactivate write-xor-execute enforcement (19) */
+	and	x12, x12, # ~(1 << 19)
+	msr	sctlr_el3, x12
 
 	/* Invalidate icache and TLB for good measure */
 	ic	iallu
@@ -51,26 +63,5 @@ ENTRY(arm_init_caches)
 	dsb	sy
 	isb
 
-	ret	x8
-ENDPROC(arm_init_caches)
-
-/* Based on u-boot transition.S */
-ENTRY(switch_el3_to_el2)
-	mov	x0, #0x5b1	/* Non-secure EL0/EL1 | HVC | 64bit EL2 */
-	msr	scr_el3, x0
-	msr	cptr_el3, xzr	/* Disable coprocessor traps to EL3 */
-	mov	x0, #0x33ff
-	msr	cptr_el2, x0	/* Disable coprocessor traps to EL2 */
-
-	/* Return to the EL2_SP2 mode from EL3 */
-	mov	x0, sp
-	msr	sp_el2, x0	/* Migrate SP */
-	mrs	x0, vbar_el3
-	msr	vbar_el2, x0	/* Migrate VBAR */
-	mrs	x0, sctlr_el3
-	msr	sctlr_el2, x0	/* Migrate SCTLR */
-	mov	x0, #0x3c9
-	msr	spsr_el3, x0	/* EL2_SP2 | D | A | I | F */
-	msr	elr_el3, x30
-	eret
-ENDPROC(switch_el3_to_el2)
+	ret	x13
+ENDPROC(arm64_init_cpu)
diff --git a/src/arch/arm64/armv8/exception.c b/src/arch/arm64/armv8/exception.c
index afbaf6d..ed6be7f 100644
--- a/src/arch/arm64/armv8/exception.c
+++ b/src/arch/arm64/armv8/exception.c
@@ -164,35 +164,6 @@ void exc_dispatch(struct exc_state *state, uint64_t idx)
 	exc_exit(&state->regs);
 }
 
-
-static int test_exception_handler(struct exc_state *state, uint64_t vector_id)
-{
-	/* Update instruction pointer to next instrution. */
-	state->elx.elr += sizeof(uint32_t);
-	raw_write_elr_current(state->elx.elr);
-	return EXC_RET_HANDLED;
-}
-
-static uint64_t test_exception(void)
-{
-	struct exception_handler sync_elx;
-	struct exception_handler sync_el0;
-	unsigned long long *a = (void *)0xffffffff00000000ULL;
-
-	sync_elx.handler = &test_exception_handler;
-	sync_el0.handler = &test_exception_handler;
-
-	exception_handler_register(EXC_VID_CUR_SP_ELX_SYNC, &sync_elx);
-	exception_handler_register(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0);
-
-	force_read(*a);
-
-	exception_handler_unregister(EXC_VID_CUR_SP_ELX_SYNC, &sync_elx);
-	exception_handler_unregister(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0);
-
-	return 0;
-}
-
 void exception_hwinit(void)
 {
 	exc_set_vbar();
@@ -204,8 +175,4 @@ void exception_init(void)
 	exception_hwinit();
 
 	printk(BIOS_DEBUG, "ARM64: Exception handlers installed.\n");
-
-	printk(BIOS_DEBUG, "ARM64: Testing exception\n");
-	test_exception();
-	printk(BIOS_DEBUG, "ARM64: Done test exception\n");
 }
diff --git a/src/arch/arm64/boot.c b/src/arch/arm64/boot.c
index 1cb01db..ab69ac0 100644
--- a/src/arch/arm64/boot.c
+++ b/src/arch/arm64/boot.c
@@ -75,3 +75,11 @@ void arch_prog_run(struct prog *prog)
 
 	doit(prog_entry_arg(prog));
 }
+
+#if !IS_ENABLED(CONFIG_SMP)
+/* Generic stage entry point. Can be overridden by board/SoC if needed. */
+__attribute__((weak)) void stage_entry(void)
+{
+	main();
+}
+#endif
diff --git a/src/arch/arm64/include/arch/header.ld b/src/arch/arm64/include/arch/header.ld
index 06d6c50..5be2a41 100644
--- a/src/arch/arm64/include/arch/header.ld
+++ b/src/arch/arm64/include/arch/header.ld
@@ -28,11 +28,7 @@ PHDRS
 	to_load PT_LOAD;
 }
 
-#if ENV_BOOTBLOCK
-TARGET(binary)
-#endif
-
-#if ENV_RMODULE
+#if ENV_BOOTBLOCK ||  ENV_RMODULE
 ENTRY(_start)
 #else
 ENTRY(stage_entry)
diff --git a/src/arch/arm64/include/arch/memlayout.h b/src/arch/arm64/include/arch/memlayout.h
index 64dde70..ff48788 100644
--- a/src/arch/arm64/include/arch/memlayout.h
+++ b/src/arch/arm64/include/arch/memlayout.h
@@ -31,13 +31,12 @@
 	_ = ASSERT(size % 4K == 0, \
 		"DMA buffer should be multiple of smallest page size (4K)!");
 
-/* ARM64 stacks need 16-byte alignment. The ramstage will set up its own stacks
- * in BSS, so this is only used for the SRAM stages. */
-#ifdef __PRE_RAM__
+/* ARM64 stacks need 16-byte alignment. */
+#if !IS_ENABLED(CONFIG_SMP)
 #define STACK(addr, size) \
 	REGION(stack, addr, size, 16) \
 	_ = ASSERT(size >= 2K, "stack should be >= 2K, see toolchain.inc");
-#else
+#else	/* Hack around old Tegra SMP implementation. TODO: remove */
 #define STACK(addr, size) REGION(preram_stack, addr, size, 16)
 #endif
 
diff --git a/src/arch/arm64/stages.c b/src/arch/arm64/stages.c
deleted file mode 100644
index ea146d7..0000000
--- a/src/arch/arm64/stages.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright 2014 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc.
- */
-
-/*
- * This file contains entry/exit functions for each stage during coreboot
- * execution (bootblock entry and ramstage exit will depend on external
- * loading).
- *
- * Entry points must be placed at the location the previous stage jumps
- * to (the lowest address in the stage image). This is done by giving
- * stage_entry() its own section in .text and placing it first in the
- * linker script.
- */
-
-#include <arch/stages.h>
-#include <arch/cache.h>
-
-/* we had marked 'doit' as 'noreturn'.
- * There is no apparent harm in leaving it as something we can return from, and in the one
- * case where we call a payload, the payload is allowed to return.
- * Hence, leave it as something we can return from.
- */
-void stage_exit(void *addr)
-{
-	void (*doit)(void) = addr;
-	/*
-	 * Most stages load code so we need to sync caches here. Should maybe
-	 * go into cbfs_load_stage() instead...
-	 */
-	cache_sync_instructions();
-	doit();
-}
diff --git a/src/soc/nvidia/tegra132/Kconfig b/src/soc/nvidia/tegra132/Kconfig
index 4be9a4c..8473d4a 100644
--- a/src/soc/nvidia/tegra132/Kconfig
+++ b/src/soc/nvidia/tegra132/Kconfig
@@ -17,6 +17,11 @@ config SOC_NVIDIA_TEGRA132
 
 if SOC_NVIDIA_TEGRA132
 
+# TODO: Remove after replacing arch/arm64/stage_entry.S
+config STACK_SIZE
+	hex
+	default 0x1000
+
 config MAINBOARD_DO_DSI_INIT
 	bool "Use dsi graphics interface"
 	depends on MAINBOARD_DO_NATIVE_VGA_INIT
diff --git a/src/soc/nvidia/tegra210/Kconfig b/src/soc/nvidia/tegra210/Kconfig
index e70cdc6..002a6d3 100644
--- a/src/soc/nvidia/tegra210/Kconfig
+++ b/src/soc/nvidia/tegra210/Kconfig
@@ -22,6 +22,11 @@ if SOC_NVIDIA_TEGRA210
 config CHROMEOS
 	select CHROMEOS_RAMOOPS_NON_ACPI
 
+# TODO: Remove after replacing arch/arm64/stage_entry.S
+config STACK_SIZE
+	hex
+	default 0x1000
+
 config MAINBOARD_DO_DSI_INIT
 	bool "Use dsi graphics interface"
 	depends on MAINBOARD_DO_NATIVE_VGA_INIT



More information about the coreboot-gerrit mailing list