Merge changes from topic "mp/exceptions" into integration

* changes:
  docs(ras): update RAS documentation
  docs(el3-runtime): update BL31 exception vector handling
  fix(el3-runtime): restrict lower el EA handlers in FFH mode
  fix(ras): remove RAS_FFH_SUPPORT and introduce FFH_SUPPORT
  fix(ras): restrict ENABLE_FEAT_RAS to have only two states
  feat(ras): use FEAT_IESB for error synchronization
  feat(el3-runtime): modify vector entry paths
diff --git a/Makefile b/Makefile
index 7f781a0..da9eb9f 100644
--- a/Makefile
+++ b/Makefile
@@ -809,6 +809,14 @@
 	BL2_RUNS_AT_EL3	:=	0
 endif
 
+# This internal flag is set to 1 when Firmware First handling of External aborts
+# is required by lowe ELs. Currently only NS requires this support.
+ifeq ($(HANDLE_EA_EL3_FIRST_NS),1)
+	FFH_SUPPORT := 1
+else
+	FFH_SUPPORT := 0
+endif
+
 $(eval $(call MAKE_PREREQ_DIR,${BUILD_PLAT}))
 
 ifeq (${ARM_ARCH_MAJOR},7)
@@ -970,18 +978,9 @@
 # RAS_EXTENSION is deprecated, provide alternate build options
 ifeq ($(RAS_EXTENSION),1)
         $(error "RAS_EXTENSION is now deprecated, please use ENABLE_FEAT_RAS \
-        and RAS_FFH_SUPPORT instead")
+        and HANDLE_EA_EL3_FIRST_NS instead")
 endif
 
-# RAS firmware first handling requires that EAs are handled in EL3 first
-ifeq ($(RAS_FFH_SUPPORT),1)
-	ifneq ($(ENABLE_FEAT_RAS),1)
-                $(error For RAS_FFH_SUPPORT, ENABLE_FEAT_RAS must also be 1)
-	endif
-	ifneq ($(HANDLE_EA_EL3_FIRST_NS),1)
-                $(error For RAS_FFH_SUPPORT, HANDLE_EA_EL3_FIRST_NS must also be 1)
-	endif
-endif #(RAS_FFH_SUPPORT)
 
 # When FAULT_INJECTION_SUPPORT is used, require that FEAT_RAS is enabled
 ifeq ($(FAULT_INJECTION_SUPPORT),1)
@@ -1283,6 +1282,8 @@
 	ENABLE_RUNTIME_INSTRUMENTATION \
 	ENABLE_SME_FOR_SWD \
 	ENABLE_SVE_FOR_SWD \
+	ENABLE_FEAT_RAS	\
+	FFH_SUPPORT	\
 	ERROR_DEPRECATED \
 	FAULT_INJECTION_SUPPORT \
 	GENERATE_COT \
@@ -1337,7 +1338,6 @@
 	ERRATA_ABI_SUPPORT \
 	ERRATA_NON_ARM_INTERCONNECT \
 	CONDITIONAL_CMO \
-	RAS_FFH_SUPPORT \
 	PSA_CRYPTO	\
 	ENABLE_CONSOLE_GETC \
 )))
@@ -1360,7 +1360,6 @@
 	ENABLE_FEAT_AMU \
 	ENABLE_FEAT_AMUv1p1 \
 	ENABLE_FEAT_CSV2_2 \
-	ENABLE_FEAT_RAS	\
 	ENABLE_FEAT_DIT \
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_FGT \
@@ -1443,6 +1442,8 @@
 	ENABLE_SPE_FOR_NS \
 	ENABLE_SVE_FOR_NS \
 	ENABLE_SVE_FOR_SWD \
+	ENABLE_FEAT_RAS \
+	FFH_SUPPORT \
 	ENCRYPT_BL31 \
 	ENCRYPT_BL32 \
 	ERROR_DEPRECATED \
@@ -1460,8 +1461,6 @@
 	PROGRAMMABLE_RESET_ADDRESS \
 	PSCI_EXTENDED_STATE_ID \
 	PSCI_OS_INIT_MODE \
-	ENABLE_FEAT_RAS \
-	RAS_FFH_SUPPORT \
 	RESET_TO_BL31 \
 	SEPARATE_CODE_AND_RODATA \
 	SEPARATE_BL2_NOLOAD_REGION \
diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S
index dd6b4dc..28d2187 100644
--- a/bl31/aarch64/ea_delegate.S
+++ b/bl31/aarch64/ea_delegate.S
@@ -15,31 +15,11 @@
 #include <cpu_macros.S>
 #include <context.h>
 
-	.globl	handle_lower_el_ea_esb
 	.globl	handle_lower_el_sync_ea
 	.globl	handle_lower_el_async_ea
