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 <jeenu.viswambharan@arm.com>
diff --git a/Makefile b/Makefile
index b270e15..23b48e8 100644
--- a/Makefile
+++ b/Makefile
@@ -517,6 +517,7 @@
$(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_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 e8cde54..494ccd7 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -8,6 +8,7 @@
#include <asm_macros.S>
#include <context.h>
#include <cpu_data.h>
+#include <ea_handle.h>
#include <interrupt_mgmt.h>
#include <platform_def.h>
#include <runtime_svc.h>
@@ -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 @@
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 @@
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 @@
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 0000000..285132b
--- /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 ff3881e..a446941 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 5f6bdc9..cdd74a3 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 <utils_def.h>
+
/*******************************************************************************
* 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 aa181c8..cd17a00 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -124,6 +124,9 @@
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 9e95cd5..00ac126 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -92,6 +92,10 @@
# 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 7a2f38c..c453156 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 @@
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();
+}