feat(fpmr): disable FPMR trap

This patch enables support of FEAT_FPMR by enabling access
to FPMR register. It achieves it by setting the EnFPM bit of
SCR_EL3. This feature is currently enabled for NS world only.

Reference:
https://developer.arm.com/documentation/109697/2024_09/
Feature-descriptions/The-Armv9-5-architecture-extension?lang=en

Change-Id: I580c409b9b22f8ead0737502280fb9093a3d5dd2
Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
diff --git a/Makefile b/Makefile
index 384c1e4..2b6857b 100644
--- a/Makefile
+++ b/Makefile
@@ -951,8 +951,21 @@
 	ifeq (${ENABLE_FEAT_RNG_TRAP},1)
                 $(error "ENABLE_FEAT_RNG_TRAP cannot be used with ARCH=aarch32")
 	endif
+
+	ifneq (${ENABLE_FEAT_FPMR},0)
+                $(error "ENABLE_FEAT_FPMR cannot be used with ARCH=aarch32")
+	endif
 endif #(ARCH=aarch32)
 
+ifneq (${ENABLE_FEAT_FPMR},0)
+	ifeq (${ENABLE_FEAT_FGT},0)
+                $(error "ENABLE_FEAT_FPMR requires ENABLE_FEAT_FGT")
+	endif
+	ifeq (${ENABLE_FEAT_HCX},0)
+                $(error "ENABLE_FEAT_FPMR requires ENABLE_FEAT_HCX")
+	endif
+endif #(ENABLE_FEAT_FPMR)
+
 ifneq (${ENABLE_SME_FOR_NS},0)
 	ifeq (${ENABLE_SVE_FOR_NS},0)
                 $(error "ENABLE_SME_FOR_NS requires ENABLE_SVE_FOR_NS")
@@ -1264,6 +1277,7 @@
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_FGT2 \
+	ENABLE_FEAT_FPMR \
 	ENABLE_FEAT_HCX \
 	ENABLE_FEAT_LS64_ACCDATA \
 	ENABLE_FEAT_MTE2 \
@@ -1425,6 +1439,7 @@
 	ENABLE_MPMM_FCONF \
 	ENABLE_FEAT_FGT \
 	ENABLE_FEAT_FGT2 \
+	ENABLE_FEAT_FPMR \
 	ENABLE_FEAT_ECV \
 	ENABLE_FEAT_AMUv1p1 \
 	ENABLE_FEAT_SEL2 \
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 336ad2b..2f9dc65 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -150,6 +150,10 @@
 BL31_SOURCES		+=	lib/extensions/trf/aarch64/trf.c
 endif
 
+ifneq (${ENABLE_FEAT_FPMR},0)
+BL31_SOURCES		+=	lib/extensions/fpmr/fpmr.c
+endif
+
 ifeq (${WORKAROUND_CVE_2017_5715},1)
 BL31_SOURCES		+=	lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S	\
 				lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 8c03ab8..0f6be9f 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -280,6 +280,12 @@
 			     ID_AA64MMFR3_EL1_D128_MASK);
 }
 
+static unsigned int read_feat_fpmr_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64pfr2_el1(), ID_AA64PFR2_EL1_FPMR_SHIFT,
+			     ID_AA64PFR2_EL1_FPMR_MASK);
+}
+
 /***********************************************************************************
  * TF-A supports many Arm architectural features starting from arch version
  * (8.0 till 8.7+). These features are mostly enabled through build flags. This
@@ -405,6 +411,8 @@
 		      "SME", 1, 2);
 	check_feature(ENABLE_SME2_FOR_NS, read_feat_sme_id_field(),
 		      "SME2", 2, 2);
+	check_feature(ENABLE_FEAT_FPMR, read_feat_fpmr_id_field(),
+		      "FPMR", 1, 1);
 
 	/* v9.3 features */
 	check_feature(ENABLE_FEAT_D128, read_feat_d128_id_field(),
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 7d067c6..bd11d68 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -351,6 +351,12 @@
    This flag can take the values 0 to 2, to align  with the ``ENABLE_FEAT``
    mechanism. Default value is ``0``.
 
+-  ``ENABLE_FEAT_FPMR``: Numerical value to enable support for Floating Point
+   Mode Register feature, allowing access to the FPMR register. FPMR register
+   controls the behaviors of FP8 instructions. It is an optional architectural
+   feature from v9.2 and upwards. This flag can take value of 0 to 2, to align
+   with the ``FEATURE_DETECTION`` mechanism. Default value is ``0``.
+
 -  ``ENABLE_FEAT_FGT``: Numeric value to enable support for FGT (Fine Grain Traps)
    feature allowing for access to the HDFGRTR_EL2 (Hypervisor Debug Fine-Grained
    Read Trap Register) during EL2 to EL3 context save/restore operations.
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 737d07a..3a7e2eb 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -465,6 +465,11 @@
 #define ID_AA64PFR2_EL1_MTEFAR_SHIFT		U(8)
 #define ID_AA64PFR2_EL1_MTEFAR_MASK		ULL(0xf)
 
+#define ID_AA64PFR2_EL1_FPMR_SHIFT		U(32)
+#define ID_AA64PFR2_EL1_FPMR_MASK		ULL(0xf)
+
+#define FPMR_IMPLEMENTED			ULL(0x1)
+
 #define VDISR_EL2				S3_4_C12_C1_1
 #define VSESR_EL2				S3_4_C5_C2_3
 
@@ -605,6 +610,7 @@
 #define SCR_NSE_SHIFT		U(62)
 #define SCR_FGTEN2_BIT		(UL(1) << 59)
 #define SCR_NSE_BIT		(ULL(1) << SCR_NSE_SHIFT)
+#define SCR_EnFPM_BIT		(ULL(1) << 50)
 #define SCR_GPF_BIT		(UL(1) << 48)
 #define SCR_D128En_BIT		(UL(1) << 47)
 #define SCR_TWEDEL_SHIFT	U(30)
@@ -1522,6 +1528,11 @@
  ******************************************************************************/
 #define CLUSTERPWRDN_EL1	S3_0_c15_c3_6
 
+/*******************************************************************************
+ * FEAT_FPMR - Floating point Mode Register
+ ******************************************************************************/
+#define FPMR			S3_3_C4_C4_2
+
 /* CLUSTERPWRDN_EL1 register definitions */
 #define DSU_CLUSTER_PWR_OFF	0
 #define DSU_CLUSTER_PWR_ON	1
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 59188da..8bdc13c 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -142,6 +142,8 @@
  * +----------------------------+
  * |	FEAT_LS64_ACCDATA	|
  * +----------------------------+
+ * |	FEAT_FPMR		|
+ * +----------------------------+
  */
 
 __attribute__((always_inline))
@@ -284,6 +286,12 @@
 		     ID_AA64MMFR3_EL1_D128_MASK, D128_IMPLEMENTED,
 		     ENABLE_FEAT_D128)
 