-
-
-/*
- * Function to delegate External Aborts synchronized by ESB instruction at EL3
- * vector entry. This function assumes GP registers x0-x29 have been saved, and
- * are available for use. It delegates the handling of the EA to platform
- * handler, and returns only upon successfully handling the EA; otherwise
- * panics. On return from this function, the original exception handler is
- * expected to resume.
- */
-func handle_lower_el_ea_esb
-	mov	x0, #ERROR_EA_ESB
-	mrs	x1, DISR_EL1
-	b	ea_proceed
-endfunc handle_lower_el_ea_esb
-
-
+	.globl	handle_pending_async_ea
 /*
- * This function forms the tail end of Synchronous Exception entry from lower
- * EL, and expects to handle Synchronous External Aborts from lower EL and CPU
- * Implementation Defined Exceptions. If any other kind of exception is detected,
- * then this function reports unhandled exception.
+ * This function handles Synchronous External Aborts from lower EL.
  *
  * It delegates the handling of the EA to platform handler, and upon successfully
  * handling the EA, exits EL3; otherwise panics.
@@ -57,27 +37,8 @@
 	cmp	x30, #EC_DABORT_LOWER_EL
 	b.eq	1f
 
-	/* Save GP registers */
-	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
-	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
-	stp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
-
-	/* Get the cpu_ops pointer */
-	bl	get_cpu_ops_ptr
-
-	/* Get the cpu_ops exception handler */
-	ldr	x0, [x0, #CPU_E_HANDLER_FUNC]
-
-	/*
-	 * If the reserved function pointer is NULL, this CPU does not have an
-	 * implementation defined exception handler function
-	 */
-	cbz	x0, 2f
-	mrs	x1, esr_el3
-	ubfx	x1, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH
-	blr	x0
-	b	2f
-
+	/* EA other than above are unhandled exceptions */
+	no_ret	report_unhandled_exception
 1:
 	/*
 	 * Save general purpose and ARMv8.3-PAuth registers (if enabled).
@@ -98,14 +59,6 @@
 	/* el3_exit assumes SP_EL0 on entry */
 	msr	spsel, #MODE_SP_EL0
 	b	el3_exit
-2:
-	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
-	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
-	ldp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
-
-	/* Synchronous exceptions other than the above are assumed to be EA */
-	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
-	no_ret	report_unhandled_exception
 endfunc handle_lower_el_sync_ea
 
 
@@ -140,6 +93,73 @@
 	b	el3_exit
 endfunc handle_lower_el_async_ea
 
+/*
+ * Handler for async EA from lower EL synchronized at EL3 entry in FFH mode.
+ *
+ * This scenario may arise when there is an error (EA) in the system which is not
+ * yet signaled to PE while executing in lower EL. During entry into EL3, the errors
+ * are synchronized either implicitly or explicitly causing async EA to pend at EL3.
+ *
+ * On detecting the pending EA (via ISR_EL1.A), if the EA routing model is Firmware
+ * First handling (FFH, SCR_EL3.EA = 1) this handler first handles the pending EA
+ * and then handles the original exception.
+ *
+ * This function assumes x30 has been saved.
+ */
+func handle_pending_async_ea
+	/*
+	 * Prepare for nested handling of EA. Stash sysregs clobbered by nested
+	 * exception and handler
+	 */
+	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_GPREG_LR]
+	mrs	x30, esr_el3
+	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ESR_EL3]
+	mrs	x30, spsr_el3
+	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_SPSR_EL3]
+	mrs	x30, elr_el3
+	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ELR_EL3]
+
+	mov	x30, #1
+	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	/*
+	 * Restore the original x30 saved as part of entering EL3. This is not
+	 * required for the current function but for EL3 SError vector entry
+	 * once PSTATE.A bit is unmasked. We restore x30 and then the same
+	 * value is stored in EL3 SError vector entry.
+	 */
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/*
+	 * After clearing PSTATE.A bit pending SError will trigger at current EL.
+	 * Put explicit synchronization event to ensure newly unmasked interrupt
+	 * is taken immediately.
+	 */
+	unmask_async_ea
+
+	/* Restore the original exception information along with zeroing the storage */
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ELR_EL3]
+	msr	elr_el3, x30
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ELR_EL3]
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_SPSR_EL3]
+	msr	spsr_el3, x30
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_SPSR_EL3]
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ESR_EL3]
+	msr	esr_el3, x30
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ESR_EL3]
+
+	/*
+	 * If the original exception corresponds to SError from lower El, eret back
+	 * to lower EL, otherwise return to vector table for original exception handling.
+	 */
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	cmp	x30, #EC_SERROR
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_GPREG_LR]
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_GPREG_LR]
+	b.eq	1f
+	ret
+1:
+	exception_return
+endfunc handle_pending_async_ea
 
 /*
  * Prelude for Synchronous External Abort handling. This function assumes that
@@ -149,7 +169,7 @@
  * x1: EA syndrome
  */
 func delegate_sync_ea
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	/*
 	 * Check for Uncontainable error type. If so, route to the platform
 	 * fatal error handler rather than the generic EA one.
@@ -179,7 +199,7 @@
  * x1: EA syndrome
  */
 func delegate_async_ea
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	/* Check Exception Class to ensure SError, as this function should
 	 * only be invoked for SError. If that is not the case, which implies
 	 * either an HW error or programming error, panic.
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index 8298696..ed48311 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -13,6 +13,7 @@
 #include <bl31/sync_handle.h>
 #include <common/runtime_svc.h>
 #include <context.h>
+#include <cpu_macros.S>
 #include <el3_common_macros.S>
 #include <lib/el3_runtime/cpu_data.h>
 #include <lib/smccc.h>
@@ -47,72 +48,30 @@
 	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
 	.endm
 
-	/*
-	 * Macro that prepares entry to EL3 upon taking an exception.
-	 *
-	 * With RAS_FFH_SUPPORT, this macro synchronizes pending errors with an
-	 * ESB instruction. When an error is thus synchronized, the handling is
-	 * delegated to platform EA handler.
-	 *
-	 * Without RAS_FFH_SUPPORT, this macro synchronizes pending errors using
-	 * a DSB, unmasks Asynchronous External Aborts and saves X30 before
-	 * setting the flag CTX_IS_IN_EL3.
-	 */
-	.macro check_and_unmask_ea
-#if RAS_FFH_SUPPORT
-	/* Synchronize pending External Aborts */
-	esb
-
-	/* Unmask the SError interrupt */
-	msr	daifclr, #DAIF_ABT_BIT
-
-	/* Check for SErrors synchronized by the ESB instruction */
-	mrs	x30, DISR_EL1
-	tbz	x30, #DISR_A_BIT, 1f
-
-	/*
-	 * Save general purpose and ARMv8.3-PAuth registers (if enabled).
-	 * Also save PMCR_EL0 and  set the PSTATE to a known state.
-	 */
-	bl	prepare_el3_entry
-
-	bl	handle_lower_el_ea_esb
-
-	/* Restore general purpose, PMCR_EL0 and ARMv8.3-PAuth registers */
-	bl	restore_gp_pmcr_pauth_regs
-1:
-#else
-	/*
-	 * Note 1: The explicit DSB at the entry of various exception vectors
-	 * for handling exceptions from lower ELs can inadvertently trigger an
-	 * SError exception in EL3 due to pending asynchronous aborts in lower
-	 * ELs. This will end up being handled by serror_sp_elx which will
-	 * ultimately panic and die.
-	 * The way to workaround is to update a flag to indicate if the exception
-	 * truly came from EL3. This flag is allocated in the cpu_context
-	 * structure and located at offset "CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3"
-	 * This is not a bullet proof solution to the problem at hand because
-	 * we assume the instructions following "isb" that help to update the
-	 * flag execute without causing further exceptions.
-	 */
+	.macro restore_x30
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	.endm
 
 	/*
-	 * For SoCs which do not implement RAS, use DSB as a barrier to
-	 * synchronize pending external aborts.
+	 * Macro that synchronizes errors (EA) and checks for pending SError.
+	 * On detecting a pending SError it either reflects it back to lower
+	 * EL (KFH) or handles it in EL3 (FFH) based on EA routing model.
 	 */
-	dsb	sy
-
-	/* Unmask the SError interrupt */
-	msr	daifclr, #DAIF_ABT_BIT
-
-	/* Use ISB for the above unmask operation to take effect immediately */
-	isb
-
-	/* Refer Note 1. */
-	mov 	x30, #1
-	str	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
-	dmb	sy
+	.macro	sync_and_handle_pending_serror
+	synchronize_errors
+	mrs	x30, ISR_EL1
+	tbz	x30, #ISR_A_SHIFT, 2f
+#if FFH_SUPPORT
+	mrs	x30, scr_el3
+	tst	x30, #SCR_EA_BIT
+	b.eq	1f
+	bl	handle_pending_async_ea
+	b	2f
 #endif
+1:
+	/* This function never returns, but need LR for decision making */
+	bl	reflect_pending_async_ea_to_lower_el
+2:
 	.endm
 
 	/* ---------------------------------------------------------------------
@@ -147,9 +106,19 @@
 	cmp	x30, #EC_AARCH64_SYS
 	b.eq	sync_handler64
 
-	/* Synchronous exceptions other than the above are assumed to be EA */
-	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	cmp	x30, #EC_IMP_DEF_EL3
+	b.eq	imp_def_el3_handler
+
+	/* If FFH Support then try to handle lower EL EA exceptions. */
+#if FFH_SUPPORT
+	mrs	x30, scr_el3
+	tst	x30, #SCR_EA_BIT
+	b.eq	1f
 	b	handle_lower_el_sync_ea
+#endif
+1:
+	/* Synchronous exceptions other than the above are unhandled */
+	b	report_unhandled_exception
 	.endm
 
 vector_base runtime_exceptions
