SPM: Create a dedicated source file for psa_call implementation

To support more granule source-level configurations, create a dedicated
source file for psa_call for the configuration system to select. This
patch changes psa_call first because it is the most frequent client API.

With these changes, users can know which sources are selected for their
configuration.

Signed-off-by: Xinyu Zhang <xinyu.zhang@arm.com>
Change-Id: If785ce50756215f31af2bfe7aa6895121745a03b
diff --git a/secure_fw/spm/CMakeLists.txt b/secure_fw/spm/CMakeLists.txt
index bdc6cf9..24261fc 100755
--- a/secure_fw/spm/CMakeLists.txt
+++ b/secure_fw/spm/CMakeLists.txt
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
 # Copyright (c) 2021-2022 Cypress Semiconductor Corporation (an Infineon
 # company) or an affiliate of Cypress Semiconductor Corporation. All rights
 # reserved.
@@ -44,6 +44,7 @@
         $<$<BOOL:${CONFIG_TFM_PSA_API_CROSS_CALL}>:cmsis_psa/spm_cross_call.c>
         cmsis_psa/static_loader.c
         ffm/psa_api.c
+        ffm/psa_call_api.c
         $<$<BOOL:${CONFIG_TFM_SPM_BACKEND_IPC}>:ffm/backend_ipc.c>
         $<$<BOOL:${CONFIG_TFM_SPM_BACKEND_SFN}>:ffm/backend_sfn.c>
         $<$<OR:$<BOOL:${CONFIG_TFM_FLIH_API}>,$<BOOL:${CONFIG_TFM_SLIH_API}>>:ffm/interrupt.c>
