diff --git a/Makefile b/Makefile index b270e1508..23b48e8f4 100644 --- a/Makefile +++ b/Makefile @@ -517,6 +517,7 @@ $(eval $(call assert_boolean,ENABLE_SVE_FOR_NS)) $(eval $(call assert_boolean,ERROR_DEPRECATED)) $(eval $(call assert_boolean,GENERATE_COT)) $(eval $(call assert_boolean,GICV2_G0_FOR_EL3)) +$(eval $(call assert_boolean,HANDLE_EA_EL3_FIRST)) $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY)) $(eval $(call assert_boolean,LOAD_IMAGE_V2)) $(eval $(call assert_boolean,MULTI_CONSOLE_API)) @@ -563,6 +564,7 @@ $(eval $(call add_define,ENABLE_SPM)) $(eval $(call add_define,ENABLE_SVE_FOR_NS)) $(eval $(call add_define,ERROR_DEPRECATED)) $(eval $(call add_define,GICV2_G0_FOR_EL3)) +$(eval $(call add_define,HANDLE_EA_EL3_FIRST)) $(eval $(call add_define,HW_ASSISTED_COHERENCY)) $(eval $(call add_define,LOAD_IMAGE_V2)) $(eval $(call add_define,LOG_LEVEL)) diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S index e8cde5470..494ccd797 100644 --- a/bl31/aarch64/runtime_exceptions.S +++ b/bl31/aarch64/runtime_exceptions.S @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,27 @@ .globl fiq_aarch32 .globl serror_aarch32 + /* + * Handle External Abort by delegating to the platform's EA handler. + * Once the platform handler returns, the macro exits EL3 and returns to + * where the abort was taken from. + * + * This macro assumes that x30 is available for use. + * + * 'abort_type' is a constant passed to the platform handler, indicating + * the cause of the External Abort. + */ + .macro handle_ea abort_type + /* Save GP registers */ + bl save_gp_registers + + /* Setup exception class and syndrome arguments for platform handler */ + mov x0, \abort_type + mrs x1, esr_el3 + adr x30, el3_exit + b delegate_ea + .endm + /* --------------------------------------------------------------------- * This macro handles Synchronous exceptions. * Only SMC exceptions are supported. @@ -69,6 +91,20 @@ cmp x30, #EC_AARCH64_SMC b.eq smc_handler64 + /* Check for I/D aborts from lower EL */ + cmp x30, #EC_IABORT_LOWER_EL + b.eq 1f + + cmp x30, #EC_DABORT_LOWER_EL + b.ne 2f + +1: + /* Test for EA bit in the instruction syndrome */ + mrs x30, esr_el3 + tbz x30, #ESR_ISS_EABORT_EA_BIT, 2f + handle_ea #ERROR_EA_SYNC + +2: /* Other kinds of synchronous exceptions are not handled */ ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] b report_unhandled_exception @@ -232,11 +268,14 @@ vector_entry fiq_aarch64 check_vector_size fiq_aarch64 vector_entry serror_aarch64 + msr daifclr, #DAIF_ABT_BIT + /* - * SError exceptions from lower ELs are not currently supported. - * Report their occurrence. + * Explicitly save x30 so as to free up a register and to enable + * branching */ - b report_unhandled_exception + str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] + handle_ea #ERROR_EA_ASYNC check_vector_size serror_aarch64 /* --------------------------------------------------------------------- @@ -262,11 +301,14 @@ vector_entry fiq_aarch32 check_vector_size fiq_aarch32 vector_entry serror_aarch32 + msr daifclr, #DAIF_ABT_BIT + /* - * SError exceptions from lower ELs are not currently supported. - * Report their occurrence. + * Explicitly save x30 so as to free up a register and to enable + * branching */ - b report_unhandled_exception + str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] + handle_ea #ERROR_EA_ASYNC check_vector_size serror_aarch32 @@ -443,3 +485,62 @@ rt_svc_fw_critical_error: msr spsel, #1 no_ret report_unhandled_exception endfunc smc_handler + +/* + * Delegate External Abort handling to platform's EA handler. This function + * assumes that all GP registers have been saved by the caller. + * + * x0: EA reason + * x1: EA syndrome + */ +func delegate_ea + /* Save EL3 state */ + mrs x2, spsr_el3 + mrs x3, elr_el3 + stp x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] + + /* + * Save ESR as handling might involve lower ELs, and returning back to + * EL3 from there would trample the original ESR. + */ + mrs x4, scr_el3 + mrs x5, esr_el3 + stp x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] + + /* + * Setup rest of arguments, and call platform External Abort handler. + * + * x0: EA reason (already in place) + * x1: Exception syndrome (already in place). + * x2: Cookie (unused for now). + * x3: Context pointer. + * x4: Flags (security state from SCR for now). + */ + mov x2, xzr + mov x3, sp + ubfx x4, x4, #0, #1 + + /* Switch to runtime stack */ + ldr x5, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] + msr spsel, #0 + mov sp, x5 + + mov x29, x30 + bl plat_ea_handler + mov x30, x29 + + /* Make SP point to context */ + msr spsel, #1 + + /* Restore EL3 state */ + ldp x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] + msr spsr_el3, x1 + msr elr_el3, x2 + + /* Restore ESR_EL3 and SCR_EL3 */ + ldp x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] + msr scr_el3, x3 + msr esr_el3, x4 + + ret +endfunc delegate_ea diff --git a/include/bl31/ea_handle.h b/include/bl31/ea_handle.h new file mode 100644 index 000000000..285132b7e --- /dev/null +++ b/include/bl31/ea_handle.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __EA_HANDLE_H__ +#define __EA_HANDLE_H__ + +/* Constants indicating the reason for an External Abort */ + +/* External Abort received at SError vector */ +#define ERROR_EA_ASYNC 0 + +/* Synchronous External Abort received at Synchronous exception vector */ +#define ERROR_EA_SYNC 1 + +#endif /* __EA_HANDLE_H__ */ diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index ff3881e60..a44694126 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -528,6 +528,12 @@ #define EC_AARCH64_FP U(0x2c) #define EC_SERROR U(0x2f) +/* + * External Abort bit in Instruction and Data Aborts synchronous exception + * syndromes. + */ +#define ESR_ISS_EABORT_EA_BIT U(9) + #define EC_BITS(x) (((x) >> ESR_EC_SHIFT) & ESR_EC_MASK) /* Reset bit inside the Reset management register for EL3 (RMR_EL3) */ diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h index 5f6bdc97a..cdd74a34c 100644 --- a/include/lib/el3_runtime/aarch64/context.h +++ b/include/lib/el3_runtime/aarch64/context.h @@ -7,6 +7,8 @@ #ifndef __CONTEXT_H__ #define __CONTEXT_H__ +#include + /******************************************************************************* * Constants that allow assembler code to access members of and the 'gp_regs' * structure at their correct offsets. @@ -53,10 +55,12 @@ ******************************************************************************/ #define CTX_EL3STATE_OFFSET (CTX_GPREGS_OFFSET + CTX_GPREGS_END) #define CTX_SCR_EL3 U(0x0) -#define CTX_RUNTIME_SP U(0x8) -#define CTX_SPSR_EL3 U(0x10) -#define CTX_ELR_EL3 U(0x18) -#define CTX_EL3STATE_END U(0x20) +#define CTX_ESR_EL3 U(0x8) +#define CTX_RUNTIME_SP U(0x10) +#define CTX_SPSR_EL3 U(0x18) +#define CTX_ELR_EL3 U(0x20) +#define CTX_UNUSED U(0x28) +#define CTX_EL3STATE_END U(0x30) /******************************************************************************* * Constants that allow assembler code to access members of and the diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h index aa181c826..cd17a00f1 100644 --- a/include/plat/common/platform.h +++ b/include/plat/common/platform.h @@ -124,6 +124,9 @@ int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode); void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr); #endif +void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, + void *handle, uint64_t flags); + /* * The following function is mandatory when the * firmware update feature is used. diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 9e95cd5ac..00ac12687 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -92,6 +92,10 @@ GENERATE_COT := 0 # default, they are for Secure EL1. GICV2_G0_FOR_EL3 := 0 +# Route External Aborts to EL3. Disabled by default; External Aborts are handled +# by lower ELs. +HANDLE_EA_EL3_FIRST := 0 + # Whether system coherency is managed in hardware, without explicit software # operations. HW_ASSISTED_COHERENCY := 0 diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c index 7a2f38cb0..c4531565b 100644 --- a/plat/common/aarch64/plat_common.c +++ b/plat/common/aarch64/plat_common.c @@ -28,6 +28,8 @@ #pragma weak plat_sdei_validate_entry_point #endif +#pragma weak plat_ea_handler + void bl31_plat_enable_mmu(uint32_t flags) { enable_mmu_el3(flags); @@ -105,3 +107,13 @@ int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode) return 0; } #endif + +/* RAS functions common to AArch64 ARM platforms */ +void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, + void *handle, uint64_t flags) +{ + ERROR("Unhandled External Abort received on 0x%lx at EL3!\n", + read_mpidr_el1()); + ERROR(" exception reason=%u syndrome=0x%lx\n", ea_reason, syndrome); + panic(); +}