Core: add PSA client API functions

NS client infrastructure for PSA API created in
conformance with v8M secure gateway call restrictions
and TF-M rules.

Note:
- S SVC handlers TBD
- Buffer read/write funtions TBD
- Sanity checks in S SVC handlers TBD

Change-Id: Ia2947c28247af699d337754db2f22e2e25235c41
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/CommonConfig.cmake b/CommonConfig.cmake
index 964a51c..858126a 100644
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -103,6 +103,8 @@
 set (SERVICES_TEST_ENABLED OFF)
 set (TEST_FRAMEWORK_S  OFF)
 set (TEST_FRAMEWORK_NS OFF)
+set (TFM_PSA_API ON)
+set (TFM_LEGACY_API ON)
 
 if(${TARGET_PLATFORM} STREQUAL "AN521" OR ${TARGET_PLATFORM} STREQUAL "AN519")
 	set (REFERENCE_PLATFORM ON)
@@ -115,6 +117,14 @@
 	set(SERVICES_TEST_ENABLED ON)
 endif()
 
+if (TFM_PSA_API)
+	add_definitions(-DTFM_PSA_API)
+endif()
+
+if (TFM_LEGACY_API)
+	add_definitions(-DTFM_LEGACY_API)
+endif()
+
 if (SERVICES_TEST_ENABLED)
 	set(SERVICE_TEST_S ON)
 	set(SERVICE_TEST_NS ON)
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 59d1713..d7b3665 100755
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -60,6 +60,12 @@
 		)
 endif()
 
+if (NOT DEFINED TFM_PSA_API)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ")
+elseif (TFM_PSA_API)
+	list(APPEND NS_APP_SRC "${INTERFACE_DIR}/src/tfm_psa_ns_api.c")
+endif()
+
 set(BUILD_CMSIS_CORE On)
 set(BUILD_RETARGET On)
 set(BUILD_NATIVE_DRIVERS On)
diff --git a/interface/include/tfm_api.h b/interface/include/tfm_api.h
index fea137a..527a433 100644
--- a/interface/include/tfm_api.h
+++ b/interface/include/tfm_api.h
@@ -13,6 +13,7 @@
 #endif
 
 #include <stdint.h>
+#include "interface/include/psa_client.h"
 
 #define TFM_INVALID_CLIENT_ID 0
 
@@ -73,6 +74,47 @@
  */
 enum tfm_status_e tfm_register_client_id (int32_t ns_client_id);
 
+/**
+ * \brief Return version of secure function provided by secure binary
+ *
+ * \param[in]  sid          ID of secure service
+ *
+ * \return Version number of secure function
+ */
+uint32_t tfm_psa_version_veneer(uint32_t sid);
+
+/**
+ * \brief Connect to secure function
+ *
+ * \param[in]  sid              ID of secure service
+ * \param[in]  minor_version    Minor version of SF requested by client
+ *
+ * \return Returns handle to connection
+ */
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version);
+
+/**
+ * \brief Call a secure function referenced by a connection handle
+ *
+ * \param[in]  handle   Handle to connection
+ * \param[in]  in_vecs  invec containing pointer/count of input vectors
+ * \param[in]  out_vecs invec containing pointer/count of output vectors
+ *
+ * \return Returns \ref psa_error_t error code
+ */
+psa_error_t tfm_psa_call_veneer(psa_handle_t handle,
+                    const psa_invec *in_vecs,
+                    const psa_invec *out_vecs);
+
+/**
+ * \brief Close connection to secure function referenced by a connection handle
+ *
+ * \param[in]  handle   Handle to connection
+ *
+ * \return Returns \ref psa_error_t error code
+ */
+psa_error_t tfm_psa_close_veneer(psa_handle_t handle);
+
 //================ End Secure function declarations ==========================//
 
 #ifdef __cplusplus