@@ -217,22 +186,33 @@
 end_vector_entry fiq_sp_elx
 
 vector_entry serror_sp_elx
-#if !RAS_FFH_SUPPORT
+#if FFH_SUPPORT
 	/*
 	 * This will trigger if the exception was taken due to SError in EL3 or
 	 * because of pending asynchronous external aborts from lower EL that got
-	 * triggered due to explicit synchronization in EL3. Refer Note 1.
+	 * triggered due to implicit/explicit synchronization in EL3 (SCR_EL3.EA=1)
+	 * during EL3 entry. For the former case we continue with "plat_handle_el3_ea".
+	 * The later case will occur when PSTATE.A bit is cleared in
+	 * "handle_pending_async_ea". This means we are doing a nested
+	 * exception in EL3. Call the handler for async EA which will eret back to
+	 * original el3 handler if it is nested exception. Also, unmask EA so that we
+	 * catch any further EA arise when handling this nested exception at EL3.
 	 */
-	/* Assumes SP_EL3 on entry */
 	save_x30
-	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
-	cbnz	x30, 1f
-
-	/* Handle asynchronous external abort from lower EL */
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	cbz	x30, 1f
+	/*
+	 * This is nested exception handling, clear the flag to avoid taking this
+	 * path for further exceptions caused by EA handling
+	 */
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	unmask_async_ea
 	b	handle_lower_el_async_ea
 1:
+	restore_x30
 #endif
 	no_ret	plat_handle_el3_ea
+
 end_vector_entry serror_sp_elx
 
 	/* ---------------------------------------------------------------------
@@ -248,34 +228,41 @@
 	 */
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	handle_sync_exception
 end_vector_entry sync_exception_aarch64
 
 vector_entry irq_aarch64
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	b	handle_interrupt_exception
 end_vector_entry irq_aarch64
 
 vector_entry fiq_aarch64
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	b 	handle_interrupt_exception
 end_vector_entry fiq_aarch64
 
+	/*
+	 * Need to synchronize any outstanding SError since we can get a burst of errors.
+	 * So reuse the sync mechanism to catch any further errors which are pending.
+	 */
 vector_entry serror_aarch64
+#if FFH_SUPPORT
 	save_x30
 	apply_at_speculative_wa
-#if RAS_FFH_SUPPORT
-	msr	daifclr, #DAIF_ABT_BIT
+	sync_and_handle_pending_serror
+	unmask_async_ea
+	b	handle_lower_el_async_ea
 #else
-	check_and_unmask_ea
+	b	report_unhandled_exception
 #endif
-	b	handle_lower_el_async_ea
-
 end_vector_entry serror_aarch64
 
 	/* ---------------------------------------------------------------------
@@ -291,34 +278,41 @@
 	 */
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	handle_sync_exception
 end_vector_entry sync_exception_aarch32
 
 vector_entry irq_aarch32
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	b	handle_interrupt_exception
 end_vector_entry irq_aarch32
 
 vector_entry fiq_aarch32
 	save_x30
 	apply_at_speculative_wa
-	check_and_unmask_ea
+	sync_and_handle_pending_serror
+	unmask_async_ea
 	b	handle_interrupt_exception
 end_vector_entry fiq_aarch32
 
+	/*
+	 * Need to synchronize any outstanding SError since we can get a burst of errors.
+	 * So reuse the sync mechanism to catch any further errors which are pending.
+	 */
 vector_entry serror_aarch32
+#if FFH_SUPPORT
 	save_x30
 	apply_at_speculative_wa
-#if RAS_FFH_SUPPORT
-	msr	daifclr, #DAIF_ABT_BIT
+	sync_and_handle_pending_serror
+	unmask_async_ea
+	b	handle_lower_el_async_ea
 #else
-	check_and_unmask_ea
+	b	report_unhandled_exception
 #endif
-	b	handle_lower_el_async_ea
-
 end_vector_entry serror_aarch32
 
 #ifdef MONITOR_TRAPS
@@ -608,6 +602,114 @@
 	b	el3_exit
 endfunc handle_interrupt_exception
 