diff --git a/secure_fw/spm/ffm/psa_api.c b/secure_fw/spm/ffm/psa_api.c
index 35561fb..b930713 100644
--- a/secure_fw/spm/ffm/psa_api.c
+++ b/secure_fw/spm/ffm/psa_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
  * Copyright (c) 2022-2023 Cypress Semiconductor Corporation (an Infineon
  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
  * reserved.
@@ -21,7 +21,6 @@
 #include "load/partition_defs.h"
 #include "load/service_defs.h"
 #include "load/interrupt_defs.h"
-#include "ffm/psa_api.h"
 #include "utilities.h"
 #include "ffm/backend.h"
 #include "ffm/psa_api.h"
@@ -32,9 +31,6 @@
 #include "tfm_psa_call_pack.h"
 #include "tfm_hal_isolation.h"
 
-#define GET_STATELESS_SERVICE(index)    (stateless_services_ref_tbl[index])
-extern struct service_t *stateless_services_ref_tbl[];
-
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 
 /*
@@ -142,190 +138,6 @@
     return service->p_ldinf->version;
 }
 
-psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
-                                     uint32_t ctrl_param,
-                                     const psa_invec *inptr,
-                                     psa_outvec *outptr)
-{
-    psa_invec invecs[PSA_MAX_IOVEC];
-    psa_outvec outvecs[PSA_MAX_IOVEC];
-    struct conn_handle_t *conn_handle;
-    struct service_t *service;
-    int i, j;
-    int32_t client_id;
-    uint32_t sid, version, index;
-    struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
-    bool ns_caller = tfm_spm_is_ns_caller();
-    struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
-    int32_t type = (int32_t)(int16_t)((ctrl_param & TYPE_MASK) >> TYPE_OFFSET);
-    size_t in_num = (size_t)((ctrl_param & IN_LEN_MASK) >> IN_LEN_OFFSET);
-    size_t out_num = (size_t)((ctrl_param & OUT_LEN_MASK) >> OUT_LEN_OFFSET);
-    fih_int fih_rc = FIH_FAILURE;
-
-    /* The request type must be zero or positive. */
-    if (type < 0) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
-    if ((in_num > SIZE_MAX - out_num) ||
-        (in_num + out_num > PSA_MAX_IOVEC)) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    /* It is a PROGRAMMER ERROR if the handle is a null handle. */
-    if (handle == PSA_NULL_HANDLE) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    client_id = tfm_spm_get_client_id(ns_caller);
-
-    /* Allocate space from handle pool for static handle. */
-    if (IS_STATIC_HANDLE(handle)) {
-        index = GET_INDEX_FROM_STATIC_HANDLE(handle);
-
-        if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-
-        service = GET_STATELESS_SERVICE(index);
-        if (!service) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-
-        sid = service->p_ldinf->sid;
-
-        /*
-         * It is a PROGRAMMER ERROR if the caller is not authorized to access
-         * the RoT Service.
-         */
-        if (tfm_spm_check_authorization(sid, service, ns_caller)
-            != PSA_SUCCESS) {
-            return PSA_ERROR_CONNECTION_REFUSED;
-        }
-
-        version = GET_VERSION_FROM_STATIC_HANDLE(handle);
-
-        if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-
-        CRITICAL_SECTION_ENTER(cs_assert);
-        conn_handle = tfm_spm_create_conn_handle();
-        CRITICAL_SECTION_LEAVE(cs_assert);
-
-        if (!conn_handle) {
-            return PSA_ERROR_CONNECTION_BUSY;
-        }
-
-        conn_handle->rhandle = NULL;
-        handle = tfm_spm_to_user_handle(conn_handle);
-    } else {
-#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
-        /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
-        conn_handle = spm_get_handle_by_client_handle(handle, client_id);
-        if (!conn_handle) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-
-        /*
-         * It is a PROGRAMMER ERROR if the connection is currently
-         * handling a request.
-         */
-        if (conn_handle->status != TFM_HANDLE_STATUS_IDLE) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-
-        service = conn_handle->service;
-
-        if (!service) {
-            /* FixMe: Need to implement a mechanism to resolve this failure. */
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-#else
-        return PSA_ERROR_PROGRAMMER_ERROR;
-#endif
-    }
-
-    /*
-     * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
-     * if the memory reference for the wrap input vector is invalid or not
-     * readable.
-     */
-    FIH_CALL(tfm_hal_memory_check, fih_rc,
-             curr_partition->boundary, (uintptr_t)inptr,
-             in_num * sizeof(psa_invec), TFM_HAL_ACCESS_READABLE);
-    if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    /*
-     * Read client outvecs from the wrap output vector and will update the
-     * actual length later. It is a PROGRAMMER ERROR if the memory reference for
-     * the wrap output vector is invalid or not read-write.
-     */
-    FIH_CALL(tfm_hal_memory_check, fih_rc,
-             curr_partition->boundary, (uintptr_t)outptr,
-             out_num * sizeof(psa_outvec), TFM_HAL_ACCESS_READWRITE);
-    if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    spm_memset(invecs, 0, sizeof(invecs));
-    spm_memset(outvecs, 0, sizeof(outvecs));
-
-    /* Copy the address out to avoid TOCTOU attacks. */
-    spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
-    spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
-
-    /*
-     * For client input vector, it is a PROGRAMMER ERROR if the provided payload
-     * memory reference was invalid or not readable.
-     */
-    for (i = 0; i < in_num; i++) {
-        FIH_CALL(tfm_hal_memory_check, fih_rc,
-                 curr_partition->boundary, (uintptr_t)invecs[i].base,
-                 invecs[i].len, TFM_HAL_ACCESS_READABLE);
-        if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-    }
-
-    /*
-     * Clients must never overlap input parameters because of the risk of a
-     * double-fetch inconsistency.
-     * Overflow is checked in tfm_hal_memory_check functions.
-     */
-    for (i = 0; i + 1 < in_num; i++) {
-        for (j = i+1; j < in_num; j++) {
-            if (!((char *) invecs[j].base + invecs[j].len <=
-                  (char *) invecs[i].base ||
-                  (char *) invecs[j].base >=
-                  (char *) invecs[i].base + invecs[i].len)) {
-                return PSA_ERROR_PROGRAMMER_ERROR;
-            }
-        }
-    }
-
-    /*
-     * For client output vector, it is a PROGRAMMER ERROR if the provided
-     * payload memory reference was invalid or not read-write.
-     */
-    for (i = 0; i < out_num; i++) {
-        FIH_CALL(tfm_hal_memory_check, fih_rc,
-                 curr_partition->boundary, (uintptr_t)outvecs[i].base,
-                 outvecs[i].len, TFM_HAL_ACCESS_READWRITE);
-        if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
-            return PSA_ERROR_PROGRAMMER_ERROR;
-        }
-    }
-
-    spm_fill_message(conn_handle, service, handle, type, client_id,
-                     invecs, in_num, outvecs, out_num, outptr);
-
-    return backend_messaging(service, conn_handle);
-}
-
 /* Following PSA APIs are only needed by connection-based services */
 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
 
