diff options
author | Julius Werner <jwerner@chromium.org> | 2018-10-10 15:42:28 -0700 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2018-10-12 20:17:28 +0000 |
commit | 5c0e72ff9952bef2dcb62881ced0d95f8ad9cf1d (patch) | |
tree | e297683091fcbea2b785c289e3f3af95bef5238f /payloads/libpayload/include | |
parent | ca52a258822c1c47d533684c5a4cbe5f2b7bd487 (diff) |
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 <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/29018
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'payloads/libpayload/include')
-rw-r--r-- | payloads/libpayload/include/arm64/arch/exception.h | 90 |
1 files changed, 86 insertions, 4 deletions
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 <stdint.h> +#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 <stddef.h> +#include <stdint.h> 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 |