+func imp_def_el3_handler
+	/* Save GP registers */
+	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	stp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+
+	/* Get the cpu_ops pointer */
+	bl	get_cpu_ops_ptr
+
+	/* Get the cpu_ops exception handler */
+	ldr	x0, [x0, #CPU_E_HANDLER_FUNC]
+
+	/*
+	 * If the reserved function pointer is NULL, this CPU does not have an
+	 * implementation defined exception handler function
+	 */
+	cbz	x0, el3_handler_exit
+	mrs	x1, esr_el3
+	ubfx	x1, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	blr	x0
+el3_handler_exit:
+	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	ldp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+	restore_x30
+	no_ret	report_unhandled_exception
+endfunc imp_def_el3_handler
+
+/*
+ * Handler for async EA from lower EL synchronized at EL3 entry in KFH mode.
+ *
+ * This scenario may arise when there is an error (EA) in the system which is not
+ * yet signaled to PE while executing in lower EL. During entry into EL3, the errors
+ * are synchronized either implicitly or explicitly causing async EA to pend at EL3.
+ *
+ * On detecting the pending EA (via ISR_EL1.A) and if the EA routing model is
+ * KFH (SCR_EL3.EA = 1) this handler reflects ther error back to lower EL.
+ *
+ * This function assumes x30 has been saved.
+ */
+func reflect_pending_async_ea_to_lower_el
+	/*
+	 * As the original exception was not handled we need to ensure that we return
+	 * back to the instruction which caused the exception. To acheive that, eret
+	 * to "elr-4" (Label "subtract_elr_el3") for SMC or simply eret otherwise
+	 * (Label "skip_smc_check").
+	 *
+	 * LIMITATION: It could be that async EA is masked at the target exception level
+	 * or the priority of async EA wrt to the EL3/secure interrupt is lower, which
+	 * causes back and forth between lower EL and EL3. In case of back and forth between
+	 * lower EL and EL3, we can track the loop count in "CTX_NESTED_EA_FLAG" and leverage
+	 * previous ELR in "CTX_SAVED_ELR_EL3" to detect this cycle and further panic
+	 * to indicate a problem here (Label "check_loop_ctr"). If we are in this cycle, loop
+	 * counter retains its value but if we do a normal el3_exit this flag gets cleared.
+	 * However, setting SCR_EL3.IESB = 1, should give priority to SError handling
+	 * as per AArch64.TakeException pseudo code in Arm ARM.
+	 *
+	 * TODO: In future if EL3 gets a capability to inject a virtual SError to lower
+	 * ELs, we can remove the el3_panic and handle the original exception first and
+	 * inject SError to lower EL before ereting back.
+	 */
+	stp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+	ldr	x29, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ELR_EL3]
+	mrs	x28, elr_el3
+	cmp	x29, x28
+	b.eq	check_loop_ctr
+	str	x28, [sp, #CTX_EL3STATE_OFFSET + CTX_SAVED_ELR_EL3]
+	/* Zero the loop counter */
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	b	skip_loop_ctr
+check_loop_ctr:
+	ldr	x29, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	add	x29, x29, #1
+	str	x29, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
+	cmp	x29, #ASYNC_EA_REPLAY_COUNTER
+	b.ge	el3_panic
+skip_loop_ctr:
+	/*
+	 * Logic to distinguish if we came from SMC or any other exception.
+	 * Use offsets in vector entry to get which exception we are handling.
+	 * In each vector entry of size 0x200, address "0x0-0x80" is for sync
+	 * exception and "0x80-0x200" is for async exceptions.
+	 * Use vector base address (vbar_el3) and exception offset (LR) to
+	 * calculate whether the address we came from is any of the following
+	 * "0x0-0x80", "0x200-0x280", "0x400-0x480" or "0x600-0x680"
+	 */
+	mrs	x29, vbar_el3
+	sub	x30, x30, x29
+	and	x30, x30, #0x1ff
+	cmp	x30, #0x80
+	b.ge	skip_smc_check
+	/* Its a synchronous exception, Now check if it is SMC or not? */
+	mrs	x30, esr_el3
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	cmp	x30, #EC_AARCH32_SMC
+	b.eq	subtract_elr_el3
+	cmp	x30, #EC_AARCH64_SMC
+	b.eq	subtract_elr_el3
+	b	skip_smc_check
+subtract_elr_el3:
+	sub	x28, x28, #4
+skip_smc_check:
+	msr	elr_el3, x28
+	ldp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	exception_return
+endfunc reflect_pending_async_ea_to_lower_el
+
 	/* ---------------------------------------------------------------------
 	 * The following code handles exceptions caused by BRK instructions.
 	 * Following a BRK instruction, the only real valid cause of action is
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index a1fc12b..3359526 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -39,7 +39,6 @@
 				bl31/interrupt_mgmt.c				\
 				bl31/aarch64/bl31_entrypoint.S			\
 				bl31/aarch64/crash_reporting.S			\
-				bl31/aarch64/ea_delegate.S			\
 				bl31/aarch64/runtime_exceptions.S		\
 				bl31/bl31_context_mgmt.c			\
 				bl31/bl31_traps.c				\
@@ -67,6 +66,10 @@
 BL31_SOURCES		+=	bl31/ehf.c
 endif
 
+ifeq (${FFH_SUPPORT},1)
+BL31_SOURCES		+=	bl31/aarch64/ea_delegate.S
+endif
+
 ifeq (${SDEI_SUPPORT},1)
 ifeq (${EL3_EXCEPTION_HANDLING},0)
   $(error EL3_EXCEPTION_HANDLING must be 1 for SDEI support)
diff --git a/docs/components/ras.rst b/docs/components/ras.rst
index 8d00345..747367a 100644
--- a/docs/components/ras.rst
+++ b/docs/components/ras.rst
@@ -10,6 +10,9 @@
 Reference Manual and `RAS Supplement`_. The rest of this document assumes
 familiarity with architecture and terminology.
 
+**IMPORTANT NOTE**: TF-A implementation assumes that if RAS extension is present
+then FEAT_IESB is also implmented.
+
 There are two philosophies for handling RAS errors from Non-secure world point
 of view.
 
@@ -56,26 +59,87 @@
 EA's originating/attributed to NS world are handled first in NS and Kernel navigates
 the std error records directly.
 
+-  KFH is the default handling mode if platform does not explicitly enable FFH mode.
+-  KFH mode does not need any EL3 involvement except for the reflection of errors back
+   to lower EL. This happens when there is an error (EA) in the system which is not yet
+   signaled to PE while executing at lower EL. During entry into EL3 the errors (EA) are
+   synchronized causing async EA to pend at EL3.
+
+Error Syncronization at EL3 entry
+=================================
+
+During entry to EL3 from lower EL, if there is any pending async EAs they are either
+reflected back to lower EL (KFH) or handled in EL3 itself (FFH).
+
-**KFH can be supported in a platform without TF-A being aware of it but there are few
-corner cases where TF-A needs to have special handling, which is currently missing and
-will be added in future**
+|Image 1|
 
 TF-A build options
 ==================
 
-- **ENABLE_FEAT_RAS**: Manage FEAT_RAS extension when switching the world.
-- **RAS_FFH_SUPPORT**: Pull in necessary framework and platform hooks for Firmware first
-  handling(FFH) of RAS errors.
+- **ENABLE_FEAT_RAS**: Enable RAS extension feature at EL3.
+- **HANDLE_EA_EL3_FIRST_NS**: Required for FFH
 - **RAS_TRAP_NS_ERR_REC_ACCESS**: Trap Non-secure access of RAS error record registers.
-- **RAS_EXTENSION**: Deprecated macro, equivalent to ENABLE_FEAT_RAS and RAS_FFH_SUPPORT
-  put together.
+- **RAS_EXTENSION**: Deprecated macro, equivalent to ENABLE_FEAT_RAS and
+  HANDLE_EA_EL3_FIRST_NS put together.
+
+RAS internal macros
+
+- **FFH_SUPPORT**: Gets enabled if **HANDLE_EA_EL3_FIRST_NS** is enabled.
 
 RAS feature has dependency on some other TF-A build flags
 
 - **EL3_EXCEPTION_HANDLING**: Required for FFH
-- **HANDLE_EA_EL3_FIRST_NS**: Required for FFH
 - **FAULT_INJECTION_SUPPORT**: Required for testing RAS feature on fvp platform
 
+TF-A Tests
+==========
+
+RAS functionality is regularly tested in TF-A CI using `RAS test group`_ which has multiple
+configurations for testing lower EL External aborts.
+
+All the tests are written in TF-A tests which runs as NS-EL2 payload.
+
+- **FFH without RAS extension**
+
+  *fvp-ea-ffh,fvp-ea-ffh:fvp-tftf-fip.tftf-aemv8a-debug*
+
+   Couple of tests, one each for sync EA and async EA from lower EL which gets handled in El3.
+   Inject External aborts(sync/async) which traps in EL3, FVP has a handler which gracefully
+   handles these errors and returns back to TF-A Tests
+
+   Build Configs : **HANDLE_EA_EL3_FIRST_NS** , **PLATFORM_TEST_EA_FFH**
+
+- **FFH with RAS extension**
+
+  Three Tests :
+
+  - *fvp-ras-ffh,fvp-single-fault:fvp-tftf-fip.tftf-aemv8a.fi-debug*
+
+    Inject an unrecoverable RAS error, which gets handled in EL3.
+
+  - *fvp-ras-ffh,fvp-uncontainable:fvp-tftf.fault-fip.tftf-aemv8a.fi-debug*
+
+    Inject uncontainable RAS errors which causes platform to panic.
+
+  - *fvp-ras-ffh,fvp-ras-ffh-nested:fvp-tftf-fip.tftf-ras_ffh_nested-aemv8a.fi-debug*
+
+    Test nested exception handling at El3 for synchronized async EAs. Inject an SError in lower EL
+    which remain pending until we enter EL3 through SMC call. At EL3 entry on encountering a pending
+    async EA it will handle the async EA first (nested exception) before handling the original SMC call.
+
+-  **KFH with RAS extension**
+
+  Couple of tests in the group :
+
+  - *fvp-ras-kfh,fvp-ras-kfh:fvp-tftf-fip.tftf-aemv8a.fi-debug*
+
+    Inject and handle RAS errors in TF-A tests (no El3 involvement)
+
+  - *fvp-ras-kfh,fvp-ras-kfh-reflect:fvp-tftf-fip.tftf-ras_kfh_reflection-aemv8a.fi-debug*
+
+    Reflection of synchronized errors from EL3 to TF-A tests, two tests one each for reflecting
+    in IRQ and SMC path.
+
 RAS Framework
 =============
 
@@ -238,7 +302,7 @@
 Enabling RAS support is a platform choice
 
 The RAS support in |TF-A| introduces a default implementation of
-``plat_ea_handler``, the External Abort handler in EL3. When ``RAS_FFH_SUPPORT``
+``plat_ea_handler``, the External Abort handler in EL3. When ``ENABLE_FEAT_RAS``
 is set to ``1``, it'll first call ``ras_ea_handler()`` function, which is the
 top-level RAS exception handler. ``ras_ea_handler`` is responsible for iterating
 to through platform-supplied error records, probe them, and when an error is
@@ -277,3 +341,6 @@
 *Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.*
 
 .. _RAS Supplement: https://developer.arm.com/documentation/ddi0587/latest
+.. _RAS Test group: https://git.trustedfirmware.org/ci/tf-a-ci-scripts.git/tree/group/tf-l3-boot-tests-ras?h=refs/heads/master
+
+.. |Image 1| image:: ../resources/diagrams/bl31-exception-entry-error-synchronization.png
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index 879ddda..ff69b43 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -1118,6 +1118,65 @@
    ``bl31_main()`` will set up the return to the normal world firmware BL33 and
    continue the boot process in the normal world.
 
+Exception handling in BL31
+--------------------------
+
+When exception occurs, PE must execute handler corresponding to exception. The
+location in memory where the handler is stored is called the exception vector.
+For ARM architecture, exception vectors are stored in a table, called the exception
+vector table.
+
+Each EL (except EL0) has its own vector table, VBAR_ELn register stores the base
+of vector table. Refer to `AArch64 exception vector table`_
+
+Current EL with SP_EL0
+~~~~~~~~~~~~~~~~~~~~~~
+
+-  Sync exception : Not expected except for BRK instruction, its debugging tool which
+   a programmer may place at specific points in a program, to check the state of
+   processor flags at these points in the code.
+
+-  IRQ/FIQ : Unexpected exception, panic
+
+-  SError : "plat_handle_el3_ea", defaults to panic
+
+Current EL with SP_ELx
+~~~~~~~~~~~~~~~~~~~~~~
+
+-  Sync exception : Unexpected exception, panic
+
+-  IRQ/FIQ : Unexpected exception, panic
+
+-  SError : "plat_handle_el3_ea" Except for special handling of lower EL's SError exception
+   which gets triggered in EL3 when PSTATE.A is unmasked. Its only applicable when lower
+   EL's EA is routed to EL3 (FFH_SUPPORT=1).
+
+Lower EL Exceptions
+~~~~~~~~~~~~~~~~~~~
+
+Applies to all the exceptions in both AArch64/AArch32 mode of lower EL.
+
+Before handling any lower EL exception, we synchronize the errors at EL3 entry to ensure
+that any errors pertaining to lower EL is isolated/identified. If we continue without
+identifying these errors early on then these errors will trigger in EL3 (as SError from
+current EL) any time after PSTATE.A is unmasked. This is wrong because the error originated
+in lower EL but exception happened in EL3.
+
+To solve this problem, synchronize the errors at EL3 entry and check for any pending
+errors (async EA). If there is no pending error then continue with original exception.
+If there is a pending error then, handle them based on routing model of EA's. Refer to
+:ref:`Reliability, Availability, and Serviceability (RAS) Extensions` for details about
+routing models.
+
+-  KFH : Reflect it back to lower EL using **reflect_pending_async_ea_to_lower_el()**
+
+-  FFH : Handle the synchronized error first using **handle_pending_async_ea()** after
+   that continue with original exception. It is the only scenario where EL3 is capable
+   of doing nested exception handling.
+
+After synchronizing and handling lower EL SErrors, unmask EA (PSTATE.A) to ensure
+that any further EA's caused by EL3 are caught.
+
 Crash Reporting in BL31
 -----------------------
 
@@ -2803,5 +2862,6 @@
 .. _SMC Calling Convention: https://developer.arm.com/docs/den0028/latest
 .. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
 .. _Arm Confidential Compute Architecture (Arm CCA): https://www.arm.com/why-arm/architecture/security-features/arm-confidential-compute-architecture
+.. _AArch64 exception vector table: https://developer.arm.com/documentation/100933/0100/AArch64-exception-vector-table
 
 .. |Image 1| image:: ../resources/diagrams/rt-svc-descs-layout.png
diff --git a/docs/getting_started/build-internals.rst b/docs/getting_started/build-internals.rst
index a015d71..390c367 100644
--- a/docs/getting_started/build-internals.rst
+++ b/docs/getting_started/build-internals.rst
@@ -12,3 +12,10 @@
    interest when Armv8.4-SecEL2 or RME extension is implemented.
    Default is 0 (disabled). This option will be set to 1 (enabled) when ``SPD=spmd``
    and ``SPMD_SPM_AT_SEL2`` is set or when ``ENABLE_RME`` is set to 1 (enabled).
+
+- ``FFH_SUPPORT``: This boolean option provides support to enable Firmware First
+  handling (FFH) of External aborts and SError interrupts originating from lower
+  ELs which gets trapped in EL3. This option will be set to 1 (enabled) if
+  ``HANDLE_EA_EL3_FIRST_NS`` is set. Currently only NS world routes EA to EL3 but
+  in future when Secure/Realm wants to use FFH then they can introduce new macros
+  which will enable this option implicitly.
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 347cf20..43b13d6 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -811,14 +811,12 @@
 -  ``PSCI_OS_INIT_MODE``: Boolean flag to enable support for optional PSCI
    OS-initiated mode. This option defaults to 0.
 
--  ``ENABLE_FEAT_RAS``: Numeric value to enable Armv8.2 RAS features. RAS features
+-  ``ENABLE_FEAT_RAS``: Boolean flag to enable Armv8.2 RAS features. RAS features
    are an optional extension for pre-Armv8.2 CPUs, but are mandatory for Armv8.2
-   or later CPUs. This flag can take the values 0 to 2, to align with the
-   ``FEATURE_DETECTION`` mechanism.
-
--  ``RAS_FFH_SUPPORT``: Support to enable Firmware first handling of RAS errors
-   originating from NS world. When ``RAS_FFH_SUPPORT`` is set to ``1``,
-   ``HANDLE_EA_EL3_FIRST_NS`` and ``ENABLE_FEAT_RAS`` must also be set to ``1``.
+   or later CPUs. This flag can take the values 0 or 1. The default value is 0.
+   NOTE: This flag enables use of IESB capability to reduce entry latency into
+   EL3 even when RAS error handling is not performed on the platform. Hence this
+   flag is recommended to be turned on Armv8.2 and later CPUs.
 
 -  ``RESET_TO_BL31``: Enable BL31 entrypoint as the CPU reset vector instead
    of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index f612e1c..082497c 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -3298,10 +3298,10 @@
     Argument : uint64_t
     Return   : void
 
-This function is invoked by the RAS framework for the platform to handle an
-External Abort received at EL3. The intention of the function is to attempt to
-resolve the cause of External Abort and return; if that's not possible, to
-initiate orderly shutdown of the system.
+This function is invoked by the runtime exception handling framework for the
+platform to handle an External Abort received at EL3. The intention of the
+function is to attempt to resolve the cause of External Abort and return;
+if that's not possible then an orderly shutdown of the system is initiated.
 
 The first parameter (``int ea_reason``) indicates the reason for External Abort.
 Its value is one of ``ERROR_EA_*`` constants defined in ``ea_handle.h``.
@@ -3316,13 +3316,8 @@
 (``uint64_t flags``) indicates the preempted security state. These parameters
 are received from the top-level exception handler.
 
-If ``RAS_FFH_SUPPORT`` is set to ``1``, the default implementation of this
-function iterates through RAS handlers registered by the platform. If any of the
-RAS handlers resolve the External Abort, no further action is taken.
-
-If ``RAS_FFH_SUPPORT`` is set to ``0``, or if none of the platform RAS handlers
-could resolve the External Abort, the default implementation prints an error
-message, and panics.
+This function must be implemented if a platform expects Firmware First handling
+of External Aborts.
 
 Function : plat_handle_uncontainable_ea
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/resources/diagrams/bl31-exception-entry-error-synchronization.png b/docs/resources/diagrams/bl31-exception-entry-error-synchronization.png
new file mode 100644
index 0000000..cdfdcb9
--- /dev/null
+++ b/docs/resources/diagrams/bl31-exception-entry-error-synchronization.png
Binary files differ
diff --git a/include/arch/aarch32/asm_macros.S b/include/arch/aarch32/asm_macros.S
index 83e94ca..3ba86e9 100644
--- a/include/arch/aarch32/asm_macros.S
+++ b/include/arch/aarch32/asm_macros.S
@@ -120,6 +120,14 @@
 	.endm
 #endif
 
+	/* Macro for error synchronization */
+	.macro synchronize_errors
+	/* Complete any stores that may return an abort */
+	dsb	sy
+	/* Synchronise the CPU context with the completion of the dsb */
+	isb
+	.endm
+
 #if (ARM_ARCH_MAJOR == 7)
 	/* ARMv7 does not support stl instruction */
 	.macro stl _reg, _write_lock
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 13927bd..e9d22b6 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -962,6 +962,7 @@
 #define EC_AARCH64_HVC			U(0x16)
 #define EC_AARCH64_SMC			U(0x17)
 #define EC_AARCH64_SYS			U(0x18)
+#define EC_IMP_DEF_EL3			U(0x1f)
 #define EC_IABORT_LOWER_EL		U(0x20)
 #define EC_IABORT_CUR_EL		U(0x21)
 #define EC_PC_ALIGN			U(0x22)
diff --git a/include/arch/aarch64/asm_macros.S b/include/arch/aarch64/asm_macros.S
index 6091f62..d09ad0f 100644
--- a/include/arch/aarch64/asm_macros.S
+++ b/include/arch/aarch64/asm_macros.S
@@ -292,4 +292,29 @@
 #endif
 	.endm
 
+	/*
+	 * Macro to unmask External Aborts by changing PSTATE.A bit.
+	 * Put explicit synchronization event to ensure newly unmasked interrupt
+	 * is taken immediately.
+	 */
+	.macro  unmask_async_ea
+	msr     daifclr, #DAIF_ABT_BIT
+	isb
+	.endm
+
+	/* Macro for error synchronization on exception boundries.
+	 * With FEAT_RAS enabled, it is assumed that FEAT_IESB is also present
+	 * and enabled.
+	 * FEAT_IESB provides an implicit error synchronization event at exception
+	 * entry and exception return, so there is no need for any explicit instruction.
+	 */
+	.macro synchronize_errors
+#if !ENABLE_FEAT_RAS
+	/* Complete any stores that may return an abort */
+	dsb	sy
+	/* Synchronise the CPU context with the completion of the dsb */
+	isb
+#endif
+	.endm
+
 #endif /* ASM_MACROS_S */
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index 9c9c00f..a78837f 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -208,6 +208,10 @@
 		 */
 		mov_imm	x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \
 				| SCTLR_SA_BIT | SCTLR_A_BIT | SCTLR_DSSBS_BIT))
