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 "ffm/backend.h"
12 #include "ffm/psa_api.h"
13 #include "load/service_defs.h"
14 #include "spm.h"
15 #include "utilities.h"
16
17 /* PSA APIs only needed by connection-based services */
18
tfm_spm_client_psa_connect(uint32_t sid,uint32_t version)19 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
20 {
21 int32_t client_id;
22 struct connection_t *p_connection;
23 psa_status_t status;
24
25 bool ns_caller = tfm_spm_is_ns_caller();
26
27 client_id = tfm_spm_get_client_id(ns_caller);
28 status = spm_psa_connect_client_id_associated(&p_connection, sid, version, client_id);
29 if (status != PSA_SUCCESS) {
30 return status;
31 }
32
33 status = backend_messaging(p_connection);
34
35 p_connection->status = TFM_HANDLE_STATUS_ACTIVE;
36 return status;
37 }
38
spm_psa_connect_client_id_associated(struct connection_t ** p_connection,uint32_t sid,uint32_t version,int32_t client_id)39 psa_status_t spm_psa_connect_client_id_associated(struct connection_t **p_connection,
40 uint32_t sid, uint32_t version, int32_t client_id)
41 {
42 const struct service_t *service;
43 struct connection_t *connection;
44 bool ns_caller = (client_id < 0) ? true : false;
45
46 /*
47 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
48 * platform.
49 */
50 service = tfm_spm_get_service_by_sid(sid);
51 if (!service) {
52 return PSA_ERROR_CONNECTION_REFUSED;
53 }
54
55 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
56 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
57 return PSA_ERROR_PROGRAMMER_ERROR;
58 }
59
60 /*
61 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
62 * RoT Service.
63 */
64 if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
65 return PSA_ERROR_CONNECTION_REFUSED;
66 }
67
68 /*
69 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
70 * not supported on the platform.
71 */
72 if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
73 return PSA_ERROR_CONNECTION_REFUSED;
74 }
75
76 /*
77 * Create connection handle here since it is possible to return the error
78 * code to client when creation fails.
79 *
80 * Current SPM doesn't support multiple context management. There is only one
81 * instance in SPM to call the connection pool allocation. It is no need to be
82 * protected.
83 * Protection should be established after the context management is implemented.
84 */
85 connection = spm_allocate_connection();
86 if (!connection) {
87 return PSA_ERROR_CONNECTION_BUSY;
88 }
89
90 spm_init_idle_connection(connection, service, client_id);
91 connection->msg.type = PSA_IPC_CONNECT;
92
93 *p_connection = connection;
94
95 return PSA_SUCCESS;
96 }
97
tfm_spm_client_psa_close(psa_handle_t handle)98 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
99 {
100 bool ns_caller = tfm_spm_is_ns_caller();
101 return spm_psa_close_client_id_associated(handle, tfm_spm_get_client_id(ns_caller));
102 }
103
spm_psa_close_client_id_associated(psa_handle_t handle,int32_t client_id)104 psa_status_t spm_psa_close_client_id_associated(psa_handle_t handle, int32_t client_id)
105 {
106 struct connection_t *p_connection;
107 psa_status_t status;
108
109 /* It will have no effect if called with the NULL handle */
110 if (handle == PSA_NULL_HANDLE) {
111 return PSA_SUCCESS;
112 }
113
114 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
115 if (IS_STATIC_HANDLE(handle)) {
116 return PSA_ERROR_PROGRAMMER_ERROR;
117 }
118
119 /*
120 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
121 * the null handle.
122 */
123 status = spm_get_idle_connection(&p_connection, handle, client_id);
124 if (status != PSA_SUCCESS) {
125 return status;
126 }
127
128 p_connection->msg.type = PSA_IPC_DISCONNECT;
129
130 status = backend_messaging(p_connection);
131
132 p_connection->status = TFM_HANDLE_STATUS_TO_FREE;
133
134 return status;
135 }
136
tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle,void * rhandle)137 psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
138 {
139 struct connection_t *handle;
140
141 /* It is a fatal error if message handle is invalid */
142 handle = spm_msg_handle_to_connection(msg_handle);
143 if (!handle) {
144 tfm_core_panic();
145 }
146
147 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
148 if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) {
149 tfm_core_panic();
150 }
151
152 handle->msg.rhandle = rhandle;
153
154 return PSA_SUCCESS;
155 }
156