+/* FEAT_FPMR */
+CREATE_FEATURE_FUNCS(feat_fpmr, id_aa64pfr2_el1, ID_AA64PFR2_EL1_FPMR_SHIFT,
+		     ID_AA64PFR2_EL1_FPMR_MASK, FPMR_IMPLEMENTED,
+		     ENABLE_FEAT_FPMR)
+
+
 __attribute__((always_inline))
 static inline bool is_feat_sxpie_supported(void)
 {
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 119c428..3f3f14d 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -718,6 +718,8 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
 DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
 
+DEFINE_RENAME_SYSREG_RW_FUNCS(fpmr, FPMR)
+
 #define IS_IN_EL(x) \
 	(GET_EL(read_CurrentEl()) == MODE_EL##x)
 
diff --git a/include/lib/extensions/fpmr.h b/include/lib/extensions/fpmr.h
new file mode 100644
index 0000000..bc3ee9e
--- /dev/null
+++ b/include/lib/extensions/fpmr.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FPMR_H
+#define FPMR_H
+
+#include <context.h>
+
+#if ENABLE_FEAT_FPMR
+void fpmr_enable_per_world(per_world_context_t *per_world_ctx);
+#else
+static inline void fpmr_enable_per_world(per_world_context_t *per_world_ctx)
+{
+}
+#endif /* ENABLE_FEAT_FPMR */
+
+#endif /* FPMR_H */
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 4ae1306..f963ed1 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -28,6 +28,7 @@
 #include <lib/extensions/brbe.h>
 #include <lib/extensions/debug_v8p9.h>
 #include <lib/extensions/fgt2.h>
+#include <lib/extensions/fpmr.h>
 #include <lib/extensions/mpam.h>
 #include <lib/extensions/pmuv3.h>
 #include <lib/extensions/sme.h>
@@ -291,6 +292,13 @@
 		scr_el3 |= SCR_D128En_BIT;
 	}
 
+	if (is_feat_fpmr_supported()) {
+		/* Set the EnFPM bit in SCR_EL3 to enable access to FPMR
+		 * register.
+		 */
+		scr_el3 |= SCR_EnFPM_BIT;
+	}
+
 	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
 
 	/* Initialize EL2 context registers */
@@ -714,6 +722,10 @@
 	if (is_feat_mpam_supported()) {
 		mpam_enable_per_world(&per_world_context[CPU_CONTEXT_NS]);
 	}
+
+	if (is_feat_fpmr_supported()) {
+		fpmr_enable_per_world(&per_world_context[CPU_CONTEXT_NS]);
+	}
 }
 #endif /* IMAGE_BL31 */
 
diff --git a/lib/extensions/fpmr/fpmr.c b/lib/extensions/fpmr/fpmr.c
new file mode 100644
index 0000000..8e37e7a
--- /dev/null
+++ b/lib/extensions/fpmr/fpmr.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/extensions/fpmr.h>
+
+void fpmr_enable_per_world(per_world_context_t *per_world_ctx)
+{
+	u_register_t reg;
+
+	/* Disable Floating point Trap in CPTR_EL3. */
+	reg = per_world_ctx->ctx_cptr_el3;
+	reg &= ~TFP_BIT;
+	per_world_ctx->ctx_cptr_el3 = reg;
+}
diff --git a/make_helpers/arch_features.mk b/make_helpers/arch_features.mk
index 57609d5..a1db0b8 100644
--- a/make_helpers/arch_features.mk
+++ b/make_helpers/arch_features.mk
@@ -408,6 +408,9 @@
 # if FEAT_BRBE is implemented.
 ENABLE_BRBE_FOR_NS			?=	0
 
+# Flag to enable Floating point exception Mode Register Feature (FEAT_FPMR)
+ENABLE_FEAT_FPMR			?=	0
+
 #----
 # 9.3
 #----
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 1340a65..3b638e4 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -57,6 +57,7 @@
       ENABLE_BRBE_FOR_NS	:= 2
       ENABLE_TRBE_FOR_NS	:= 2
       ENABLE_FEAT_D128		:= 2
+      ENABLE_FEAT_FPMR		:= 2
 endif
 
 ENABLE_SYS_REG_TRACE_FOR_NS	:= 2