+#if ENABLE_FEAT_RAS
+		/* If FEAT_RAS is present assume FEAT_IESB is also present */
+		orr	x0, x0, #SCTLR_IESB_BIT
+#endif
 		msr	sctlr_el3, x0
 		isb
 	.endif /* _init_sctlr */
diff --git a/include/bl31/ea_handle.h b/include/bl31/ea_handle.h
index 68f012c..7cd7b6a 100644
--- a/include/bl31/ea_handle.h
+++ b/include/bl31/ea_handle.h
@@ -21,4 +21,6 @@
 /* RAS event signalled as peripheral interrupt */
 #define ERROR_INTERRUPT		3
 
+#define ASYNC_EA_REPLAY_COUNTER	U(100)
+
 #endif /* EA_HANDLE_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 470d113..47d91de 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -63,7 +63,22 @@
 #define CTX_PMCR_EL0		U(0x28)
 #define CTX_IS_IN_EL3		U(0x30)
 #define CTX_MPAM3_EL3		U(0x38)
-#define CTX_EL3STATE_END	U(0x40) /* Align to the next 16 byte boundary */
+/* Constants required in supporting nested exception in EL3 */
+#define CTX_SAVED_ELR_EL3	U(0x40)
+/*
+ * General purpose flag, to save various EL3 states
+ * FFH mode : Used to identify if handling nested exception
+ * KFH mode : Used as counter value
+ */
+#define CTX_NESTED_EA_FLAG	U(0x48)
+#if FFH_SUPPORT
+ #define CTX_SAVED_ESR_EL3	U(0x50)
+ #define CTX_SAVED_SPSR_EL3	U(0x58)
+ #define CTX_SAVED_GPREG_LR	U(0x60)
+ #define CTX_EL3STATE_END	U(0x70) /* Align to the next 16 byte boundary */
+#else
+ #define CTX_EL3STATE_END	U(0x50) /* Align to the next 16 byte boundary */
+#endif
 
 /*******************************************************************************
  * Constants that allow assembler code to access members of and the
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 314eb93..9176e88 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -774,7 +774,7 @@
 #define PLAT_PERCPU_BAKERY_LOCK_SIZE		(1 * CACHE_WRITEBACK_GRANULE)
 
 /* Priority levels for ARM platforms */
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 #define PLAT_RAS_PRI			0x10
 #endif
 #define PLAT_SDEI_CRITICAL_PRI		0x60
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 41b25d6..631094f 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -649,23 +649,9 @@
 1:
 #endif /* IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639 */
 
