From 06993ee7295c81f71462616277624fbf8ebc8ec9 Mon Sep 17 00:00:00 2001 From: Asami Doi Date: Wed, 7 Aug 2019 13:40:53 +0900 Subject: [PATCH] lib: ramdetect: Register exception handlers for ARMv8 Register exception handlers to avoid a Synchronous External Abort that is raised when you try to access a non-memory address on ARMv8. An exception handler can jump over the faulting instruction. This is the feature only for QEMU/AArch64. Signed-off-by: Asami Doi Change-Id: I09a306ca307ba4027d9758c3debc2e7c844c66b8 Reviewed-on: https://review.coreboot.org/c/coreboot/+/34774 Tested-by: build bot (Jenkins) Reviewed-by: Raul Rangel --- src/arch/arm64/Makefile.inc | 2 ++ src/arch/arm64/ramdetect.c | 41 +++++++++++++++++++++++++++++++++++++ src/include/ramdetect.h | 6 ++++++ src/lib/ramdetect.c | 2 +- 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/arch/arm64/ramdetect.c diff --git a/src/arch/arm64/Makefile.inc b/src/arch/arm64/Makefile.inc index 6bb7196805..89cc8780a6 100644 --- a/src/arch/arm64/Makefile.inc +++ b/src/arch/arm64/Makefile.inc @@ -107,6 +107,7 @@ romstage-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c romstage-y += memset.S romstage-y += memcpy.S romstage-y += memmove.S +romstage-y += ramdetect.c romstage-y += romstage.c romstage-y += transition.c transition_asm.S @@ -131,6 +132,7 @@ ramstage-y += div0.c ramstage-y += eabi_compat.c ramstage-y += boot.c ramstage-y += tables.c +ramstage-y += ramdetect.c ramstage-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c ramstage-y += memset.S ramstage-y += memcpy.S diff --git a/src/arch/arm64/ramdetect.c b/src/arch/arm64/ramdetect.c new file mode 100644 index 0000000000..bc034c311b --- /dev/null +++ b/src/arch/arm64/ramdetect.c @@ -0,0 +1,41 @@ +/* + * This file is part of the coreboot project. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include +#include +#include +#include + +static enum { + ABORT_CHECKER_NOT_TRIGGERED, + ABORT_CHECKER_TRIGGERED, +} abort_state = ABORT_CHECKER_NOT_TRIGGERED; + +static int abort_checker(struct exc_state *state, uint64_t vector_id) +{ + if (raw_read_esr_el3() >> 26 != 0x25) + return EXC_RET_IGNORED; /* Not a data abort. */ + + abort_state = ABORT_CHECKER_TRIGGERED; + state->elx.elr += sizeof(uint32_t); /* Jump over faulting instruction. */ + raw_write_elr_el3(state->elx.elr); + return EXC_RET_HANDLED; +} + +static struct exception_handler sync_el0 = {.handler = &abort_checker}; + +int probe_mb(const uintptr_t dram_start, const uintptr_t size) +{ + uintptr_t addr = dram_start + (size * MiB) - sizeof(uint32_t); + void *ptr = (void *)addr; + + abort_state = ABORT_CHECKER_NOT_TRIGGERED; + exception_handler_register(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0); + read32(ptr); + exception_handler_unregister(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0); + return abort_state == ABORT_CHECKER_NOT_TRIGGERED; +} diff --git a/src/include/ramdetect.h b/src/include/ramdetect.h index b63cdf14cf..e2a7eced67 100644 --- a/src/include/ramdetect.h +++ b/src/include/ramdetect.h @@ -11,6 +11,12 @@ * GNU General Public License for more details. */ + +/* + * Used in probe_ramsize(). This is a weak function and it's overridden for + * ARMv8. Return 1 when DRAM exists at the address, otherwise return 0. + */ +int probe_mb(const uintptr_t dram_start, const uintptr_t size); /* * Probe an area if it's read/writable. * Primary use case is the detection of DRAM amount on emulators. diff --git a/src/lib/ramdetect.c b/src/lib/ramdetect.c index 5416a580dd..2c83092ebc 100644 --- a/src/lib/ramdetect.c +++ b/src/lib/ramdetect.c @@ -19,7 +19,7 @@ #define OVERLAP(a, b, s, e) ((b) > (s) && (a) < (e)) -static int probe_mb(const uintptr_t dram_start, const uintptr_t size) +int __weak probe_mb(const uintptr_t dram_start, const uintptr_t size) { uintptr_t addr = dram_start + (size * MiB) - sizeof(uint32_t); static const uint32_t patterns[] = {