AArch64: Introduce External Abort handling
authorJeenu Viswambharan <jeenu.viswambharan@arm.com>
Thu, 30 Nov 2017 12:54:15 +0000 (12:54 +0000)
committerJeenu Viswambharan <jeenu.viswambharan@arm.com>
Fri, 4 May 2018 07:32:42 +0000 (08:32 +0100)
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>
Makefile
bl31/aarch64/runtime_exceptions.S
include/bl31/ea_handle.h [new file with mode: 0644]
include/lib/aarch64/arch.h
include/lib/el3_runtime/aarch64/context.h
include/plat/common/platform.h
make_helpers/defaults.mk
plat/common/aarch64/plat_common.c

index b270e1508247be31865a04fb19f1f18f60feece4..23b48e8f4be16cc2eb4a029273dec0e2a8416e77 100644 (file)
--- 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))
index e8cde5470144d305732b8b90b17ad6572db12201..494ccd79723b1352f8de2e44c5dd1a9f613d9268 100644 (file)
@@ -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>
        .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.
        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 (file)
index 0000000..285132b
--- /dev/null
@@ -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__ */
index ff3881e60fee5c15746d6cdc41cc240fefa61eb5..a44694126309bd5d7388b7130cc1363bb2d626bd 100644 (file)
@@ -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
  */
 #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) */
index 5f6bdc97af6a322a7d1407ba11139036dddd8a6d..cdd74a34c05cbc823b9795034e14560a568a942f 100644 (file)
@@ -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.
  ******************************************************************************/
 #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
index aa181c826b4142d9ef1b27cf48872739880a2c46..cd17a00f1dd31552ff6d2e1e52cf67fdb7596181 100644 (file)
@@ -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.
index 9e95cd5ac03426b00ab80f6fc57077c743f4d758..00ac12687b8a7c19d825bdfd041a406d628f52ec 100644 (file)
@@ -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
index 7a2f38cb0365441a13e7ac32d65de84e4599c509..c4531565bf5c716a95e0e5af4433a02b52d0b8a7 100644 (file)
@@ -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();
+}