refactor(cpufeat): enable FEAT_RAS for FEAT_STATE_CHECKED

At the moment we only support FEAT_RAS to be either unconditionally
compiled in, or to be not supported at all.

Add support for runtime detection (FEAT_RAS=2), by splitting
is_armv8_2_feat_ras_present() into an ID register reading function and
a second function to report the support status. That function considers
both build time settings and runtime information (if needed), and is
used before we access RAS related registers.

Also move the context saving code from assembly to C, and use the new
is_feat_ras_supported() function to guard its execution.

Change the FVP platform default to the now supported dynamic
option (=2), so the right decision can be made by the code at runtime.

Change-Id: I30498f72fd80b136850856244687400456a03d0e
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Manish Pandey <manish.pandey2@arm.com>
diff --git a/Makefile b/Makefile
index d5e64ea..edd435c 100644
--- a/Makefile
+++ b/Makefile
@@ -809,8 +809,8 @@
 endif
 # When FAULT_INJECTION_SUPPORT is used, require that FEAT_RAS is enabled
 ifeq ($(FAULT_INJECTION_SUPPORT),1)
-    ifneq ($(ENABLE_FEAT_RAS),1)
-        $(error For FAULT_INJECTION_SUPPORT, ENABLE_FEAT_RAS must also be 1)
+    ifeq ($(ENABLE_FEAT_RAS),0)
+        $(error For FAULT_INJECTION_SUPPORT, ENABLE_FEAT_RAS must not be 0)
     endif
 endif
 
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 9b3bffc..50b74d0 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -60,16 +60,6 @@
 	}
 }
 
-/*******************************************************************************
- * Feature : FEAT_RAS (Reliability, Availability, and Serviceability Extension)
- ******************************************************************************/
-static void read_feat_ras(void)
-{
-#if (ENABLE_FEAT_RAS == FEAT_STATE_ALWAYS)
-	feat_detect_panic(is_armv8_2_feat_ras_present(), "RAS");
-#endif
-}
-
 /************************************************
  * Feature : FEAT_PAUTH (Pointer Authentication)
  ***********************************************/
@@ -160,9 +150,9 @@
 	check_feature(ENABLE_FEAT_VHE, read_feat_vhe_id_field(), "VHE", 1, 1);
 
 	/* v8.2 features */
-	read_feat_ras();
 	check_feature(ENABLE_SVE_FOR_NS, read_feat_sve_id_field(),
 		      "SVE", 1, 1);
+	check_feature(ENABLE_FEAT_RAS, read_feat_ras_id_field(), "RAS", 1, 2);
 
 	/* v8.3 features */
 	read_feat_pauth();
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index ac5eae2..20206c1 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -393,6 +393,9 @@
 #define ID_AA64PFR1_EL1_RNG_TRAP_SUPPORTED	ULL(0x1)
 #define ID_AA64PFR1_EL1_RNG_TRAP_NOT_SUPPORTED	ULL(0x0)
 
+#define VDISR_EL2				S3_4_C12_C1_1
+#define VSESR_EL2				S3_4_C5_C2_3
+
 /* Memory Tagging Extension is not implemented */
 #define MTE_UNIMPLEMENTED	U(0)
 /* FEAT_MTE: MTE instructions accessible at EL0 are implemented */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index a0141de..d6f12f3 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -499,14 +499,22 @@
 	return read_feat_sve_id_field() >= ID_AA64PFR0_SVE_SUPPORTED;
 }
 
-/*******************************************************************************
- * Function to identify the presence of FEAT_RAS (Reliability,Availability,
- * and Serviceability Extension)
- ******************************************************************************/
-static inline bool is_armv8_2_feat_ras_present(void)
+static unsigned int read_feat_ras_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64pfr0_el1(), ID_AA64PFR0_RAS);
+}
+
+static inline bool is_feat_ras_supported(void)
 {
-	return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_RAS_SHIFT) &
-		ID_AA64PFR0_RAS_MASK) != ID_AA64PFR0_RAS_NOT_SUPPORTED);
+	if (ENABLE_FEAT_RAS == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_RAS == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_ras_id_field() != 0U;
 }
 
 static unsigned int read_feat_dit_id_field(void)
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 1b4bc11..5b3d4c2 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -549,6 +549,10 @@
 /* Armv8.2 ID Registers */
 DEFINE_RENAME_IDREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
 
