Arch: Add function to configure coprocessors

Adds a function to do architecture-specific coprocessor configuration
and implements it to configure the FPU as appropriate for all supported
architectures.

Change-Id: Ie09b27513b57d561081d10271f2042b5d965b0fd
Signed-off-by: Jamie Fox <jamie.fox@arm.com>
diff --git a/secure_fw/spm/cmsis_func/arch.c b/secure_fw/spm/cmsis_func/arch.c
index f804d4e..d62ce71 100644
--- a/secure_fw/spm/cmsis_func/arch.c
+++ b/secure_fw/spm/cmsis_func/arch.c
@@ -251,6 +251,39 @@
 }
 #endif
 
+void tfm_arch_configure_coprocessors(void)
+{
+#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 (__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,
+     * then FPCCR.TS, FPCCR.CLRONRET and FPCCR.CLRONRETS must be set at
+     * initialisation and not changed again afterwards.
+     */
+    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
+#endif
+}
+
 #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
 __attribute__((naked)) void SVC_Handler(void)
 {
diff --git a/secure_fw/spm/cmsis_func/main.c b/secure_fw/spm/cmsis_func/main.c
index e785587..d6bb304 100644
--- a/secure_fw/spm/cmsis_func/main.c
+++ b/secure_fw/spm/cmsis_func/main.c
@@ -72,6 +72,9 @@
         return TFM_ERROR_GENERIC;
     }
 
+    /* Configures architecture-specific coprocessors */
+    tfm_arch_configure_coprocessors();
+
     LOG_MSG("\033[1;34m[Sec Thread] Secure image initializing!\033[0m\r\n");
 
 #ifdef TFM_CORE_DEBUG
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 34debc6..8b66522 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
@@ -147,6 +147,20 @@
 {
 }
 
+void tfm_arch_configure_coprocessors(void)
+{
+    /* There are no coprocessors in Armv6-M implementations */
+#ifndef __ARM_ARCH_6M__
+#if defined (__FPU_USED) && (__FPU_USED == 1U)
+    /* Enable privileged and unprivilged access to the floating-point
+     * coprocessor.
+     */
+    SCB->CPACR |= (3U << 10U*2U)     /* enable CP10 full access */
+                  | (3U << 11U*2U);  /* enable CP11 full access */
+#endif
+#endif
+}
+
 /* There is no FPCA in v6m */
 #ifndef __ARM_ARCH_6M__
 __attribute__((naked, noinline)) void tfm_arch_clear_fp_status(void)
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
index a05a6ca..29256d7 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
@@ -154,6 +154,11 @@
                  (AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
 }
 
+/* There are no coprocessors in Armv8-M Baseline implementations */
+void tfm_arch_configure_coprocessors(void)
+{
+}
+
 /* There is no FPCA in baseline. */
 void tfm_arch_clear_fp_status(void)
 {
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 718dd91..e363ff8 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
@@ -175,6 +175,35 @@
                  (AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
 }
 
+void tfm_arch_configure_coprocessors(void)
+{
+#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 (__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 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.
+     */
+    FPU->FPCCR |= FPU_FPCCR_TS_Msk
+                  | FPU_FPCCR_CLRONRET_Msk
+                  | FPU_FPCCR_CLRONRETS_Msk;
+#endif
+
+    /* 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
+}
+
 __attribute__((naked, noinline)) void tfm_arch_clear_fp_status(void)
 {
     __ASM volatile(
diff --git a/secure_fw/spm/cmsis_psa/main.c b/secure_fw/spm/cmsis_psa/main.c
index 7fe66e6..39e6c47 100644
--- a/secure_fw/spm/cmsis_psa/main.c
+++ b/secure_fw/spm/cmsis_psa/main.c
@@ -71,6 +71,9 @@
         return TFM_ERROR_GENERIC;
     }
 
+    /* Configures architecture-specific coprocessors */
+    tfm_arch_configure_coprocessors();
+
     LOG_MSG("\033[1;34m[Sec Thread] Secure image initializing!\033[0m\r\n");
 
 #ifdef TFM_CORE_DEBUG
diff --git a/secure_fw/spm/include/tfm_arch.h b/secure_fw/spm/include/tfm_arch.h
index 96251ae..4bf7f16 100644
--- a/secure_fw/spm/include/tfm_arch.h
+++ b/secure_fw/spm/include/tfm_arch.h
@@ -118,6 +118,11 @@
  */
 void tfm_arch_prioritize_secure_exception(void);
 
+/**
+ * \brief Configure coprocessors
+ */
+void tfm_arch_configure_coprocessors(void);
+
 /*
  * Clear float point status.
  */