feat(hcx): add build option to enable FEAT_HCX

FEAT_HCX adds the extended hypervisor configuration register (HCRX_EL2)
and access to this register must be explicitly enabled through the
SCR_EL3.HXEn bit.  This patch adds a new build flag ENABLE_FEAT_HCX to
allow the register to be accessed from EL2.

Signed-off-by: John Powell <john.powell@arm.com>
Change-Id: Ibb36ad90622f1dc857adab4b0d4d7a89456a522b
diff --git a/Makefile b/Makefile
index 9d1e945..a11e55f 100644
--- a/Makefile
+++ b/Makefile
@@ -971,6 +971,7 @@
         ENABLE_TRBE_FOR_NS \
         ENABLE_SYS_REG_TRACE_FOR_NS \
         ENABLE_TRF_FOR_NS \
+        ENABLE_FEAT_HCX \
 )))
 
 $(eval $(call assert_numerics,\
@@ -1074,6 +1075,7 @@
         ENABLE_TRBE_FOR_NS \
         ENABLE_SYS_REG_TRACE_FOR_NS \
         ENABLE_TRF_FOR_NS \
+        ENABLE_FEAT_HCX \
 )))
 
 ifeq (${SANITIZE_UB},trap)
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index 44bf32c..f272af5 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -85,6 +85,15 @@
 	/* Perform late platform-specific setup */
 	bl31_plat_arch_setup();
 
+#if ENABLE_FEAT_HCX
+	/*
+	 * Assert that FEAT_HCX is supported on this system, without this check
+	 * an exception would occur during context save/restore if enabled but
+	 * not supported.
+	 */
+	assert(is_feat_hcx_present());
+#endif /* ENABLE_FEAT_HCX */
+
 #if CTX_INCLUDE_PAUTH_REGS
 	/*
 	 * Assert that the ARMv8.3-PAuth registers are present or an access
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 115b2b2..0ec10f5 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -235,6 +235,10 @@
    builds, but this behaviour can be overridden in each platform's Makefile or
    in the build command line.
 
+-  ``ENABLE_FEAT_HCX``: This option sets the bit SCR_EL3.HXEn in EL3 to allow
+   access to HCRX_EL2 (extended hypervisor control register) from EL2 as well as
+   adding HCRX_EL2 to the EL2 context save/restore operations.
+
 -  ``ENABLE_LTO``: Boolean option to enable Link Time Optimization (LTO)
    support in GCC for TF-A. This option is currently only supported for
    AArch64. Default is 0.
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 9ea1114..d260ecf 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -281,6 +281,11 @@
 #define ID_AA64MMFR1_EL1_VHE_SHIFT		U(8)
 #define ID_AA64MMFR1_EL1_VHE_MASK		ULL(0xf)
 
+#define ID_AA64MMFR1_EL1_HCX_SHIFT              U(40)
+#define ID_AA64MMFR1_EL1_HCX_MASK               ULL(0xf)
+#define ID_AA64MMFR1_EL1_HCX_SUPPORTED          ULL(0x1)
+#define ID_AA64MMFR1_EL1_HCX_NOT_SUPPORTED      ULL(0x0)
+
 /* ID_AA64MMFR2_EL1 definitions */
 #define ID_AA64MMFR2_EL1		S3_0_C0_C7_2
 
@@ -429,6 +434,7 @@
 #define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
 #define SCR_TWEDEL_SHIFT	U(30)
 #define SCR_TWEDEL_MASK		ULL(0xf)
+#define SCR_HXEn_BIT            (UL(1) << 38)
 #define SCR_AMVOFFEN_BIT	(UL(1) << 35)
 #define SCR_TWEDEn_BIT		(UL(1) << 29)
 #define SCR_ECVEN_BIT		(UL(1) << 28)
@@ -1144,6 +1150,16 @@
 #define GCR_EL1			S3_0_C1_C0_6
 
 /*******************************************************************************
+ * FEAT_HCX - Extended Hypervisor Configuration Register
+ ******************************************************************************/
+#define HCRX_EL2                S3_4_C1_C2_2
+#define HCRX_EL2_FGTnXS_BIT     (UL(1) << 4)
+#define HCRX_EL2_FnXS_BIT       (UL(1) << 3)
+#define HCRX_EL2_EnASR_BIT      (UL(1) << 2)
+#define HCRX_EL2_EnALS_BIT      (UL(1) << 1)
+#define HCRX_EL2_EnAS0_BIT      (UL(1) << 0)
+
+/*******************************************************************************
  * Definitions for DynamicIQ Shared Unit registers
  ******************************************************************************/
 #define CLUSTERPWRDN_EL1	S3_0_c15_c3_6
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index dc0b7f3..3ff67e5 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -117,4 +117,10 @@
 		ID_AA64PFR1_MPAM_FRAC_SHIFT) & ID_AA64PFR1_MPAM_FRAC_MASK));
 }
 
+static inline bool is_feat_hcx_present(void)
+{
+	return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_HCX_SHIFT) &
+		ID_AA64MMFR1_EL1_HCX_MASK) == ID_AA64MMFR1_EL1_HCX_SUPPORTED);
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index a41b325..549ae66 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -532,6 +532,9 @@
 DEFINE_SYSREG_READ_FUNC(rndr)
 DEFINE_SYSREG_READ_FUNC(rndrrs)
 
+/* FEAT_HCX Register */
+DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
+
 /* DynamIQ Shared Unit power management */
 DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
 
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index d449a65..c3f4117 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -228,6 +228,10 @@
 
 // Starting with Armv8.5
 #define CTX_SCXTNUM_EL2		U(0x1e0)
+
+// Register for FEAT_HCX
+#define CTX_HCRX_EL2            U(0x1e8)
+
 /* Align to the next 16 byte boundary */
 #define CTX_EL2_SYSREGS_END	U(0x1f0)
 
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 40e7ddf..e270ad0 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -193,6 +193,11 @@
 	str	x13, [x0, #CTX_SCXTNUM_EL2]
 #endif
 
+#if ENABLE_FEAT_HCX
+	mrs	x14, hcrx_el2
+	str	x14, [x0, #CTX_HCRX_EL2]
+#endif
+
 	ret
 endfunc el2_sysregs_context_save
 
@@ -362,6 +367,11 @@
 	msr	scxtnum_el2, x13
 #endif
 
+#if ENABLE_FEAT_HCX
+	ldr	x14, [x0, #CTX_HCRX_EL2]
+	msr	hcrx_el2, x14
+#endif
+
 	ret
 endfunc el2_sysregs_context_restore
 
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 52102dd..08022d4 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -112,6 +112,14 @@
 	if (EP_GET_ST(ep->h.attr) != 0U)
 		scr_el3 |= SCR_ST_BIT;
 
+	/*
+	 * If FEAT_HCX is enabled, enable access to HCRX_EL2 by setting
+	 * SCR_EL3.HXEn.
+	 */
+#if ENABLE_FEAT_HCX
+	scr_el3 |= SCR_HXEn_BIT;
+#endif
+
 #if RAS_TRAP_LOWER_EL_ERR_ACCESS
 	/*
 	 * SCR_EL3.TERR: Trap Error record accesses. Accesses to the RAS ERR
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index c188621..18092e7 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -121,6 +121,9 @@
 # Use BRANCH_PROTECTION to enable PAUTH.
 ENABLE_PAUTH			:= 0
 
+# Flag to enable access to the HCRX_EL2 register by setting SCR_EL3.HXEn.
+ENABLE_FEAT_HCX                 := 0
+
 # By default BL31 encryption disabled
 ENCRYPT_BL31			:= 0