Core: thread mode transition for IPC calls

Align NS IPC calls with thread mode NS-S transition
changes

Change-Id: Ifbc4a5229ee0400bde9755d2964bcf82e8fcfca2
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/interface/include/tfm_ns_psa_svc.h b/interface/include/tfm_ns_psa_svc.h
deleted file mode 100644
index a1032f6..0000000
--- a/interface/include/tfm_ns_psa_svc.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __TFM_NS_PSA_SVC_H__
-#define __TFM_NS_PSA_SVC_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "interface/include/psa_client.h"
-
-uint32_t tfm_psa_ns_version(uint32_t sid);
-
-psa_handle_t tfm_psa_ns_connect(uint32_t sid, uint32_t minor_version);
-
-psa_error_t tfm_psa_ns_call(psa_handle_t handle,
-                            const psa_invec *in_vecs,
-                            const psa_invec *out_vecs);
-
-psa_error_t tfm_psa_ns_close(psa_handle_t handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __TFM_NS_PSA_SVC_H__ */
diff --git a/interface/src/tfm_psa_ns_api.c b/interface/src/tfm_psa_ns_api.c
index 80c3af8..45e8082 100644
--- a/interface/src/tfm_psa_ns_api.c
+++ b/interface/src/tfm_psa_ns_api.c
@@ -35,6 +35,10 @@
                      const psa_outvec *out_vec,
                      size_t out_len)
 {
+    /* FixMe: sanity check can be added to offload some NS thread checks from
+     * TFM secure API
+     */
+
     /* Due to v8M restrictions, TF-M NS API needs to add another layer of
      * serialization in order for NS to pass arguments to S
      */
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index 88ac443..2b7ce44 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -21,6 +21,9 @@
  * buffer area
  */
 extern int32_t tfm_core_set_buffer_area_handler(const uint32_t args[]);
+#ifdef TFM_PSA_API
+extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
+#endif
 
 struct tfm_fault_context_s {
     uint32_t R0;
@@ -171,6 +174,11 @@
     case TFM_SVC_SET_SHARE_AREA:
         tfm_core_set_buffer_area_handler(svc_args);
         break;
+#ifdef TFM_PSA_API
+    case TFM_SVC_IPC_REQUEST:
+        tfm_psa_ipc_request_handler(svc_args);
+        break;
+#endif
     case TFM_SVC_PRINT:
         printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
         break;
diff --git a/secure_fw/core/tfm_psa_api_client.c b/secure_fw/core/tfm_psa_api_client.c
index 963ae4a..e7673e2 100644
--- a/secure_fw/core/tfm_psa_api_client.c
+++ b/secure_fw/core/tfm_psa_api_client.c
@@ -18,16 +18,9 @@
 extern int32_t tfm_secure_lock;
 
 __attribute__ ((always_inline)) __STATIC_INLINE
-int32_t tfm_psa_veneer_sanity_check(void)
+int32_t tfm_psa_veneer_sanity_check(struct tfm_sfn_req_s *desc_ptr)
 {
-    int32_t ns_caller = cmse_nonsecure_caller();
-    uint32_t exc_num = __get_active_exc_num();
-
-    if (exc_num != EXC_NUM_SVCALL) {
-        return TFM_ERROR_INVALID_EXC_MODE;
-    }
-
-    if (ns_caller) {
+    if (desc_ptr->ns_caller) {
         if (tfm_secure_lock != 0) {
             /* Secure domain is already locked!
              * FixMe: Decide if this is a fault or permitted in case of PSA
@@ -46,25 +39,56 @@
 
 /* Veneer implementation */
 
+#define TFM_CORE_NS_IPC_REQUEST_VENEER(fn, a, b, c, d) \
+            return tfm_core_ns_ipc_request(fn, (int32_t)a, (int32_t)b, \
+                (int32_t)c, (int32_t)d)
+
+__attribute__ ((always_inline)) __STATIC_INLINE
+int32_t tfm_core_ns_ipc_request(void *fn, int32_t arg1, int32_t arg2,
+                                int32_t arg3, int32_t arg4)
+{
+    int32_t args[4] = {arg1, arg2, arg3, arg4};
+    struct tfm_sfn_req_s desc, *desc_ptr = &desc;
+    int32_t res;
+
+    desc.sfn = fn;
+    desc.args = args;
+    desc.ns_caller = cmse_nonsecure_caller();
+
+    if (__get_active_exc_num() != EXC_NUM_THREAD_MODE)
+    {
+        /* FIXME: Proper error handling to be implemented */
+        return TFM_ERROR_INVALID_EXC_MODE;
+    } else {
+        __ASM("MOV r0, %1\n"
+              "SVC %2\n"
+              "MOV %0, r0\n"
+              : "=r" (res)
+              : "r" (desc_ptr), "I" (TFM_SVC_IPC_REQUEST)
+              : "r0");
+        return res;
+    }
+}
+
 /* FixMe: these functions need to have different attributes compared to those
  * legacy veneers which may be called by secure partitions.
  * They won't call legacy SFN but instead will be handlers for TF-M
  */
 
-__tfm_secure_gateway_attributes__
-uint32_t tfm_psa_version_veneer(uint32_t sid)
+uint32_t tfm_psa_version_handler(uint32_t sid)
 {
     /* perform sanity check */
-    /* FixMe: pattern should follow guides on tfm core veneer return values */
-    if(tfm_psa_veneer_sanity_check() != TFM_SUCCESS) {
-        return PSA_VERSION_NONE;
-    }
     /* return version number registered in manifest for given SID */
     return PSA_VERSION_NONE;
 }
 
 __tfm_secure_gateway_attributes__
-psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
+uint32_t tfm_psa_version_veneer(uint32_t sid)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_psa_version_handler, sid, 0, 0, 0);
+}
+
+psa_handle_t tfm_psa_connect_handler(uint32_t sid, uint32_t minor_version)
 {
     /* perform sanity check */
     /* decide whether a connection can be established to a given SID.
@@ -86,7 +110,13 @@
 }
 
 __tfm_secure_gateway_attributes__
-psa_error_t tfm_psa_call_veneer(psa_handle_t handle,
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_psa_connect_handler, sid, minor_version,
+                                   0, 0);
+}
+
+psa_error_t tfm_psa_call_handler(psa_handle_t handle,
                     const psa_invec *in_vecs,
                     const psa_invec *out_vecs)
 {
@@ -105,7 +135,15 @@
 }
 
 __tfm_secure_gateway_attributes__
-psa_error_t tfm_psa_close_veneer(psa_handle_t handle)
+psa_error_t tfm_psa_call_veneer(psa_handle_t handle,
+                    const psa_invec *in_vecs,
+                    const psa_invec *out_vecs)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_psa_call_handler, handle, in_vecs,
+                                   out_vecs, 0);
+}
+
+psa_error_t tfm_psa_close_handler(psa_handle_t handle)
 {
     /* perform sanity check */
     /* Close connection referenced by handle */
@@ -116,3 +154,31 @@
     tfm_thread_schedule();
     return TFM_SUCCESS;
 }
+
+__tfm_secure_gateway_attributes__
+psa_error_t tfm_psa_close_veneer(psa_handle_t handle)
+{
+    TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_psa_close_handler, handle, 0, 0, 0);
+}
+
+void tfm_psa_ipc_request_handler(uint32_t svc_ctx[])
+{
+    uint32_t *r0_ptr = svc_ctx;
+
+    /* The only argument to the SVC call is stored in the stacked r0 */
+    struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) *r0_ptr;
+
+    if(tfm_psa_veneer_sanity_check(desc_ptr) != TFM_SUCCESS) {
+        /* FixMe: consider error handling - this may be critical error */
+        *r0_ptr = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    /* Store SVC return value in stacked r0 */
+    *r0_ptr = desc_ptr->sfn(desc_ptr->args[0],
+                            desc_ptr->args[1],
+                            desc_ptr->args[2],
+                            desc_ptr->args[3]);
+
+    return;
+}
diff --git a/secure_fw/core/tfm_svc.h b/secure_fw/core/tfm_svc.h
index 60c9ac8..4fa241a 100644
--- a/secure_fw/core/tfm_svc.h
+++ b/secure_fw/core/tfm_svc.h
@@ -20,6 +20,9 @@
     TFM_SVC_SPM_REQUEST,
     TFM_SVC_PRINT,
     TFM_SVC_GET_BOOT_DATA,
+#ifdef TFM_PSA_API
+    TFM_SVC_IPC_REQUEST,
+#endif
 } tfm_svc_number_t;
 
 #define SVC(code) __ASM("svc %0" : : "I" (code))