+/* Armv8.2 RAS Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(vdisr_el2, VDISR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(vsesr_el2, VSESR_EL2)
+
 /* Armv8.2 MPAM Registers */
 DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3)
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index c9590d4..e6af43e 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -523,10 +523,6 @@
 void el2_sysregs_context_save_mte(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_mte(el2_sysregs_t *regs);
 #endif /* CTX_INCLUDE_MTE_REGS */
-#if ENABLE_FEAT_RAS
-void el2_sysregs_context_save_ras(el2_sysregs_t *regs);
-void el2_sysregs_context_restore_ras(el2_sysregs_t *regs);
-#endif /* ENABLE_FEAT_RAS */
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 #if CTX_INCLUDE_FPREGS
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 63566da..0f2dfeb 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -17,10 +17,6 @@
 	.global	el2_sysregs_context_save_mte
 	.global	el2_sysregs_context_restore_mte
 #endif /* CTX_INCLUDE_MTE_REGS */
-#if ENABLE_FEAT_RAS
-	.global	el2_sysregs_context_save_ras
-	.global	el2_sysregs_context_restore_ras
-#endif /* ENABLE_FEAT_RAS */
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 	.global	el1_sysregs_context_save
@@ -210,30 +206,6 @@
 endfunc el2_sysregs_context_restore_mte
 #endif /* CTX_INCLUDE_MTE_REGS */
 
-#if ENABLE_FEAT_RAS
-func el2_sysregs_context_save_ras
-	/*
-	 * VDISR_EL2 and VSESR_EL2 registers are saved only when
-	 * FEAT_RAS is supported.
-	 */
-	mrs	x11, vdisr_el2
-	mrs	x12, vsesr_el2
-	stp	x11, x12, [x0, #CTX_VDISR_EL2]
-	ret
-endfunc el2_sysregs_context_save_ras
-
-func el2_sysregs_context_restore_ras
-	/*
-	 * VDISR_EL2 and VSESR_EL2 registers are restored only when FEAT_RAS
-	 * is supported.
-	 */
-	ldp	x11, x12, [x0, #CTX_VDISR_EL2]
-	msr	vdisr_el2, x11
-	msr	vsesr_el2, x12
-	ret
-endfunc el2_sysregs_context_restore_ras
-#endif /* ENABLE_FEAT_RAS */
-
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 /* ------------------------------------------------------------------
@@ -855,7 +827,12 @@
 1:
 #endif /* IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639 */
 
-#if IMAGE_BL31 && ENABLE_FEAT_RAS
+/*
+ * 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
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 3ddf5fa..e107f5a 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -1012,9 +1012,13 @@
 			write_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2,
 				      read_ttbr1_el2());
 		}
-#if ENABLE_FEAT_RAS
-		el2_sysregs_context_save_ras(el2_sysregs_ctx);
-#endif
+
+		if (is_feat_ras_supported()) {
+			write_ctx_reg(el2_sysregs_ctx, CTX_VDISR_EL2,
+				      read_vdisr_el2());
+			write_ctx_reg(el2_sysregs_ctx, CTX_VSESR_EL2,
+				      read_vsesr_el2());
+		}
 
 		if (is_feat_nv2_supported()) {
 			write_ctx_reg(el2_sysregs_ctx, CTX_VNCR_EL2,
@@ -1095,9 +1099,11 @@
 			write_contextidr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_CONTEXTIDR_EL2));
 			write_ttbr1_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TTBR1_EL2));
 		}
-#if ENABLE_FEAT_RAS
-		el2_sysregs_context_restore_ras(el2_sysregs_ctx);
-#endif
+
+		if (is_feat_ras_supported()) {
+			write_vdisr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VDISR_EL2));
+			write_vsesr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VSESR_EL2));
+		}
 
 		if (is_feat_nv2_supported()) {
 			write_vncr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_VNCR_EL2));
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 29835d9..8a6aa00 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -50,6 +50,7 @@
 	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)