Build: Add option CONFIG_TFM_ENABLE_FPU
Add CONFIG_TFM_ENABLE_FPU for enabling the FPU coprocessors when either
or both of the SPE and the NSPE needs to operate the FPU. On an Armv8-M
platform with TrustZone, this option also enables Non-Secure access to
the FPU.
The motivation of this new option is that in the TrustZone architecture,
both the SPE and NSPE must enable the FPU consistently. If one of the
processing environments has the FPU coprocessors enabled and the other
has not, then a context switch (e.g. an interrupt) that happens during
a cross-environment call will trigger a NOCP (No coprocessor) usage
fault, if CONTROL.FPCA==1 (floating point context active). This fault
happens because CONTROL.FPCA is not banked, and the system see a
contradiction if the current side does not have the FPU enabled but
the floating point context (FPCA) has been set as active by the other
side.
CONFIG_TFM_FP=hard, which enables floating point instructions and the
hard float ABI, depends on CONFIG_TFM_ENABLE_FPU=ON as the FPU is used.
Therefore a dependency check has been added.
For a user of TF-M, setting CONFIG_TFM_ENABLE_FPU=ON while leaving
CONFIG_TFM_FP=soft (default) enables the FPU coprocessors but keeps
the TF-M SPE to be without any floating point operations. The user's
Non-Secure application is allowed to operate the FPU as needed.
Note: If the SPE operates the FPU (CONFIG_TFM_FP=hard), the compiler
support for patching the CVE-2021-35465 (VLLDM instruction security)
vulnerability is required for FPU context protection. If the NSPE is
the only side that operates the FPU, then the FPU context protection
can be skipped as the SPE does not touch the floating point registers
anyway.
Change-Id: I20c80f3d86087585bc569a1bfa183c7c22220c09
Signed-off-by: Lingkai Dong <lingkai.dong@arm.com>
diff --git a/config/check_config.cmake b/config/check_config.cmake
index 284dd8a..3984485 100644
--- a/config/check_config.cmake
+++ b/config/check_config.cmake
@@ -60,6 +60,7 @@
tfm_invalid_config((NOT CONFIG_TFM_FP_ARCH) AND CONFIG_TFM_FP STREQUAL "hard")
tfm_invalid_config((NOT TFM_PSA_API) AND CONFIG_TFM_FP STREQUAL "hard")
tfm_invalid_config(CONFIG_TFM_FP STREQUAL "soft" AND CONFIG_TFM_LAZY_STACKING)
+tfm_invalid_config(CONFIG_TFM_FP STREQUAL "hard" AND NOT CONFIG_TFM_ENABLE_FPU)
########################## BL2 #################################################
diff --git a/config/config_default.cmake b/config/config_default.cmake
index fedc45a..2afc324 100755
--- a/config/config_default.cmake
+++ b/config/config_default.cmake
@@ -57,9 +57,11 @@
set(CONFIG_TFM_HALT_ON_CORE_PANIC OFF CACHE BOOL "On fatal errors in the secure firmware, halt instead of rebooting.")
-set(CONFIG_TFM_FP "soft" CACHE STRING "FP ABI type in SPE and NSPE: soft-Software ABI, hard-Hardware ABI")
+set(CONFIG_TFM_FP "soft" CACHE STRING "FP ABI type in SPE and NSPE: soft-Software ABI, hard-Hardware ABI. This configuration applies to both SPE and TF-M tests NSPE, and needs to be hard when enabling TF-M S/NS FPU tests.")
set(CONFIG_TFM_LAZY_STACKING OFF CACHE BOOL "Enable/disable lazy stacking")
+set(CONFIG_TFM_ENABLE_FPU OFF CACHE BOOL "Make FPU operational when SPE and/or NSPE require FPU usage. This alone only enables the FPU coprocessors, whereas CONFIG_TFM_FP=hard compiles the code with hardware FP instructions and ABI.")
+
set(CONFIG_TFM_DOORBELL_API ON CACHE BOOL "Enable the doorbell APIs")
set(CONFIG_TFM_STACK_WATERMARKS OFF CACHE BOOL "Whether to pre-fill partition stacks with a set value to help determine stack usage")
diff --git a/config/cp_config_default.cmake b/config/cp_config_default.cmake
index 45e119e..8fcebaa 100644
--- a/config/cp_config_default.cmake
+++ b/config/cp_config_default.cmake
@@ -14,4 +14,5 @@
if (CONFIG_TFM_FP STREQUAL "hard")
set(CONFIG_TFM_LAZY_STACKING ON CACHE BOOL "Enable lazy stacking")
+ set(CONFIG_TFM_ENABLE_FPU ON CACHE BOOL "Permit TrustZone NSPE access to FPU")
endif()
diff --git a/docs/integration_guide/tfm_fpu_support.rst b/docs/integration_guide/tfm_fpu_support.rst
index 09f826b..df6cdca 100644
--- a/docs/integration_guide/tfm_fpu_support.rst
+++ b/docs/integration_guide/tfm_fpu_support.rst
@@ -24,6 +24,12 @@
Please refer to Arm musca S1 [7]_ platform as a reference implementation when
you enable FP support on your platforms.
+.. Note::
+ Alternatively, if you intend to use FP in your own NSPE application but the
+ TF-M SPE services that you enable do not require FP, you can set the CMake
+ configuration ``CONFIG_TFM_ENABLE_FPU`` to ``ON`` and **ignore** any
+ configurations described below.
+
============================
FP ABI type for SPE and NSPE
============================
@@ -65,6 +71,12 @@
FP software ABI type is default in TF-M.
+.. Note::
+ If you build TF-M SPE with ``CONFIG_TFM_FP=hard`` and provide your own NSPE
+ application, your own NSPE **must** take care of enabling floating point
+ coprocessors CP10 and CP11 on the NS side to avoid aforementioned NOCP usage
+ fault.
+
* ``CONFIG_TFM_LAZY_STACKING`` is used to enable/disable lazy stacking
feature. This feature is only valid for FP hardware ABI type.
NSPE is not allowed to enable/disable this feature. Let SPE decide the
diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt
index 236624d..fd70a52 100755
--- a/platform/CMakeLists.txt
+++ b/platform/CMakeLists.txt
@@ -94,6 +94,7 @@
$<$<STREQUAL:${CONFIG_TFM_FP},hard>:CONFIG_TFM_FP=2>
$<$<STREQUAL:${CONFIG_TFM_FP},soft>:CONFIG_TFM_FP=0>
$<$<BOOL:${CONFIG_TFM_LAZY_STACKING}>:CONFIG_TFM_LAZY_STACKING>
+ $<$<BOOL:${CONFIG_TFM_ENABLE_FPU}>:CONFIG_TFM_ENABLE_FPU>
PRIVATE
$<$<BOOL:${SYMMETRIC_INITIAL_ATTESTATION}>:SYMMETRIC_INITIAL_ATTESTATION>
$<$<OR:$<VERSION_GREATER:${TFM_ISOLATION_LEVEL},1>,$<STREQUAL:"${TEST_PSA_API}","IPC">>:CONFIG_TFM_ENABLE_MEMORY_PROTECT>
@@ -132,6 +133,7 @@
$<$<STREQUAL:${CONFIG_TFM_FP},hard>:CONFIG_TFM_FP=2>
$<$<STREQUAL:${CONFIG_TFM_FP},soft>:CONFIG_TFM_FP=0>
$<$<BOOL:${TEST_NS_FPU}>:TEST_NS_FPU>
+ $<$<BOOL:${CONFIG_TFM_ENABLE_FPU}>:CONFIG_TFM_ENABLE_FPU>
PRIVATE
$<$<BOOL:${TEST_NS_SLIH_IRQ}>:TEST_NS_SLIH_IRQ>
)
diff --git a/secure_fw/spm/cmsis_func/arch.c b/secure_fw/spm/cmsis_func/arch.c
index 9713370..0264b46 100644
--- a/secure_fw/spm/cmsis_func/arch.c
+++ b/secure_fw/spm/cmsis_func/arch.c
@@ -262,39 +262,51 @@
void tfm_arch_config_extensions(void)
{
+/*
+ * Note: The following applies to Armv8-M Mainline, as older architectures do
+ * not support the function based model and Armv8-M Baseline does not provide
+ * an FPU.
+ */
#if defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)
- /* Configure Secure access to the FPU only if the secure image is being
- * built with the FPU in use. This avoids introducing extra interrupt
- * latency when the FPU is not used by the SPE.
+
+#if defined(CONFIG_TFM_ENABLE_FPU)
+ /*
+ * Enable Secure privileged and unprivilged access to the FP Extension.
+ * Note: On Armv8-M, if Non-Secure access to the FPU is needed, Secure access
+ * to the FPU must be enabled first in order to avoid No Coprocessor (NOCP)
+ * usage fault when a Non-secure to Secure service call is interrupted while
+ * CONTROL.FPCA=1 is set by Non-Secure. This is needed even if the SPE will not
+ * use the FPU directly.
*/
-#if defined(__FPU_USED) && (__FPU_USED == 1U)
- /* Enable Secure privileged and unprivilged access to the FP Extension */
SCB->CPACR |= (3U << 10U*2U) /* enable CP10 full access */
| (3U << 11U*2U); /* enable CP11 full access */
-#if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
- /* If the SPE will ever use the floating-point registers for sensitive data,
+ /*
+ * Permit Non-secure access to the Floating-point Extension.
+ * Note: It is still necessary to set CPACR_NS to enable the FP Extension in
+ * the NSPE. This configuration is left to the NS privileged software.
+ */
+ SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk;
+#endif
+
+#if (defined(__FPU_USED) && (__FPU_USED == 1U))
+ /*
+ * If the SPE will ever use the floating-point registers for sensitive data,
* then FPCCR.TS, FPCCR.CLRONRET and FPCCR.CLRONRETS must be set at
- * initialisation and not changed again afterwards.
+ * initialization and not changed again afterwards. This is not needed
+ * if the SPE will never use floating-point but enables FPU only for
+ * avoiding NOCP faults during interrupted NSPE to SPE calls.
*/
FPU->FPCCR |= FPU_FPCCR_TS_Msk
| FPU_FPCCR_CLRONRET_Msk
| FPU_FPCCR_CLRONRETS_Msk;
#endif
-#endif
-
-#if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
- /* Permit Non-secure access to the Floating-point Extension.
- * Note: It is still necessary to set CPACR_NS to enable the FP Extension in
- * the NSPE. This configuration is left to NS privileged software.
- */
- SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk;
-#endif
#if defined(__ARM_ARCH_8_1M_MAIN__)
SCB->CCR |= SCB_CCR_TRD_Msk;
#endif
-#endif
+
+#endif /* __FPU_PRESENT */
}
#if defined(__ARM_ARCH_8M_BASE__) || \
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
index 2f04b30..d2e90a2 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
@@ -190,7 +190,7 @@
{
/* There are no coprocessors in Armv6-M implementations */
#ifndef __ARM_ARCH_6M__
-#if defined(__FPU_USED) && (__FPU_USED == 1U)
+#if defined(CONFIG_TFM_ENABLE_FPU)
/* Enable privileged and unprivilged access to the floating-point
* coprocessor.
*/
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
index 7d706a9..242776a 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
@@ -210,13 +210,28 @@
void tfm_arch_config_extensions(void)
{
-#if (CONFIG_TFM_FP >= 1)
-#ifdef __GNUC__
- /* Enable SPE privileged and unprivileged access to the FP Extension */
+#if defined(CONFIG_TFM_ENABLE_FPU)
+ /*
+ * Enable SPE privileged and unprivileged access to the FP Extension.
+ * Note: On Armv8-M, if Non-secure access to the FPU is needed, Secure
+ * access to the FPU must be enabled first in order to avoid No Coprocessor
+ * (NOCP) usage fault when a Non-secure to Secure service call is
+ * interrupted while CONTROL.FPCA=1 is set by Non-secure. This is needed
+ * even if SPE will not use the FPU directly.
+ */
SCB->CPACR |= (3U << 10U*2U) /* enable CP10 full access */
| (3U << 11U*2U); /* enable CP11 full access */
+
+ /*
+ * Permit Non-secure access to the Floating-point Extension.
+ * Note: It is still necessary to set CPACR_NS to enable the FP Extension
+ * in the NSPE. This configuration is left to NS privileged software.
+ */
+ SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk;
#endif
+#if (CONFIG_TFM_FP >= 1)
+
#ifdef CONFIG_TFM_LAZY_STACKING
/* Enable lazy stacking. */
FPU->FPCCR |= FPU_FPCCR_LSPEN_Msk;
@@ -225,11 +240,14 @@
FPU->FPCCR &= ~FPU_FPCCR_LSPEN_Msk;
#endif
- /* If the SPE will ever use the floating-point registers for sensitive
+ /*
+ * If the SPE will ever use the floating-point registers for sensitive
* data, then FPCCR.ASPEN, FPCCR.TS, FPCCR.CLRONRET and FPCCR.CLRONRETS
* must be set at initialisation and not changed again afterwards.
* Let SPE decide the S/NS shared setting (LSPEN and CLRONRET) to avoid the
- * possible side-path brought by flexibility.
+ * possible side-path brought by flexibility. This is not needed
+ * if the SPE will never use floating-point but enables the FPU only for
+ * avoiding NOCP faults during interrupted NSPE to SPE calls.
*/
FPU->FPCCR |= FPU_FPCCR_ASPEN_Msk
| FPU_FPCCR_TS_Msk
@@ -237,12 +255,6 @@
| FPU_FPCCR_CLRONRETS_Msk
| FPU_FPCCR_LSPENS_Msk;
- /* Permit Non-secure access to the Floating-point Extension.
- * Note: It is still necessary to set CPACR_NS to enable the FP Extension
- * in the NSPE. This configuration is left to NS privileged software.
- */
- SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk;
-
/* Prevent non-secure from modifying FPU’s power setting. */
SCnSCB->CPPWR |= SCnSCB_CPPWR_SUS11_Msk | SCnSCB_CPPWR_SUS10_Msk;
#endif /* CONFIG_TFM_FP >= 1 */