diff --git a/interface/include/tfm_ns_psa_svc.h b/interface/include/tfm_ns_psa_svc.h
new file mode 100644
index 0000000..a1032f6
--- /dev/null
+++ b/interface/include/tfm_ns_psa_svc.h
@@ -0,0 +1,31 @@
+/*
+ * 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
new file mode 100644
index 0000000..80c3af8
--- /dev/null
+++ b/interface/src/tfm_psa_ns_api.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "interface/include/psa_client.h"
+#include "tfm_ns_lock.h"
+#include "tfm_api.h"
+
+/**** API functions ****/
+
+uint32_t psa_version(uint32_t sid)
+{
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer,
+                                sid,
+                                0,
+                                0,
+                                0);
+}
+
+psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
+{
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer,
+                                sid,
+                                minor_version,
+                                0,
+                                0);
+}
+
+psa_error_t psa_call(psa_handle_t handle,
+                     const psa_invec *in_vec,
+                     size_t in_len,
+                     const psa_outvec *out_vec,
+                     size_t out_len)
+{
+    /* Due to v8M restrictions, TF-M NS API needs to add another layer of
+     * serialization in order for NS to pass arguments to S
+     */
+    psa_invec in_vecs, out_vecs;
+    in_vecs.base = in_vec;
+    in_vecs.len = in_len;
+    out_vecs.base = out_vec;
+    out_vecs.len = out_len;
+    return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer,
+                                (uint32_t)handle,
+                                (uint32_t)&in_vecs,
+                                (uint32_t)&out_vecs,
+                                0);
+}
+
+void psa_close(psa_handle_t handle)
+{
+    tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer,
+                         (uint32_t)handle,
+                         0,
+                         0,
+                         0);
+}
+
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index c7e4392..564209c 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -39,6 +39,12 @@
 		"${SS_CORE_DIR}/tfm_boot_data.c"
 	)
 
+if (NOT DEFINED TFM_PSA_API)
+	message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ")
+elseif (TFM_PSA_API)
+	list(APPEND SS_CORE_C_SRC "${SS_CORE_DIR}/tfm_psa_api_client.c")
+endif()
+
 #Append all our source files to global lists.
 list(APPEND ALL_SRC_C ${SS_CORE_C_SRC})
 unset(SS_CORE_C_SRC)
diff --git a/secure_fw/core/tfm_psa_api_client.c b/secure_fw/core/tfm_psa_api_client.c
new file mode 100644
index 0000000..56bda99
--- /dev/null
+++ b/secure_fw/core/tfm_psa_api_client.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "secure_utilities.h"
+#include "tfm_secure_api.h"
+#include "tfm_api.h"
+
+/* FixMe: check if this is really needed */
+extern int32_t tfm_secure_lock;
+
+__attribute__ ((always_inline)) __STATIC_INLINE
+int32_t tfm_psa_veneer_sanity_check(void)
+{
+    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 (tfm_secure_lock != 0) {
+            /* Secure domain is already locked!
+             * FixMe: Decide if this is a fault or permitted in case of PSA
+             * API usage
+             */
+            return TFM_ERROR_SECURE_DOMAIN_LOCKED;
+        }
+    } else {
+        /* Secure partition should not call a different secure partition
+         * using TFM PSA veneers
+         */
+        return TFM_ERROR_INVALID_EXC_MODE;
+    }
+    return TFM_SUCCESS;
+}
+
+/* Veneer implementation */
+
+/* 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)
+{
+    /* perform sanity check */
+    /* FixMe: pattern should follow guides on tfm core veneer return values */
+    if(tfm_psa_veneer_sanity_check() != TFM_SUCCESS) {
+        return TFM_ERROR_GENERIC;
+    }
+    /* return version number registered in manifest for given SID */
+    return TFM_SUCCESS;
+}
+
+__tfm_secure_gateway_attributes__
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
+{
+    /* perform sanity check */
+    /* decide whether a connection can be established to a given SID.
+     * In case of library model, this function always returns a valid handle.
+     * In thread model, it needs to perform the procedures outlined in PSA IPC
+     */
+    return TFM_SUCCESS;
+}
+
+__tfm_secure_gateway_attributes__
+psa_error_t tfm_psa_call_veneer(psa_handle_t handle,
+                    const psa_invec *in_vecs,
+                    const psa_invec *out_vecs)
+{
+    /* perform sanity check */
+    /* In case of library model, call the function referenced by the handle
+     * In thread model, it needs to perform the procedures outlined in PSA IPC
+     */
+    return TFM_SUCCESS;
+}
+
+__tfm_secure_gateway_attributes__
+psa_error_t tfm_psa_close_veneer(psa_handle_t handle)
+{
+    /* perform sanity check */
+    /* Close connection referenced by handle */
+    return TFM_SUCCESS;
+}
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 0b66ba5..863643b 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -36,7 +36,7 @@
 /* This is the "Big Lock" on the secure side, to guarantee single entry
  * to SPE
  */
-static int32_t tfm_secure_lock;
+int32_t tfm_secure_lock;
 static int32_t tfm_secure_api_initializing = 1;
 
 static int32_t *prepare_partition_ctx(