-/*
- * This is a hot path, so we don't want to do some actual FEAT_RAS runtime
- * detection here. The "esb" is a cheaper variant, so using "dsb" in the
- * ENABLE_FEAT_RAS==2 case is not ideal, but won't hurt.
- */
-#if IMAGE_BL31 && ENABLE_FEAT_RAS == 1
-	/* ----------------------------------------------------------
-	 * Issue Error Synchronization Barrier to synchronize SErrors
-	 * before exiting EL3. We're running with EAs unmasked, so
-	 * any synchronized errors would be taken immediately;
-	 * therefore no need to inspect DISR_EL1 register.
- 	 * ----------------------------------------------------------
-	 */
-	esb
-#else
-	dsb	sy
-#endif /* IMAGE_BL31 && ENABLE_FEAT_RAS */
+#if IMAGE_BL31
+	synchronize_errors
+#endif /* IMAGE_BL31 */
 
 	/* ----------------------------------------------------------
 	 * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET
@@ -689,7 +675,8 @@
 	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
 
 #ifdef IMAGE_BL31
-	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
+	/* Clear the EL3 flag as we are exiting el3 */
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_NESTED_EA_FLAG]
 #endif /* IMAGE_BL31 */
 
 	exception_return
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index ea22655..e02917c 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -191,9 +191,6 @@
 # Enable PSCI OS-initiated mode support
 PSCI_OS_INIT_MODE		:= 0
 
