From 5c0e72ff9952bef2dcb62881ced0d95f8ad9cf1d Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 10 Oct 2018 15:42:28 -0700 Subject: libpayload: arm64: Make exception handling closer to arm32 This patch reworks the arm64 exception handling to be more similar to how it works on arm32. This includes a bunch of features like actually saving and restoring more exception state in the exception_state structure and supporting the same sort of partial reentrancy that is useful for GDB. Since there's no instruction to directly load into or store out of SP on arm64, we can't do quite the same thing where we use that to read an exception_state_ptr variable right after exception entry when no other register is available. But we can do something very similar by (ab-)using the "high" stack pointer (SP_EL2) as a pointer to the exception_state struct and providing a function to change it. Change-Id: Ia16a1124be1824392a309ae1f4cb031547d184c1 Signed-off-by: Julius Werner Reviewed-on: https://review.coreboot.org/29018 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- payloads/libpayload/include/arm64/arch/exception.h | 90 +++++++++++++++++++++- 1 file changed, 86 insertions(+), 4 deletions(-) (limited to 'payloads/libpayload/include/arm64') diff --git a/payloads/libpayload/include/arm64/arch/exception.h b/payloads/libpayload/include/arm64/arch/exception.h index 8afe39103b..f699d3d6ed 100644 --- a/payloads/libpayload/include/arm64/arch/exception.h +++ b/payloads/libpayload/include/arm64/arch/exception.h @@ -30,18 +30,98 @@ #ifndef _ARCH_EXCEPTION_H #define _ARCH_EXCEPTION_H -#include +#define EXCEPTION_STATE_ELR 0x0 +#define EXCEPTION_STATE_ESR 0x8 +#define EXCEPTION_STATE_SPSR 0x10 +#define EXCEPTION_STATE_SP 0x18 +#define EXCEPTION_STATE_REG(r) (0x20 + r * 0x8) + +#define ESR_EC_UNKNOWN 0b000000 +#define ESR_EC_SVC_64 0b010101 +#define ESR_EC_INSN_ABT_LOWER 0b100000 +#define ESR_EC_INSN_ABT_SAME 0b100001 +#define ESR_EC_DATA_ABT_LOWER 0b100100 +#define ESR_EC_DATA_ABT_SAME 0b100101 +#define ESR_EC_SERROR 0b101111 +#define ESR_EC_SS_SAME 0b110011 +#define ESR_EC_BKPT_64 0b111100 + +#define MDCR_TDE (1 << 8) -void set_vbar(void* vbar); +#define MDSCR_SS (1 << 0) +#define MDSCR_KDE (1 << 13) +#define MDSCR_MDE (1 << 15) + +#ifndef __ASSEMBLER__ + +#include +#include struct exception_state { uint64_t elr; - uint64_t esr; + union { + uint64_t esr; + union { + struct { + uint64_t iss : 25; + uint64_t il : 1; + uint64_t ec : 6; + uint64_t _res0 : 32; + }; + struct { + uint64_t isfc : 6; + uint64_t _res0 : 1; + uint64_t s1ptw : 1; + uint64_t _res1 : 1; + uint64_t ea : 1; + uint64_t fnv : 1; + uint64_t _res2 : 53; + } insn_abt; + }; + }; + union { + uint32_t spsr; + struct { + uint32_t sp : 1; /* M[0] */ + uint32_t _res0 : 1; /* M[1] */ + uint32_t el : 2; /* M[3:2] */ + uint32_t arch : 1; /* M[4] */ + uint32_t _res1 : 1; + uint32_t f : 1; + uint32_t i : 1; + uint32_t a : 1; + uint32_t d : 1; + uint32_t _res2 : 10; + uint32_t il : 1; + uint32_t ss : 1; + uint32_t _res3 : 6; + uint32_t v : 1; + uint32_t c : 1; + uint32_t z : 1; + uint32_t n : 1; + } pstate; + }; + uint32_t spsr_high_unused; + uint64_t sp; uint64_t regs[31]; } __packed; -extern struct exception_state *exception_state; +#define CHECK_ES(field, constant) \ + _Static_assert(offsetof(struct exception_state, field) == constant, \ + "(struct exception_state)." #field " doesn't match constant " #constant) +CHECK_ES(elr, EXCEPTION_STATE_ELR); +CHECK_ES(esr, EXCEPTION_STATE_ESR); +CHECK_ES(spsr, EXCEPTION_STATE_SPSR); +CHECK_ES(sp, EXCEPTION_STATE_SP); +CHECK_ES(regs[0], EXCEPTION_STATE_REG(0)); +CHECK_ES(regs[30], EXCEPTION_STATE_REG(30)); + +extern struct exception_state exception_state; +extern u64 exception_stack[]; +extern u64 *exception_stack_end; + +void exception_set_state_ptr(struct exception_state *exception_state_ptr); enum { EXC_SYNC_SP0 = 0, @@ -63,4 +143,6 @@ enum { EXC_COUNT }; +#endif /* !__ASSEMBLER__ */ + #endif -- cgit v1.2.3