SPM: Move SPM processing in Library mode to Secure Privileged Thread

This patch moves the bulk of SPM processing in Library mode
to request or return from a secure partition from Handler
to Secure Privileged Thread mode.

Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: I95b61661daa3a8e865b468e91be9a512832607a2
diff --git a/secure_fw/spm/cmsis_func/arch.c b/secure_fw/spm/cmsis_func/arch.c
index 9d45336..8a2310f 100644
--- a/secure_fw/spm/cmsis_func/arch.c
+++ b/secure_fw/spm/cmsis_func/arch.c
@@ -57,6 +57,15 @@
 }
 
 __attribute__((naked))
+void tfm_sfn_completion(enum tfm_status_e res, uint32_t exc_return, uintptr_t msp)
+{
+    __ASM volatile("MSR msp, %0\n"
+                   "SVC %1\n"
+                   "BX LR\n"
+                   : : "r" (msp), "I" (TFM_SVC_SFN_COMPLETION) : );
+}
+
+__attribute__((naked))
 static psa_signal_t psa_wait_internal(psa_signal_t signal_mask,
                                       uint32_t timeout)
 {
@@ -84,6 +93,12 @@
 }
 
 __attribute__((naked))
+void tfm_arch_trigger_exc_return(uint32_t exc_return)
+{
+    __ASM volatile("BX R0");
+}
+
+__attribute__((naked))
 void psa_eoi(psa_signal_t irq_signal)
 {
     __ASM("SVC %0\n"
diff --git a/secure_fw/spm/cmsis_func/arch.h b/secure_fw/spm/cmsis_func/arch.h
index 964ddf7..c483d7c 100644
--- a/secure_fw/spm/cmsis_func/arch.h
+++ b/secure_fw/spm/cmsis_func/arch.h
@@ -1,9 +1,11 @@
 /*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
  */
+#include <stdint.h>
+#include "tfm_api.h"
 
 #ifndef __ARCH_H__
 #define __ARCH_H__
@@ -24,4 +26,27 @@
  */
 void jump_to_ns_code(void);
 
+/**
+ * \brief Trigger EXC_RETURN
+ *
+ * \param[in] exc_return The EXC_RETURN value to initiate the return
+ *                       procedure
+ *
+ * \returns              Does not return
+ */
+void tfm_arch_trigger_exc_return(uint32_t exc_return);
+
+/**
+ * \brief Trigger an sfn request/return completion from Thread mode
+ *
+ * \param[in] res        The tfm_status_e return value to report back to SPM
+ * \param[in] exc_return The EXC_RETURN value to use to return from the original
+ *                       request/return
+ * \param[in] msp        The value of the top of the MSP to reset the MSP before
+ *                       trigger the TFM_SVC_SFN_COMPLETION
+ *
+ * \return               Does not return
+ */
+void tfm_sfn_completion(enum tfm_status_e res, uint32_t exc_return, uintptr_t msp);
+
 #endif /* __ARCH_H__ */
diff --git a/secure_fw/spm/cmsis_func/include/spm_func.h b/secure_fw/spm/cmsis_func/include/spm_func.h
index 2fbaa25..568b456 100644
--- a/secure_fw/spm/cmsis_func/include/spm_func.h
+++ b/secure_fw/spm/cmsis_func/include/spm_func.h
@@ -13,6 +13,7 @@
 #include "spm_partition_defs.h"
 #include "tfm_arch.h"
 #include "psa/client.h"
+#include "tfm_api.h"
 
 #define SPM_PARTITION_STATE_UNINIT       0
 #define SPM_PARTITION_STATE_IDLE         1
@@ -271,16 +272,17 @@
 void tfm_spm_secure_api_init_done(void);
 
 /**
- * \brief Called if veneer is running in thread mode
+ * \brief Called for requests or returns from partition
  */
-uint32_t tfm_spm_partition_request_svc_handler(
-        const uint32_t *svc_args, uint32_t lr);
+void tfm_spm_partition_request_return_handler(
+        const uint32_t *svc_args, uint32_t exc_return, uint32_t *msp);
 
 /**
- * \brief Called when secure service returns
+ * \brief Called when SPM has completed a partition request or return
  */
-uint32_t tfm_spm_partition_return_handler(uint32_t lr);
-
+void tfm_spm_partition_completion_handler(enum tfm_status_e res,
+                                          uint32_t exc_return,
+                                          uint32_t *msp);
 /**
  * \brief Stores caller's client id in state context
  */
diff --git a/secure_fw/spm/cmsis_func/include/tfm_core_svc.h b/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
index 1c06a33..ce4eed8 100644
--- a/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
+++ b/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
@@ -15,6 +15,7 @@
 #define TFM_SVC_PSA_EOI                 (0x1)
 #define TFM_SVC_SFN_REQUEST             (0x2)
 #define TFM_SVC_SFN_RETURN              (0x3)
+#define TFM_SVC_SFN_COMPLETION          (0x4)
 #define TFM_SVC_SPM_REQUEST             (0x5)
 #define TFM_SVC_GET_BOOT_DATA           (0x6)
 #define TFM_SVC_DEPRIV_REQ              (0x7)
diff --git a/secure_fw/spm/cmsis_func/spm_func.c b/secure_fw/spm/cmsis_func/spm_func.c
index 443ea02..53bebfd 100644
--- a/secure_fw/spm/cmsis_func/spm_func.c
+++ b/secure_fw/spm/cmsis_func/spm_func.c
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <arm_cmse.h>
+#include "arch.h"
 #include "bitops.h"
 #include "fih.h"
 #include "tfm_nspm.h"
@@ -789,7 +790,7 @@
     tfm_secure_api_initializing = 0;
 }
 
-enum tfm_status_e tfm_spm_sfn_request_handler(
+static enum tfm_status_e tfm_spm_sfn_request_handler(
                              struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
 {
     enum tfm_status_e res;
@@ -900,13 +901,30 @@
     return TFM_ERROR_INVALID_PARAMETER;
 }
 
-/* This SVC handler is called if veneer is running in thread mode */
-uint32_t tfm_spm_partition_request_svc_handler(
-        const uint32_t *svc_ctx, uint32_t excReturn)
+static void tfm_spm_partition_requests_thread(struct tfm_sfn_req_s *desc_ptr,
+                                              uint32_t exc_return,
+                                              uint32_t is_return,
+                                              uintptr_t msp)
 {
-    struct tfm_sfn_req_s *desc_ptr;
+    enum tfm_status_e res;
+    uint32_t exc_ret;
 
-    if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
+    if (!is_return) {
+        res = tfm_spm_sfn_request_handler(desc_ptr, exc_return);
+        exc_ret = EXC_RETURN_SECURE_FUNCTION;
+    } else {
+        res = tfm_return_from_partition(&exc_return);
+        exc_ret = exc_return;
+    }
+    /* Reset MSP at top of stack and do TFM_SVC_SFN_COMPLETION */
+    tfm_sfn_completion(res, exc_ret, msp);
+}
+
+/* This SVC handler is called if veneer is running in thread mode */
+void tfm_spm_partition_request_return_handler(
+        const uint32_t *svc_ctx, uint32_t exc_return, uint32_t *msp)
+{
+    if (!(exc_return & EXC_RETURN_STACK_PROCESS)) {
         /* Service request SVC called with MSP active.
          * Either invalid configuration for Thread mode or SVC called
          * from Handler mode, which is not supported.
@@ -916,13 +934,30 @@
         tfm_secure_api_error_handler();
     }
 
-    desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
+    /* Setup a context on the stack to trigger exception return */
+    struct tfm_state_context_t ctx = {0};
 
-    if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
+    ctx.r0 = svc_ctx ? svc_ctx[0] : (uintptr_t) NULL;
+    ctx.r1 = exc_return;
+    ctx.r2 = svc_ctx ? 0 : 1;
+    ctx.r3 = (uintptr_t) msp;
+    ctx.xpsr = XPSR_T32;
+    ctx.ra = (uint32_t) tfm_spm_partition_requests_thread & ~0x1UL;
+
+    __set_MSP((uint32_t)&ctx);
+
+    tfm_arch_trigger_exc_return(EXC_RETURN_THREAD_S_MSP);
+}
+
+void tfm_spm_partition_completion_handler(enum tfm_status_e res, uint32_t exc_return, uint32_t *msp)
+{
+    if (res != TFM_SUCCESS) {
         tfm_secure_api_error_handler();
     }
 
-    return EXC_RETURN_SECURE_FUNCTION;
+    __set_MSP((uint32_t)msp + sizeof(struct tfm_state_context_t));
+
+    tfm_arch_trigger_exc_return(exc_return);
 }
 
 /* This SVC handler is called, if a thread mode execution environment is to
@@ -955,31 +990,6 @@
     return EXC_RETURN_SECURE_FUNCTION;
 }
 
-/* This SVC handler is called when sfn returns */
-uint32_t tfm_spm_partition_return_handler(uint32_t lr)
-{
-    enum tfm_status_e res;
-
-    if (!(lr & EXC_RETURN_STACK_PROCESS)) {
-        /* Partition return SVC called with MSP active.
-         * This should not happen!
-         */
-        ERROR_MSG("Partition return SVC called with MSP active!");
-        tfm_secure_api_error_handler();
-    }
-
-    res = tfm_return_from_partition(&lr);
-    if (res != TFM_SUCCESS) {
-        /* Unlock errors indicate ctx database corruption or unknown anomalies
-         * Halt execution
-         */
-        ERROR_MSG("Secure API error during unlock!");
-        tfm_secure_api_error_handler();
-    }
-
-    return lr;
-}
-
 /* This SVC handler is called if a deprivileged IRQ handler was executed, and
  * the execution environment is to be set back for the privileged handler mode
  */
diff --git a/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c b/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
index a06edc1..e6412a5 100644
--- a/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
+++ b/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
@@ -28,7 +28,6 @@
  */
 #include "tfm_secure_irq_handlers.inc"
 
-
 uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return)
 {
     uint8_t svc_number = 0;
@@ -61,10 +60,13 @@
     }
     switch (svc_number) {
     case TFM_SVC_SFN_REQUEST:
-        retval = tfm_spm_partition_request_svc_handler(svc_args, exc_return);
+        tfm_spm_partition_request_return_handler(svc_args, exc_return, msp);
         break;
     case TFM_SVC_SFN_RETURN:
-        retval = tfm_spm_partition_return_handler(exc_return);
+        tfm_spm_partition_request_return_handler(NULL, exc_return, msp);
+        break;
+    case TFM_SVC_SFN_COMPLETION:
+        tfm_spm_partition_completion_handler(svc_args[0], svc_args[1], msp);
         break;
     case TFM_SVC_SPM_REQUEST:
         tfm_spm_request_handler((struct tfm_state_context_t *)svc_args);
diff --git a/secure_fw/spm/include/tfm_arch.h b/secure_fw/spm/include/tfm_arch.h
index f9b7a3d..8a96d9f 100644
--- a/secure_fw/spm/include/tfm_arch.h
+++ b/secure_fw/spm/include/tfm_arch.h
@@ -36,7 +36,7 @@
     uint32_t    lr;
     uint32_t    ra;
     uint32_t    xpsr;
-};
+} __attribute__ ((aligned(8)));
 
 #define TFM_STATE_RET_VAL(ctx) (((struct tfm_state_context_t *)((ctx)->sp))->r0)
 
diff --git a/secure_fw/spm/include/tfm_arch_v8m.h b/secure_fw/spm/include/tfm_arch_v8m.h
index 58576d3..a51c8c6 100644
--- a/secure_fw/spm/include/tfm_arch_v8m.h
+++ b/secure_fw/spm/include/tfm_arch_v8m.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -21,6 +21,7 @@
 #define EXC_RETURN_FPU_FRAME_BASIC              (1 << 4)
 #define EXC_RETURN_MODE_THREAD                  (1 << 3)
 #define EXC_RETURN_STACK_PROCESS                (1 << 2)
+#define EXC_RETURN_STACK_MAIN                   (0 << 2)
 #define EXC_RETURN_RES0                         (0 << 1)
 #define EXC_RETURN_EXC_SECURE                   (1)
 
@@ -32,6 +33,13 @@
         EXC_RETURN_STACK_PROCESS | EXC_RETURN_RES0 |            \
         EXC_RETURN_EXC_SECURE
 
+#define EXC_RETURN_THREAD_S_MSP                                 \
+        EXC_RETURN_INDICATOR | EXC_RETURN_RES1 |                \
+        EXC_RETURN_SECURE_STACK | EXC_RETURN_STACK_RULE |       \
+        EXC_RETURN_FPU_FRAME_BASIC | EXC_RETURN_MODE_THREAD |   \
+        EXC_RETURN_STACK_MAIN | EXC_RETURN_RES0 |               \
+        EXC_RETURN_EXC_SECURE
+
 #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
 struct tfm_arch_ctx_t {
     uint32_t    r4;