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/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