-# Enable RAS Firmware First Handling Support
-RAS_FFH_SUPPORT			:= 0
-
 # By default, BL1 acts as the reset handler, not BL31
 RESET_TO_BL31			:= 0
 
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index f7c174f..2fdff34 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -56,7 +56,6 @@
 	ENABLE_FEAT_RNG			:= 2
 	ENABLE_FEAT_TWED		:= 2
 	ENABLE_FEAT_GCS			:= 2
-	ENABLE_FEAT_RAS			:= 2
 ifeq (${ARCH}, aarch64)
 ifneq (${SPD}, spmd)
 ifeq (${SPM_MM}, 0)
@@ -398,8 +397,12 @@
 endif
 endif
 
-ifeq (${RAS_FFH_SUPPORT},1)
+ifeq (${HANDLE_EA_EL3_FIRST_NS},1)
+ifeq (${ENABLE_FEAT_RAS},1)
 BL31_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_ras.c
+else
+BL31_SOURCES		+= 	plat/arm/board/fvp/aarch64/fvp_ea.c
+endif
 endif
 
 ifneq (${ENABLE_STACK_PROTECTOR},0)
@@ -519,16 +522,19 @@
 # Test specific macros, keep them at bottom of this file
 $(eval $(call add_define,PLATFORM_TEST_EA_FFH))
 ifeq (${PLATFORM_TEST_EA_FFH}, 1)
-    ifeq (${HANDLE_EA_EL3_FIRST_NS}, 0)
-         $(error "PLATFORM_TEST_EA_FFH expects HANDLE_EA_EL3_FIRST_NS to be 1")
+    ifeq (${FFH_SUPPORT}, 0)
+         $(error "PLATFORM_TEST_EA_FFH expects FFH_SUPPORT to be 1")
     endif
-BL31_SOURCES	+= plat/arm/board/fvp/aarch64/fvp_ea.c
+
 endif
 
 $(eval $(call add_define,PLATFORM_TEST_RAS_FFH))
 ifeq (${PLATFORM_TEST_RAS_FFH}, 1)
-    ifeq (${RAS_EXTENSION}, 0)
-         $(error "PLATFORM_TEST_RAS_FFH expects RAS_EXTENSION to be 1")
+    ifeq (${ENABLE_FEAT_RAS}, 0)
+         $(error "PLATFORM_TEST_RAS_FFH expects ENABLE_FEAT_RAS to be 1")
+    endif
+    ifeq (${HANDLE_EA_EL3_FIRST_NS}, 0)
+         $(error "PLATFORM_TEST_RAS_FFH expects HANDLE_EA_EL3_FIRST_NS to be 1")
     endif
 endif
 
diff --git a/plat/arm/board/rdn2/platform.mk b/plat/arm/board/rdn2/platform.mk
index 1506714..ef8f3d4 100644
--- a/plat/arm/board/rdn2/platform.mk
+++ b/plat/arm/board/rdn2/platform.mk
@@ -69,7 +69,7 @@
 BL31_CFLAGS		+=	-DPLAT_XLAT_TABLES_DYNAMIC
 endif
 
-ifeq (${RAS_FFH_SUPPORT},1)
+ifeq (${ENABLE_FEAT_RAS}-${HANDLE_EA_EL3_FIRST_NS},1-1)
 BL31_SOURCES		+=	${RDN2_BASE}/rdn2_ras.c			\
 				${CSS_ENT_BASE}/ras/sgi_ras_common.c	\
 				${CSS_ENT_BASE}/ras/sgi_ras_sram.c	\
diff --git a/plat/arm/board/rdn2/rdn2_plat.c b/plat/arm/board/rdn2/rdn2_plat.c
index f117456..2a6c658 100644
--- a/plat/arm/board/rdn2/rdn2_plat.c
+++ b/plat/arm/board/rdn2/rdn2_plat.c
@@ -137,7 +137,7 @@
 
 	sgi_bl31_common_platform_setup();
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	sgi_ras_platform_setup(&ras_config);
 #endif
 }
diff --git a/plat/arm/board/rdn2/rdn2_security.c b/plat/arm/board/rdn2/rdn2_security.c
index b836a7f..7cd4a1c 100644
--- a/plat/arm/board/rdn2/rdn2_security.c
+++ b/plat/arm/board/rdn2/rdn2_security.c
@@ -15,7 +15,7 @@
 
 static const arm_tzc_regions_info_t tzc_regions[] = {
 	ARM_TZC_REGIONS_DEF,
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	RDN2_TZC_CPER_REGION,
 #endif
 	{}
diff --git a/plat/arm/board/tc/platform.mk b/plat/arm/board/tc/platform.mk
index 8ca33ca..8db6f1d 100644
--- a/plat/arm/board/tc/platform.mk
+++ b/plat/arm/board/tc/platform.mk
@@ -21,8 +21,6 @@
 
 ENABLE_FEAT_RAS		:=	1
 
-RAS_FFH_SUPPORT		:=	0
-
 SDEI_SUPPORT		:=	0
 
 EL3_EXCEPTION_HANDLING	:=	0
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index cfd1aac..f47bc3e 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -295,7 +295,7 @@
 	/* Initialize power controller before setting up topology */
 	plat_arm_pwrc_setup();
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	ras_init();
 #endif
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 421c8e9..bbb39d5 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -352,7 +352,7 @@
 endif
 
 # RAS sources
-ifeq (${RAS_FFH_SUPPORT},1)
+ifeq (${ENABLE_FEAT_RAS}-${HANDLE_EA_EL3_FIRST_NS},1-1)
 BL31_SOURCES		+=	lib/extensions/ras/std_err_record.c		\
 				lib/extensions/ras/ras_common.c
 endif
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index 8c16877..5becbcd 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -41,7 +41,7 @@
 static const interrupt_prop_t arm_interrupt_props[] = {
 	PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
 	PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0),
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	INTR_PROP_DESC(PLAT_CORE_FAULT_IRQ, PLAT_RAS_PRI, INTR_GROUP0,
 			GIC_INTR_CFG_LEVEL)
 #endif
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/css/sgi/include/sgi_base_platform_def.h
index 8a13bf3..9dfe040 100644
--- a/plat/arm/css/sgi/include/sgi_base_platform_def.h
+++ b/plat/arm/css/sgi/include/sgi_base_platform_def.h
@@ -204,13 +204,13 @@
 					SOC_CSS_DEVICE_SIZE,	\
 					MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 #define PLAT_SP_PRI				PLAT_RAS_PRI
 #else
 #define PLAT_SP_PRI				0x10
 #endif
 
-#if (SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)) && RAS_FFH_SUPPORT
+#if (SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)) && ENABLE_FEAT_RAS && FFH_SUPPORT
 /*
  * CPER buffer memory of 128KB is reserved and it is placed adjacent to the
  * memory shared between EL3 and S-EL0.
@@ -239,7 +239,7 @@
  */
 #define PLAT_ARM_SP_IMAGE_STACK_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE +	\
 					 PLAT_SP_IMAGE_NS_BUF_SIZE)
