SPM: Add fault injection protection support in Library model

Create a reference implementation of fault injection protection in
Library model SPM initialization.

Signed-off-by: Tamas Ban <tamas.ban@arm.com>
Co-authorized-by: David Hu <david.hu@arm.com>
Change-Id: Ifa4a83bfb9a43de785cee27a13a783a52cf47c7c
diff --git a/secure_fw/spm/CMakeLists.txt b/secure_fw/spm/CMakeLists.txt
index 655d57b..fc661de 100755
--- a/secure_fw/spm/CMakeLists.txt
+++ b/secure_fw/spm/CMakeLists.txt
@@ -86,6 +86,7 @@
         $<$<STREQUAL:${TEST_PSA_API},IPC>:tfm_psa_rot_partition_driver_partition>
         $<$<STREQUAL:${TEST_PSA_API},IPC>:tfm_app_rot_partition_client_partition>
         $<$<STREQUAL:${TEST_PSA_API},IPC>:tfm_app_rot_partition_server_partition>
+        $<$<NOT:$<BOOL:${TFM_PSA_API}>>:tfm_fih>
 )
 
 target_compile_definitions(tfm_spm
diff --git a/secure_fw/spm/cmsis_func/include/spm_func.h b/secure_fw/spm/cmsis_func/include/spm_func.h
index 1ffe943..88d2f7d 100644
--- a/secure_fw/spm/cmsis_func/include/spm_func.h
+++ b/secure_fw/spm/cmsis_func/include/spm_func.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -9,6 +9,7 @@
 #define __SPM_FUNC_H__
 
 #include <stdint.h>
+#include "fih.h"
 #include "spm_partition_defs.h"
 #include "tfm_arch.h"
 #include "psa/client.h"
@@ -43,11 +44,12 @@
 
 enum spm_err_t {
     SPM_ERR_OK = 0,
-    SPM_ERR_PARTITION_DB_NOT_INIT,
-    SPM_ERR_PARTITION_ALREADY_ACTIVE,
-    SPM_ERR_PARTITION_NOT_AVAILABLE,
-    SPM_ERR_INVALID_PARAMETER,
-    SPM_ERR_INVALID_CONFIG,
+    SPM_ERR_PARTITION_DB_NOT_INIT = 0x3A5C,
+    SPM_ERR_PARTITION_ALREADY_ACTIVE = 0x5C3A,
+    SPM_ERR_PARTITION_NOT_AVAILABLE = 0xA35C,
+    SPM_ERR_INVALID_PARAMETER = 0xCA35,
+    SPM_ERR_INVALID_CONFIG = 0x35A3C,
+    SPM_ERR_GENERIC_ERR = 0x5C3A5,
 };
 
 /**
@@ -237,9 +239,11 @@
 /**
  * \brief Execute partition init function
  *
- * \return Error code \ref spm_err_t
+ * \return Error code \ref spm_err_t.
+ *         When FIH_ENABLE_DOUBLE_VARS is enabled, the return code will be
+ *         wrapped and protected in \ref fih_int structure.
  */
-enum spm_err_t tfm_spm_partition_init(void);
+fih_int tfm_spm_partition_init(void);
 
 /**
  * \brief Clears the context info from the database for a partition.
diff --git a/secure_fw/spm/cmsis_func/main.c b/secure_fw/spm/cmsis_func/main.c
index 5695279..2a809dd 100644
--- a/secure_fw/spm/cmsis_func/main.c
+++ b/secure_fw/spm/cmsis_func/main.c
@@ -6,6 +6,7 @@
  */
 
 #include "arch.h"
+#include "fih.h"
 #include "ffm/tfm_boot_data.h"
 #include "region.h"
 #include "spm_func.h"
@@ -34,44 +35,61 @@
 
 REGION_DECLARE(Image$$, ARM_LIB_STACK_MSP,  $$ZI$$Base);
 
-static int32_t tfm_core_init(void)
+static fih_int tfm_core_init(void)
 {
     size_t i;
     enum tfm_hal_status_t hal_status = TFM_HAL_ERROR_GENERIC;
     enum tfm_plat_err_t plat_err = TFM_PLAT_ERR_SYSTEM_ERR;
     enum irq_target_state_t irq_target_state = TFM_IRQ_TARGET_STATE_SECURE;
+#ifdef TFM_FIH_PROFILE_ON
+    fih_int fih_rc = FIH_FAILURE;
+#endif
 
     /* Enables fault handlers */
     plat_err = tfm_spm_hal_enable_fault_handlers();
     if (plat_err != TFM_PLAT_ERR_SUCCESS) {
-        return TFM_ERROR_GENERIC;
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
     }
 
     /* Configures the system reset request properties */
     plat_err = tfm_spm_hal_system_reset_cfg();
     if (plat_err != TFM_PLAT_ERR_SUCCESS) {
-        return TFM_ERROR_GENERIC;
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
     }
 
     /* Configures debug authentication */
+#ifdef TFM_FIH_PROFILE_ON
+    FIH_CALL(tfm_spm_hal_init_debug, fih_rc);
+    if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+    }
+#else /* TFM_FIH_PROFILE_ON */
     plat_err = tfm_spm_hal_init_debug();
     if (plat_err != TFM_PLAT_ERR_SUCCESS) {
         return TFM_ERROR_GENERIC;
     }
+#endif /* TFM_FIH_PROFILE_ON */
 
     /*
      * Access to any peripheral should be performed after programming
      * the necessary security components such as PPC/SAU.
      */
+#ifdef TFM_FIH_PROFILE_ON
+    FIH_CALL(tfm_hal_set_up_static_boundaries, fih_rc);
+    if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
+    }
+#else /* TFM_FIH_PROFILE_ON */
     hal_status = tfm_hal_set_up_static_boundaries();
     if (hal_status != TFM_HAL_SUCCESS) {
         return TFM_ERROR_GENERIC;
     }