diff --git a/secure_fw/spm/ffm/psa_call_api.c b/secure_fw/spm/ffm/psa_call_api.c
new file mode 100644
index 0000000..e9e81e5
--- /dev/null
+++ b/secure_fw/spm/ffm/psa_call_api.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2023 Cypress Semiconductor Corporation (an Infineon
+ * company) or an affiliate of Cypress Semiconductor Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "config_impl.h"
+#include "critical_section.h"
+#include "ffm/backend.h"
+#include "ffm/psa_api.h"
+#include "tfm_hal_isolation.h"
+#include "tfm_psa_call_pack.h"
+#include "utilities.h"
+
+extern struct service_t *stateless_services_ref_tbl[];
+
+psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
+                                     uint32_t ctrl_param,
+                                     const psa_invec *inptr,
+                                     psa_outvec *outptr)
+{
+    psa_invec invecs[PSA_MAX_IOVEC];
+    psa_outvec outvecs[PSA_MAX_IOVEC];
+    struct conn_handle_t *conn_handle;
+    struct service_t *service;
+    int i, j;
+    int32_t client_id;
+    uint32_t sid, version, index;
+    struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
+    bool ns_caller = tfm_spm_is_ns_caller();
+    struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
+    int32_t type = (int32_t)(int16_t)((ctrl_param & TYPE_MASK) >> TYPE_OFFSET);
+    size_t in_num = (size_t)((ctrl_param & IN_LEN_MASK) >> IN_LEN_OFFSET);
+    size_t out_num = (size_t)((ctrl_param & OUT_LEN_MASK) >> OUT_LEN_OFFSET);
+    fih_int fih_rc = FIH_FAILURE;
+
+    /* The request type must be zero or positive. */
+    if (type < 0) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
+    if ((in_num > SIZE_MAX - out_num) ||
+        (in_num + out_num > PSA_MAX_IOVEC)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    /* It is a PROGRAMMER ERROR if the handle is a null handle. */
+    if (handle == PSA_NULL_HANDLE) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    client_id = tfm_spm_get_client_id(ns_caller);
+
+    /* Allocate space from handle pool for static handle. */
+    if (IS_STATIC_HANDLE(handle)) {
+        index = GET_INDEX_FROM_STATIC_HANDLE(handle);
+
+        if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+
+        service = stateless_services_ref_tbl[index];
+        if (!service) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+
+        sid = service->p_ldinf->sid;
+
+        /*
+         * It is a PROGRAMMER ERROR if the caller is not authorized to access
+         * the RoT Service.
+         */
+        if (tfm_spm_check_authorization(sid, service, ns_caller)
+            != PSA_SUCCESS) {
+            return PSA_ERROR_CONNECTION_REFUSED;
+        }
+
+        version = GET_VERSION_FROM_STATIC_HANDLE(handle);
+
+        if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+
+        CRITICAL_SECTION_ENTER(cs_assert);
+        conn_handle = tfm_spm_create_conn_handle();
+        CRITICAL_SECTION_LEAVE(cs_assert);
+
+        if (!conn_handle) {
+            return PSA_ERROR_CONNECTION_BUSY;
+        }
+
+        conn_handle->rhandle = NULL;
+        handle = tfm_spm_to_user_handle(conn_handle);
+    } else {
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+        /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
+        conn_handle = spm_get_handle_by_client_handle(handle, client_id);
+        if (!conn_handle) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+
+        /*
+         * It is a PROGRAMMER ERROR if the connection is currently
+         * handling a request.
+         */
+        if (conn_handle->status != TFM_HANDLE_STATUS_IDLE) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+
+        service = conn_handle->service;
+
+        if (!service) {
+            /* FixMe: Need to implement a mechanism to resolve this failure. */
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+#else
+        return PSA_ERROR_PROGRAMMER_ERROR;
+#endif
+    }
+
+    /*
+     * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
+     * if the memory reference for the wrap input vector is invalid or not
+     * readable.
+     */
+    FIH_CALL(tfm_hal_memory_check, fih_rc,
+             curr_partition->boundary, (uintptr_t)inptr,
+             in_num * sizeof(psa_invec), TFM_HAL_ACCESS_READABLE);
+    if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    /*
+     * Read client outvecs from the wrap output vector and will update the
+     * actual length later. It is a PROGRAMMER ERROR if the memory reference for
+     * the wrap output vector is invalid or not read-write.
+     */
+    FIH_CALL(tfm_hal_memory_check, fih_rc,
+             curr_partition->boundary, (uintptr_t)outptr,
+             out_num * sizeof(psa_outvec), TFM_HAL_ACCESS_READWRITE);
+    if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    spm_memset(invecs, 0, sizeof(invecs));
+    spm_memset(outvecs, 0, sizeof(outvecs));
+
+    /* Copy the address out to avoid TOCTOU attacks. */
+    spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
+    spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
+
+    /*
+     * For client input vector, it is a PROGRAMMER ERROR if the provided payload
+     * memory reference was invalid or not readable.
+     */
+    for (i = 0; i < in_num; i++) {
+        FIH_CALL(tfm_hal_memory_check, fih_rc,
+                 curr_partition->boundary, (uintptr_t)invecs[i].base,
+                 invecs[i].len, TFM_HAL_ACCESS_READABLE);
+        if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+    }
+
+    /*
+     * Clients must never overlap input parameters because of the risk of a
+     * double-fetch inconsistency.
+     * Overflow is checked in tfm_hal_memory_check functions.
+     */
+    for (i = 0; i + 1 < in_num; i++) {
+        for (j = i+1; j < in_num; j++) {
+            if (!((char *) invecs[j].base + invecs[j].len <=
+                  (char *) invecs[i].base ||
+                  (char *) invecs[j].base >=
+                  (char *) invecs[i].base + invecs[i].len)) {
+                return PSA_ERROR_PROGRAMMER_ERROR;
+            }
+        }
+    }
+
+    /*
+     * For client output vector, it is a PROGRAMMER ERROR if the provided
+     * payload memory reference was invalid or not read-write.
+     */
+    for (i = 0; i < out_num; i++) {
+        FIH_CALL(tfm_hal_memory_check, fih_rc,
+                 curr_partition->boundary, (uintptr_t)outvecs[i].base,
+                 outvecs[i].len, TFM_HAL_ACCESS_READWRITE);
+        if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
+            return PSA_ERROR_PROGRAMMER_ERROR;
+        }
+    }
+
+    spm_fill_message(conn_handle, service, handle, type, client_id,
+                     invecs, in_num, outvecs, out_num, outptr);
+
+    return backend_messaging(service, conn_handle);
+}