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);
+}