+#endif /* TFM_FIH_PROFILE_ON */
 
     /* Performs platform specific initialization */
     hal_status = tfm_hal_platform_init();
     if (hal_status != TFM_HAL_SUCCESS) {
-        return TFM_ERROR_GENERIC;
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
     }
 
     /* Configures architecture */
@@ -90,7 +108,7 @@
      */
     plat_err = tfm_spm_hal_nvic_interrupt_target_state_cfg();
     if (plat_err != TFM_PLAT_ERR_SUCCESS) {
-        return TFM_ERROR_GENERIC;
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
     }
 
     for (i = 0; i < tfm_core_irq_signals_count; ++i) {
@@ -98,27 +116,30 @@
                                           tfm_core_irq_signals[i].irq_line,
                                           tfm_core_irq_signals[i].irq_priority);
         if (plat_err != TFM_PLAT_ERR_SUCCESS) {
-            return TFM_ERROR_GENERIC;
+            FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
         }
         irq_target_state = tfm_spm_hal_set_irq_target_state(
                                           tfm_core_irq_signals[i].irq_line,
                                           TFM_IRQ_TARGET_STATE_SECURE);
         if (irq_target_state != TFM_IRQ_TARGET_STATE_SECURE) {
-            return TFM_ERROR_GENERIC;
+            FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
         }
     }
 
     /* Enable secure peripherals interrupts */
     plat_err = tfm_spm_hal_nvic_interrupt_enable();
     if (plat_err != TFM_PLAT_ERR_SUCCESS) {
-        return TFM_ERROR_GENERIC;
+        FIH_RET(fih_int_encode(TFM_ERROR_GENERIC));
     }
 
