1 /*
2 * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
3 * Copyright (c) 2022-2024 Cypress Semiconductor Corporation (an Infineon
4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5 * reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #include "critical_section.h"
12 #include "ffm/backend.h"
13 #include "ffm/psa_api.h"
14 #include "load/service_defs.h"
15 #include "spm.h"
16 #include "utilities.h"
17
18 /* PSA APIs only needed by connection-based services */
19
tfm_spm_client_psa_connect(uint32_t sid,uint32_t version)20 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
21 {
22 int32_t client_id;
23 struct connection_t *p_connection;
24 psa_status_t status;
25
26 bool ns_caller = tfm_spm_is_ns_caller();
27
28 client_id = tfm_spm_get_client_id(ns_caller);
29 status = spm_psa_connect_client_id_associated(&p_connection, sid, version, client_id);
30 if (status != PSA_SUCCESS) {
31 return status;
32 }
33
34 return backend_messaging(p_connection);
35 }
36
spm_psa_connect_client_id_associated(struct connection_t ** p_connection,uint32_t sid,uint32_t version,int32_t client_id)37 psa_status_t spm_psa_connect_client_id_associated(struct connection_t **p_connection,
38 uint32_t sid, uint32_t version, int32_t client_id)
39 {
40 const struct service_t *service;
41 struct connection_t *connection;
42 struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
43 bool ns_caller = (client_id < 0) ? true : false;
44
45 /*
46 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
47 * platform.
48 */
49 service = tfm_spm_get_service_by_sid(sid);
50 if (!service) {
51 return PSA_ERROR_CONNECTION_REFUSED;
52 }
53
54 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
55 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
56 return PSA_ERROR_PROGRAMMER_ERROR;
57 }
58
59 /*
60 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
61 * RoT Service.
62 */
63 if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
64 return PSA_ERROR_CONNECTION_REFUSED;
65 }
66
67 /*
68 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
69 * not supported on the platform.
70 */
71 if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
72 return PSA_ERROR_CONNECTION_REFUSED;
73 }
74
75 /*
76 * Create connection handle here since it is possible to return the error
77 * code to client when creation fails.
78 */
79 CRITICAL_SECTION_ENTER(cs_assert);
80 connection = spm_allocate_connection();
81 CRITICAL_SECTION_LEAVE(cs_assert);
82 if (!connection) {
83 return PSA_ERROR_CONNECTION_BUSY;
84 }
85
86 spm_init_idle_connection(connection, service, client_id);
87 connection->msg.type = PSA_IPC_CONNECT;
88
89 *p_connection = connection;
90
91 return PSA_SUCCESS;
92 }
93
tfm_spm_client_psa_close(psa_handle_t handle)94 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
95 {
96 bool ns_caller = tfm_spm_is_ns_caller();
97 return spm_psa_close_client_id_associated(handle, tfm_spm_get_client_id(ns_caller));
98 }
99
spm_psa_close_client_id_associated(psa_handle_t handle,int32_t client_id)100 psa_status_t spm_psa_close_client_id_associated(psa_handle_t handle, int32_t client_id)
101 {
102 struct connection_t *p_connection;
103 psa_status_t status;
104
105 /* It will have no effect if called with the NULL handle */
106 if (handle == PSA_NULL_HANDLE) {
107 return PSA_SUCCESS;
108 }
109
110 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
111 if (IS_STATIC_HANDLE(handle)) {
112 return PSA_ERROR_PROGRAMMER_ERROR;
113 }
114
115 /*
116 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
117 * the null handle.
118 */
119 status = spm_get_idle_connection(&p_connection, handle, client_id);
120 if (status != PSA_SUCCESS) {
121 return status;
122 }
123
124 p_connection->msg.type = PSA_IPC_DISCONNECT;
125
126 return backend_messaging(p_connection);
127 }
128
tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle,void * rhandle)129 psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
130 {
131 struct connection_t *handle;
132
133 /* It is a fatal error if message handle is invalid */
134 handle = spm_msg_handle_to_connection(msg_handle);
135 if (!handle) {
136 tfm_core_panic();
137 }
138
139 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
140 if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) {
141 tfm_core_panic();
142 }
143
144 handle->msg.rhandle = rhandle;
145
146 return PSA_SUCCESS;
147 }
148