From 76454abf4a2a5df482a753fc435b2de0219659bf Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Thu, 30 Nov 2017 12:54:15 +0000 Subject: [PATCH] AArch64: Introduce External Abort handling At present, any External Abort routed to EL3 is reported as an unhandled exception and cause a panic. This patch enables ARM Trusted Firmware to handle External Aborts routed to EL3. With this patch, when an External Abort is received at EL3, its handling is delegated to plat_ea_handler() function. Platforms can provide their own implementation of this function. This patch adds a weak definition of the said function that prints out a message and just panics. In order to support handling External Aborts at EL3, the build option HANDLE_EA_EL3_FIRST must be set to 1. Before this patch, HANDLE_EA_EL3_FIRST wasn't passed down to compilation; this patch fixes that too. Change-Id: I4d07b7e65eb191ff72d63b909ae9512478cd01a1 Signed-off-by: Jeenu Viswambharan --- Makefile | 2 + bl31/aarch64/runtime_exceptions.S | 113 ++++++++++++++++++++-- include/bl31/ea_handle.h | 18 ++++ include/lib/aarch64/arch.h | 8 +- include/lib/el3_runtime/aarch64/context.h | 12 ++- include/plat/common/platform.h | 3 + make_helpers/defaults.mk | 4 + plat/common/aarch64/plat_common.c | 12 +++ 8 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 include/bl31/ea_handle.h 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(); +}