-    return TFM_SUCCESS;
+    FIH_RET(fih_int_encode(TFM_SUCCESS));
 }
 
 int main(void)
 {
+    enum spm_err_t spm_err = SPM_ERR_GENERIC_ERR;
+    fih_int fih_rc = FIH_FAILURE;
+
     /* set Main Stack Pointer limit */
     tfm_arch_init_secure_msp((uint32_t)&REGION_NAME(Image$$,
                                                     ARM_LIB_STACK_MSP,
@@ -127,13 +148,18 @@
     /* Seal the PSP stacks viz ARM_LIB_STACK and TFM_SECURE_STACK */
     tfm_spm_seal_psp_stacks();
 
-    if (tfm_core_init() != TFM_SUCCESS) {
+    fih_delay_init();
+
+    FIH_CALL(tfm_core_init, fih_rc);
+    if (fih_not_eq(fih_rc, fih_int_encode(TFM_SUCCESS))) {
         tfm_core_panic();
     }
+
     /* Print the TF-M version */
     SPMLOG_INFMSG("\033[1;34mBooting TFM v"VERSION_FULLSTR"\033[0m\r\n");
 
-    if (tfm_spm_db_init() != SPM_ERR_OK) {
+    spm_err = tfm_spm_db_init();
+    if (spm_err != SPM_ERR_OK) {
         tfm_core_panic();
     }
 
@@ -145,7 +171,8 @@
 
     tfm_arch_set_psplim(psp_stack_bottom);
 
-    if (tfm_spm_partition_init() != SPM_ERR_OK) {
+    FIH_CALL(tfm_spm_partition_init, fih_rc);
+    if (fih_not_eq(fih_rc, fih_int_encode(SPM_ERR_OK))) {
         /* Certain systems might refuse to boot altogether if partitions fail
          * to initialize. This is a placeholder for such an error handler
          */
@@ -164,6 +191,13 @@
     tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
                                 SPM_PARTITION_STATE_RUNNING);
 
+#ifdef TFM_FIH_PROFILE_ON
+    FIH_CALL(tfm_spm_hal_verify_isolation_hw, fih_rc);
+    if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
+        tfm_core_panic();
+    }
+#endif
+
 #ifdef TFM_CORE_DEBUG
     /* Jumps to non-secure code */
     SPMLOG_DBGMSG("\033[1;34mJumping to non-secure code...\033[0m\r\n");
diff --git a/secure_fw/spm/cmsis_func/spm_func.c b/secure_fw/spm/cmsis_func/spm_func.c
index da107f3..b85463f 100644
--- a/secure_fw/spm/cmsis_func/spm_func.c
+++ b/secure_fw/spm/cmsis_func/spm_func.c
@@ -9,6 +9,7 @@
 #include <stdbool.h>
 #include <arm_cmse.h>
 #include "bitops.h"
+#include "fih.h"
 #include "tfm_nspm.h"
 #include "tfm_api.h"
 #include "tfm_arch.h"
@@ -1216,14 +1217,17 @@
     tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_CLOSED);
 }
 
-enum spm_err_t tfm_spm_partition_init(void)
+fih_int tfm_spm_partition_init(void)
 {
     struct spm_partition_desc_t *part;
     struct tfm_sfn_req_s desc;
     int32_t args[4] = {0};
-    int32_t fail_cnt = 0;
+    fih_int fail_cnt = FIH_INT_INIT(0);
     uint32_t idx;
     const struct platform_data_t **platform_data_p;
+#ifdef TFM_FIH_PROFILE_ON
+    fih_int fih_rc = FIH_FAILURE;
+#endif
 
     /* Call the init function for each partition */
     for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
@@ -1231,10 +1235,18 @@
         platform_data_p = part->platform_data_list;
         if (platform_data_p != NULL) {
             while ((*platform_data_p) != NULL) {
+#ifdef TFM_FIH_PROFILE_ON
+                FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc, idx,
+                         *platform_data_p);
+                if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
+                    fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
+                }
+#else /* TFM_FIH_PROFILE_ON */
                 if (tfm_spm_hal_configure_default_isolation(idx,
                             *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
                     fail_cnt++;
                 }
+#endif /* TFM_FIH_PROFILE_ON */
                 ++platform_data_p;
             }
         }
@@ -1254,18 +1266,19 @@
                 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
             } else {
                 tfm_spm_partition_err_handler(idx, res);
-                fail_cnt++;
+                fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
             }
         }
     }
 
     tfm_spm_secure_api_init_done();
 
-    if (fail_cnt == 0) {
-        return SPM_ERR_OK;
-    } else {
-        return SPM_ERR_PARTITION_NOT_AVAILABLE;
+    fih_int_validate(fail_cnt);
+    if (fih_eq(fail_cnt, fih_int_encode(0))) {
+        FIH_RET(fih_int_encode(SPM_ERR_OK));
     }
+
+    FIH_RET(fih_int_encode(SPM_ERR_PARTITION_NOT_AVAILABLE));
 }
 
 void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
diff --git a/secure_fw/spm/ffm/utilities.c b/secure_fw/spm/ffm/utilities.c
index 98a3e19..e3f3697 100644
--- a/secure_fw/spm/ffm/utilities.c
+++ b/secure_fw/spm/ffm/utilities.c
@@ -1,15 +1,18 @@
 /*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
  */
 #include <inttypes.h>
+#include "fih.h"
 #include "utilities.h"
 #include "tfm_hal_platform.h"
 
 void tfm_core_panic(void)
 {
+    fih_delay();
+
     /*
      * FixMe: In the first stage, the SPM will restart the entire system when a
      * programmer error is detected in either the SPE or NSPE.
@@ -19,4 +22,10 @@
      * functionality for terminating an execution context.
      */
     tfm_hal_system_reset();
+
+#ifdef TFM_FIH_PROFILE_ON
+    fih_delay();
+
+    tfm_hal_system_reset();
+#endif
 }