Asami Doi has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/34774 )
Change subject: lib: Register exception handlers for ARMv8 ......................................................................
lib: 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.
Signed-off-by: Asami Doi d0iasm.pub@gmail.com Change-Id: I09a306ca307ba4027d9758c3debc2e7c844c66b8 --- M src/lib/ramdetect.c 1 file changed, 54 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/74/34774/1
diff --git a/src/lib/ramdetect.c b/src/lib/ramdetect.c index 5416a58..7f53b57 100644 --- a/src/lib/ramdetect.c +++ b/src/lib/ramdetect.c @@ -15,24 +15,62 @@ #include <symbols.h> #include <device/mmio.h> #include <ramdetect.h> +#include <arch/exception.h> #include <console/console.h>
#define OVERLAP(a, b, s, e) ((b) > (s) && (a) < (e))
+static enum { + ABORT_CHECKER_NOT_REGISTERED, + ABORT_CHECKER_DEACTIVATED, + ABORT_CHECKER_NOT_TRIGGERED, + ABORT_CHECKER_TRIGGERED, +} abort_state = ABORT_CHECKER_NOT_REGISTERED; + +static int abort_checker(struct exc_state *state, uint64_t vector_id) +{ + if (abort_state == ABORT_CHECKER_DEACTIVATED) + return EXC_RET_IGNORED; + + 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 void register_checker(void) +{ + struct exception_handler sync_elx; + struct exception_handler sync_el0; + + sync_elx.handler = &abort_checker; + sync_el0.handler = &abort_checker; + + exception_handler_register(EXC_VID_CUR_SP_ELX_SYNC, &sync_elx); + exception_handler_register(EXC_VID_CUR_SP_EL0_SYNC, &sync_el0); + + printk(BIOS_DEBUG, "ARM64: Abort checker handlers installed.\n"); +} + static int 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[] = { - 0x55aa55aa, - 0x12345678 - }; - void *ptr = (void *) addr; + static const uint32_t patterns[] = {0x55aa55aa, 0x12345678}; + void *ptr = (void *)addr; size_t i;
/* Don't accidentally clober oneself. */ - if (OVERLAP(addr, addr + sizeof(uint32_t), (uintptr_t)_program, (uintptr_t) _eprogram)) + if (OVERLAP(addr, addr + sizeof(uint32_t), (uintptr_t)_program, (uintptr_t)_eprogram)) return 1;
+ if (ENV_ARM64) { + read32((void *)addr); + return abort_state == ABORT_CHECKER_NOT_TRIGGERED; + } + uint32_t old = read32(ptr); for (i = 0; i < ARRAY_SIZE(patterns); i++) { write32(ptr, patterns[i]); @@ -50,6 +88,12 @@ /* Probe an area if it's read/writable. */ size_t probe_ramsize(const uintptr_t dram_start, const size_t probe_size) { + if (ENV_ARM64) { + if (abort_state == ABORT_CHECKER_NOT_REGISTERED) + register_checker(); + abort_state = ABORT_CHECKER_NOT_TRIGGERED; + } + ssize_t i; size_t msb = 0; size_t discovered = 0; @@ -74,5 +118,9 @@
saved_result = discovered; printk(BIOS_DEBUG, "RAMDETECT: Found %zu MiB RAM\n", discovered); + + if (ENV_ARM64) + abort_state = ABORT_CHECKER_DEACTIVATED; + return discovered; }