-#endif /* SPM_MM && RAS_FFH_SUPPORT */
+#endif /* SPM_MM && ENABLE_FEAT_RAS && FFH_SUPPORT */
 
 /* Platform ID address */
 #define SSC_VERSION                     (SSC_REG_BASE + SSC_VERSION_OFFSET)
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk
index 358316c..2cd7034 100644
--- a/plat/arm/css/sgi/sgi-common.mk
+++ b/plat/arm/css/sgi/sgi-common.mk
@@ -10,8 +10,6 @@
 
 ENABLE_FEAT_RAS			:=	1
 
-RAS_FFH_SUPPORT			:=	0
-
 SDEI_SUPPORT			:=	0
 
 EL3_EXCEPTION_HANDLING		:=	0
diff --git a/plat/arm/css/sgi/sgi_plat.c b/plat/arm/css/sgi/sgi_plat.c
index 7f79d54..01b426e 100644
--- a/plat/arm/css/sgi/sgi_plat.c
+++ b/plat/arm/css/sgi/sgi_plat.c
@@ -93,7 +93,7 @@
 	PLAT_ARM_SECURE_MAP_DEVICE,
 	ARM_SP_IMAGE_MMAP,
 	ARM_SP_IMAGE_NS_BUF_MMAP,
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	CSS_SGI_SP_CPER_BUF_MMAP,
 #endif
 	ARM_SP_IMAGE_RW_MMAP,
diff --git a/plat/arm/css/sgi/sgi_plat_v2.c b/plat/arm/css/sgi/sgi_plat_v2.c
index 85f99d4..624fed3 100644
--- a/plat/arm/css/sgi/sgi_plat_v2.c
+++ b/plat/arm/css/sgi/sgi_plat_v2.c
@@ -87,7 +87,7 @@
 	SOC_PLATFORM_PERIPH_MAP_DEVICE_USER,
 	ARM_SP_IMAGE_MMAP,
 	ARM_SP_IMAGE_NS_BUF_MMAP,
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	CSS_SGI_SP_CPER_BUF_MMAP,
 #endif
 	ARM_SP_IMAGE_RW_MMAP,
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
index eca81b1..ab99b15 100644
--- a/plat/common/aarch64/plat_common.c
+++ b/plat/common/aarch64/plat_common.c
@@ -11,7 +11,7 @@
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <drivers/console.h>
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 #include <lib/extensions/ras.h>
 #endif
 #include <lib/xlat_tables/xlat_mmu_helpers.h>
@@ -29,7 +29,9 @@
 #pragma weak plat_sdei_validate_entry_point
 #endif
 
+#if FFH_SUPPORT
 #pragma weak plat_ea_handler = plat_default_ea_handler
+#endif
 
 void bl31_plat_runtime_setup(void)
 {
@@ -77,11 +79,12 @@
 	return "EL1";
 }
 
+#if FFH_SUPPORT
 /* Handler for External Aborts from lower EL including RAS errors */
 void plat_default_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
 		void *handle, uint64_t flags)
 {
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	/* Call RAS EA handler */
 	int handled = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
 	if (handled != 0)
@@ -99,3 +102,4 @@
 	 */
 	lower_el_panic();
 }
+#endif
diff --git a/plat/common/aarch64/plat_ehf.c b/plat/common/aarch64/plat_ehf.c
index 41b175d..6100a20 100644
--- a/plat/common/aarch64/plat_ehf.c
+++ b/plat/common/aarch64/plat_ehf.c
@@ -12,7 +12,7 @@
  * Enumeration of priority levels on ARM platforms.
  */
 ehf_pri_desc_t plat_exceptions[] = {
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 	/* RAS Priority */
 	EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_RAS_PRI),
 #endif
@@ -26,7 +26,7 @@
 #endif
 
 #if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 #if (PLAT_SP_PRI != PLAT_RAS_PRI)
 	EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
 #endif
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
index f93585d..ad80596 100644
--- a/plat/nvidia/tegra/include/tegra_private.h
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -154,7 +154,7 @@
 		     void *handle,
 		     uint64_t flags);
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS && FFH_SUPPORT
 void tegra194_ras_enable(void);
 void tegra194_ras_corrected_err_clear(uint64_t *cookie);
 #endif
diff --git a/plat/nvidia/tegra/soc/t194/plat_ras.c b/plat/nvidia/tegra/soc/t194/plat_ras.c
index 2f438c3..841d70b 100644
--- a/plat/nvidia/tegra/soc/t194/plat_ras.c
+++ b/plat/nvidia/tegra/soc/t194/plat_ras.c
@@ -484,7 +484,7 @@
 void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
 		void *handle, uint64_t flags)
 {
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
 #else
 	plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
diff --git a/plat/nvidia/tegra/soc/t194/plat_setup.c b/plat/nvidia/tegra/soc/t194/plat_setup.c
index d3d09d3..6850330 100644
--- a/plat/nvidia/tegra/soc/t194/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t194/plat_setup.c
@@ -254,7 +254,7 @@
 	/* sanity check MCE firmware compatibility */
 	mce_verify_firmware_version();
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	/* Enable Uncorrectable RAS error */
 	tegra194_ras_enable();
 #endif
diff --git a/plat/nvidia/tegra/soc/t194/plat_sip_calls.c b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c
index f0704ed..6e42e64 100644
--- a/plat/nvidia/tegra/soc/t194/plat_sip_calls.c
+++ b/plat/nvidia/tegra/soc/t194/plat_sip_calls.c
@@ -71,7 +71,7 @@
 
 		break;
 
-#if RAS_FFH_SUPPORT
+#if ENABLE_FEAT_RAS
 	case TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS:
 	{
 		/*
diff --git a/plat/nvidia/tegra/soc/t194/platform_t194.mk b/plat/nvidia/tegra/soc/t194/platform_t194.mk
index 289e921..e6e0b5e 100644
--- a/plat/nvidia/tegra/soc/t194/platform_t194.mk
+++ b/plat/nvidia/tegra/soc/t194/platform_t194.mk
@@ -37,7 +37,7 @@
 
 # enable RAS handling
 HANDLE_EA_EL3_FIRST_NS			:= 1
-RAS_FFH_SUPPORT				:= 1
+ENABLE_FEAT_RAS				:= 1
 
 # platform files
 PLAT_INCLUDES		+=	-Iplat/nvidia/tegra/include/t194 \
@@ -71,7 +71,7 @@
 endif
 
 # RAS sources
-ifeq (${RAS_FFH_SUPPORT},1)
+ifeq (${ENABLE_FEAT_RAS}-${HANDLE_EA_EL3_FIRST_NS},1-1)
 BL31_SOURCES		+=	lib/extensions/ras/std_err_record.c		\
 				lib/extensions/ras/ras_common.c			\
 				${SOC_DIR}/plat_ras.c