/* * Copyright (c) 2019-2024, Arm Limited. All rights reserved. * Copyright (c) 2022-2024 Cypress Semiconductor Corporation (an Infineon * company) or an affiliate of Cypress Semiconductor Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include "critical_section.h" #include "ffm/backend.h" #include "ffm/psa_api.h" #include "load/service_defs.h" #include "spm.h" #include "utilities.h" /* PSA APIs only needed by connection-based services */ psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version) { int32_t client_id; struct connection_t *p_connection; psa_status_t status; bool ns_caller = tfm_spm_is_ns_caller(); client_id = tfm_spm_get_client_id(ns_caller); status = spm_psa_connect_client_id_associated(&p_connection, sid, version, client_id); if (status != PSA_SUCCESS) { return status; } return backend_messaging(p_connection); } psa_status_t spm_psa_connect_client_id_associated(struct connection_t **p_connection, uint32_t sid, uint32_t version, int32_t client_id) { const struct service_t *service; struct connection_t *connection; struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT; bool ns_caller = (client_id < 0) ? true : false; /* * It is a PROGRAMMER ERROR if the RoT Service does not exist on the * platform. */ service = tfm_spm_get_service_by_sid(sid); if (!service) { return PSA_ERROR_CONNECTION_REFUSED; } /* It is a PROGRAMMER ERROR if connecting to a stateless service. */ if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) { return PSA_ERROR_PROGRAMMER_ERROR; } /* * 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; } /* * It is a PROGRAMMER ERROR if the version of the RoT Service requested is * not supported on the platform. */ if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) { return PSA_ERROR_CONNECTION_REFUSED; } /* * Create connection handle here since it is possible to return the error * code to client when creation fails. */ CRITICAL_SECTION_ENTER(cs_assert); connection = spm_allocate_connection(); CRITICAL_SECTION_LEAVE(cs_assert); if (!connection) { return PSA_ERROR_CONNECTION_BUSY; } spm_init_idle_connection(connection, service, client_id); connection->msg.type = PSA_IPC_CONNECT; *p_connection = connection; return PSA_SUCCESS; } psa_status_t tfm_spm_client_psa_close(psa_handle_t handle) { bool ns_caller = tfm_spm_is_ns_caller(); return spm_psa_close_client_id_associated(handle, tfm_spm_get_client_id(ns_caller)); } psa_status_t spm_psa_close_client_id_associated(psa_handle_t handle, int32_t client_id) { struct connection_t *p_connection; psa_status_t status; /* It will have no effect if called with the NULL handle */ if (handle == PSA_NULL_HANDLE) { return PSA_SUCCESS; } /* It is a PROGRAMMER ERROR if called with a stateless handle. */ if (IS_STATIC_HANDLE(handle)) { return PSA_ERROR_PROGRAMMER_ERROR; } /* * It is a PROGRAMMER ERROR if an invalid handle was provided that is not * the null handle. */ status = spm_get_idle_connection(&p_connection, handle, client_id); if (status != PSA_SUCCESS) { return status; } p_connection->msg.type = PSA_IPC_DISCONNECT; return backend_messaging(p_connection); } psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle) { struct connection_t *handle; /* It is a fatal error if message handle is invalid */ handle = spm_msg_handle_to_connection(msg_handle); if (!handle) { tfm_core_panic(); } /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */ if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) { tfm_core_panic(); } handle->msg.rhandle = rhandle; return PSA_SUCCESS; }