blob: a65bdec8caa40583f4b2a336ca5bae5d6f043a66 [file] [log] [blame]
David Hu733d8f92019-09-23 15:32:40 +08001/*
Shawn Shanb222d892021-01-04 17:41:48 +08002 * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
David Hu733d8f92019-09-23 15:32:40 +08003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
Mingyang Sunb26b2802021-07-07 11:25:00 +08008#include "bitops.h"
David Hu733d8f92019-09-23 15:32:40 +08009#include "psa/service.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080010#include "spm_ipc.h"
Mingyang Sun22a3faf2021-07-09 15:32:47 +080011#include "tfm_arch.h"
David Hu733d8f92019-09-23 15:32:40 +080012#include "tfm_core_utils.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080013#include "load/partition_defs.h"
Mingyang Sun2b352662021-04-21 11:35:43 +080014#include "load/service_defs.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080015#include "load/irq_defs.h"
Mingyang Sun133a7922021-07-08 16:01:26 +080016#include "psa_api.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080017#include "utilities.h"
David Hu733d8f92019-09-23 15:32:40 +080018#include "tfm_wait.h"
Summer Qin1ce712a2019-10-14 18:04:05 +080019#include "tfm_nspm.h"
Ken Liubcae38b2021-01-20 15:47:44 +080020#include "ffm/spm_error_base.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080021#include "tfm_rpc.h"
22#include "tfm_spm_hal.h"
23#include "tfm_hal_platform.h"
David Hu733d8f92019-09-23 15:32:40 +080024
Ken Liub3b2cb62021-05-22 00:39:28 +080025#define GET_STATELESS_SERVICE(index) (stateless_services_ref_tbl[index])
Xinyu Zhanga38e9b52021-06-02 17:48:01 +080026extern struct service_t *stateless_services_ref_tbl[];
Mingyang Suncb6f70e2021-03-05 23:30:25 +080027
Mingyang Sund44522a2020-01-16 16:48:37 +080028uint32_t tfm_spm_client_psa_framework_version(void)
David Hu733d8f92019-09-23 15:32:40 +080029{
30 return PSA_FRAMEWORK_VERSION;
31}
32
Mingyang Sun22a3faf2021-07-09 15:32:47 +080033uint32_t tfm_spm_client_psa_version(uint32_t sid)
David Hu733d8f92019-09-23 15:32:40 +080034{
Mingyang Sun783a59b2021-04-20 15:52:18 +080035 struct service_t *service;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080036 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080037
38 /*
39 * It should return PSA_VERSION_NONE if the RoT Service is not
40 * implemented.
41 */
42 service = tfm_spm_get_service_by_sid(sid);
43 if (!service) {
44 return PSA_VERSION_NONE;
45 }
46
47 /*
Shawn Shan2365c902019-12-19 18:35:36 +080048 * It should return PSA_VERSION_NONE if the caller is not authorized
49 * to access the RoT Service.
David Hu733d8f92019-09-23 15:32:40 +080050 */
Ken Liubcae38b2021-01-20 15:47:44 +080051 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
Shawn Shan2365c902019-12-19 18:35:36 +080052 return PSA_VERSION_NONE;
David Hu733d8f92019-09-23 15:32:40 +080053 }
54
Ken Liuacd2a572021-05-12 16:19:04 +080055 return service->p_ldinf->version;
David Hu733d8f92019-09-23 15:32:40 +080056}
57
Mingyang Sun22a3faf2021-07-09 15:32:47 +080058psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
David Hu733d8f92019-09-23 15:32:40 +080059{
Mingyang Sun783a59b2021-04-20 15:52:18 +080060 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +080061 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +080062 struct tfm_conn_handle_t *connect_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +080063 int32_t client_id;
Ken Liu505b1702020-05-29 13:19:58 +080064 psa_handle_t handle;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080065 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080066
Kevin Pengedb8ee42021-03-09 16:50:11 +080067 /*
68 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
69 * platform.
70 */
David Hu733d8f92019-09-23 15:32:40 +080071 service = tfm_spm_get_service_by_sid(sid);
72 if (!service) {
Shawn Shanb222d892021-01-04 17:41:48 +080073 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
David Hu733d8f92019-09-23 15:32:40 +080074 }
75
Mingyang Sunef42f442021-06-11 15:07:58 +080076 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
77 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
78 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
79 }
80
Kevin Pengedb8ee42021-03-09 16:50:11 +080081 /*
82 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
83 * RoT Service.
84 */
85 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
86 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
87 }
88
89 /*
90 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
91 * not supported on the platform.
92 */
93 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
94 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
95 }
96
Summer Qin1ce712a2019-10-14 18:04:05 +080097 if (ns_caller) {
98 client_id = tfm_nspm_get_current_client_id();
99 } else {
100 client_id = tfm_spm_partition_get_running_partition_id();
101 }
102
David Hu733d8f92019-09-23 15:32:40 +0800103 /*
104 * Create connection handle here since it is possible to return the error
105 * code to client when creation fails.
106 */
Summer Qin1ce712a2019-10-14 18:04:05 +0800107 connect_handle = tfm_spm_create_conn_handle(service, client_id);
Summer Qin630c76b2020-05-20 10:32:58 +0800108 if (!connect_handle) {
David Hu733d8f92019-09-23 15:32:40 +0800109 return PSA_ERROR_CONNECTION_BUSY;
110 }
111
Kevin Pengdf6aa292021-03-11 17:58:50 +0800112 msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
113 if (!msg) {
114 /* Have no enough resource to create message */
115 return PSA_ERROR_CONNECTION_BUSY;
116 }
David Hu733d8f92019-09-23 15:32:40 +0800117
Ken Liu505b1702020-05-29 13:19:58 +0800118 handle = tfm_spm_to_user_handle(connect_handle);
David Hu733d8f92019-09-23 15:32:40 +0800119 /* No input or output needed for connect message */
Ken Liu505b1702020-05-29 13:19:58 +0800120 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
Summer Qin1ce712a2019-10-14 18:04:05 +0800121 client_id, NULL, 0, NULL, 0, NULL);
David Hu733d8f92019-09-23 15:32:40 +0800122
123 /*
124 * Send message and wake up the SP who is waiting on message queue,
125 * and scheduler triggered
126 */
127 tfm_spm_send_event(service, msg);
128
129 return PSA_SUCCESS;
130}
131
Mingyang Sund44522a2020-01-16 16:48:37 +0800132psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, int32_t type,
133 const psa_invec *inptr, size_t in_num,
Mingyang Sune529e3b2021-07-12 14:46:30 +0800134 psa_outvec *outptr, size_t out_num)
David Hu733d8f92019-09-23 15:32:40 +0800135{
136 psa_invec invecs[PSA_MAX_IOVEC];
137 psa_outvec outvecs[PSA_MAX_IOVEC];
Summer Qin630c76b2020-05-20 10:32:58 +0800138 struct tfm_conn_handle_t *conn_handle;
Mingyang Sun783a59b2021-04-20 15:52:18 +0800139 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800140 struct tfm_msg_body_t *msg;
Summer Qinba2346e2019-11-12 16:26:31 +0800141 int i, j;
Summer Qin1ce712a2019-10-14 18:04:05 +0800142 int32_t client_id;
Mingyang Sun453ad402021-03-17 17:58:33 +0800143 uint32_t sid, version, index;
Mingyang Sune529e3b2021-07-12 14:46:30 +0800144 uint32_t privileged;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800145 bool ns_caller = tfm_spm_is_ns_caller();
146
147 /* The request type must be zero or positive. */
148 if (type < 0) {
149 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
150 }
David Hu733d8f92019-09-23 15:32:40 +0800151
Shawn Shanb222d892021-01-04 17:41:48 +0800152 /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
David Hu733d8f92019-09-23 15:32:40 +0800153 if ((in_num > PSA_MAX_IOVEC) ||
154 (out_num > PSA_MAX_IOVEC) ||
155 (in_num + out_num > PSA_MAX_IOVEC)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800156 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800157 }
158
Summer Qin1ce712a2019-10-14 18:04:05 +0800159 if (ns_caller) {
160 client_id = tfm_nspm_get_current_client_id();
161 } else {
162 client_id = tfm_spm_partition_get_running_partition_id();
163 }
164
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800165 /* Allocate space from handle pool for static handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800166 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun453ad402021-03-17 17:58:33 +0800167 index = GET_INDEX_FROM_STATIC_HANDLE(handle);
Mingyang Sune8d38082021-03-30 18:34:40 +0800168
169 if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
170 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
171 }
172
Mingyang Sun453ad402021-03-17 17:58:33 +0800173 service = GET_STATELESS_SERVICE(index);
Mingyang Sun86213242021-07-14 10:26:43 +0800174 if (!service) {
175 tfm_core_panic();
176 }
177
Ken Liub3b2cb62021-05-22 00:39:28 +0800178 sid = service->p_ldinf->sid;
Mingyang Sun453ad402021-03-17 17:58:33 +0800179
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800180 /*
181 * It is a PROGRAMMER ERROR if the caller is not authorized to access
182 * the RoT Service.
183 */
184 if (tfm_spm_check_authorization(sid, service, ns_caller)
185 != SPM_SUCCESS) {
186 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
187 }
188
Mingyang Sun453ad402021-03-17 17:58:33 +0800189 version = GET_VERSION_FROM_STATIC_HANDLE(handle);
190
191 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
192 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
193 }
194
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800195 conn_handle = tfm_spm_create_conn_handle(service, client_id);
196
197 if (!conn_handle) {
198 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_BUSY);
199 }
200
Mingyang Sun6d5dc3d2021-03-15 15:34:44 +0800201 conn_handle->rhandle = NULL;
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800202 handle = tfm_spm_to_user_handle(conn_handle);
203 } else {
204 conn_handle = tfm_spm_to_handle_instance(handle);
205
206 /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
207 if (tfm_spm_validate_conn_handle(conn_handle, client_id)
208 != SPM_SUCCESS) {
209 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
210 }
211
212 /*
213 * It is a PROGRAMMER ERROR if the connection is currently
214 * handling a request.
215 */
216 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
217 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
218 }
219
220 /*
221 * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
222 * has been terminated by the RoT Service.
223 */
224 if (conn_handle->status == TFM_HANDLE_STATUS_CONNECT_ERROR) {
225 return PSA_ERROR_PROGRAMMER_ERROR;
226 }
227
228 service = conn_handle->service;
Summer Qin1ce712a2019-10-14 18:04:05 +0800229 }
Shawn Shanb222d892021-01-04 17:41:48 +0800230
David Hu733d8f92019-09-23 15:32:40 +0800231 if (!service) {
232 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800233 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800234 }
235
Mingyang Sune529e3b2021-07-12 14:46:30 +0800236 privileged = tfm_spm_get_caller_privilege_mode();
237
Kevin Pengedb8ee42021-03-09 16:50:11 +0800238 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800239 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
David Hu733d8f92019-09-23 15:32:40 +0800240 * if the memory reference for the wrap input vector is invalid or not
241 * readable.
242 */
243 if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800244 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800245 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800246 }
Summer Qinba2346e2019-11-12 16:26:31 +0800247
David Hu733d8f92019-09-23 15:32:40 +0800248 /*
249 * Read client outvecs from the wrap output vector and will update the
Shawn Shanb222d892021-01-04 17:41:48 +0800250 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
David Hu733d8f92019-09-23 15:32:40 +0800251 * the wrap output vector is invalid or not read-write.
252 */
253 if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800254 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800255 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800256 }
257
Summer Qinf24dbb52020-07-23 14:53:54 +0800258 spm_memset(invecs, 0, sizeof(invecs));
259 spm_memset(outvecs, 0, sizeof(outvecs));
David Hu733d8f92019-09-23 15:32:40 +0800260
261 /* Copy the address out to avoid TOCTOU attacks. */
Summer Qinf24dbb52020-07-23 14:53:54 +0800262 spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
263 spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
David Hu733d8f92019-09-23 15:32:40 +0800264
265 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800266 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
David Hu733d8f92019-09-23 15:32:40 +0800267 * memory reference was invalid or not readable.
268 */
269 for (i = 0; i < in_num; i++) {
270 if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800271 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800272 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800273 }
274 }
Summer Qinba2346e2019-11-12 16:26:31 +0800275
276 /*
277 * Clients must never overlap input parameters because of the risk of a
278 * double-fetch inconsistency.
279 * Overflow is checked in tfm_memory_check functions.
280 */
281 for (i = 0; i + 1 < in_num; i++) {
282 for (j = i+1; j < in_num; j++) {
TTornblom83d96372019-11-19 12:53:16 +0100283 if (!((char *) invecs[j].base + invecs[j].len <=
284 (char *) invecs[i].base ||
285 (char *) invecs[j].base >=
286 (char *) invecs[i].base + invecs[i].len)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800287 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
Summer Qinba2346e2019-11-12 16:26:31 +0800288 }
289 }
290 }
291
David Hu733d8f92019-09-23 15:32:40 +0800292 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800293 * For client output vector, it is a PROGRAMMER ERROR if the provided
294 * payload memory reference was invalid or not read-write.
David Hu733d8f92019-09-23 15:32:40 +0800295 */
296 for (i = 0; i < out_num; i++) {
297 if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
Ken Liubcae38b2021-01-20 15:47:44 +0800298 ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800299 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800300 }
301 }
302
303 /*
304 * FixMe: Need to check if the message is unrecognized by the RoT
305 * Service or incorrectly formatted.
306 */
Kevin Pengdf6aa292021-03-11 17:58:50 +0800307 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
308 if (!msg) {
309 /* FixMe: Need to implement one mechanism to resolve this failure. */
310 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
311 }
David Hu733d8f92019-09-23 15:32:40 +0800312
Ken Liu505b1702020-05-29 13:19:58 +0800313 tfm_spm_fill_msg(msg, service, handle, type, client_id,
Summer Qin630c76b2020-05-20 10:32:58 +0800314 invecs, in_num, outvecs, out_num, outptr);
David Hu733d8f92019-09-23 15:32:40 +0800315
316 /*
317 * Send message and wake up the SP who is waiting on message queue,
318 * and scheduler triggered
319 */
Kevin Peng8dac6102021-03-09 16:44:00 +0800320 tfm_spm_send_event(service, msg);
321
David Hu733d8f92019-09-23 15:32:40 +0800322 return PSA_SUCCESS;
323}
324
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800325void tfm_spm_client_psa_close(psa_handle_t handle)
David Hu733d8f92019-09-23 15:32:40 +0800326{
Mingyang Sun783a59b2021-04-20 15:52:18 +0800327 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800328 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +0800329 struct tfm_conn_handle_t *conn_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +0800330 int32_t client_id;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800331 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +0800332
333 /* It will have no effect if called with the NULL handle */
334 if (handle == PSA_NULL_HANDLE) {
335 return;
336 }
337
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800338 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800339 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800340 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
341 }
342
Summer Qin1ce712a2019-10-14 18:04:05 +0800343 if (ns_caller) {
344 client_id = tfm_nspm_get_current_client_id();
345 } else {
346 client_id = tfm_spm_partition_get_running_partition_id();
347 }
348
Summer Qin373feb12020-03-27 15:35:33 +0800349 conn_handle = tfm_spm_to_handle_instance(handle);
David Hu733d8f92019-09-23 15:32:40 +0800350 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800351 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
352 * the null handle.
David Hu733d8f92019-09-23 15:32:40 +0800353 */
Ken Liubcae38b2021-01-20 15:47:44 +0800354 if (tfm_spm_validate_conn_handle(conn_handle, client_id) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800355 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Summer Qin1ce712a2019-10-14 18:04:05 +0800356 }
Shawn Shanb222d892021-01-04 17:41:48 +0800357
Summer Qin630c76b2020-05-20 10:32:58 +0800358 service = conn_handle->service;
David Hu733d8f92019-09-23 15:32:40 +0800359 if (!service) {
360 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800361 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800362 }
363
Kevin Pengdf6aa292021-03-11 17:58:50 +0800364 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
365 if (!msg) {
366 /* FixMe: Need to implement one mechanism to resolve this failure. */
367 tfm_core_panic();
368 }
David Hu733d8f92019-09-23 15:32:40 +0800369
Shawn Shanb222d892021-01-04 17:41:48 +0800370 /*
371 * It is a PROGRAMMER ERROR if the connection is currently handling a
372 * request.
373 */
Summer Qin630c76b2020-05-20 10:32:58 +0800374 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
Shawn Shanb222d892021-01-04 17:41:48 +0800375 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Shawn Shancc39fcb2019-11-13 15:38:16 +0800376 }
377
David Hu733d8f92019-09-23 15:32:40 +0800378 /* No input or output needed for close message */
Ken Liu505b1702020-05-29 13:19:58 +0800379 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
David Hu733d8f92019-09-23 15:32:40 +0800380 NULL, 0, NULL, 0, NULL);
381
382 /*
383 * Send message and wake up the SP who is waiting on message queue,
384 * and scheduler triggered
385 */
386 tfm_spm_send_event(service, msg);
387}
Mingyang Sunb26b2802021-07-07 11:25:00 +0800388
389psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
390 uint32_t timeout)
391{
392 struct partition_t *partition = NULL;
393
394 /*
395 * Timeout[30:0] are reserved for future use.
396 * SPM must ignore the value of RES.
397 */
398 timeout &= PSA_TIMEOUT_MASK;
399
400 partition = tfm_spm_get_running_partition();
401 if (!partition) {
402 tfm_core_panic();
403 }
404
405 /*
406 * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
407 * signals.
408 */
409 if ((partition->signals_allowed & signal_mask) == 0) {
410 tfm_core_panic();
411 }
412
413 /*
414 * tfm_event_wait() blocks the caller thread if no signals are available.
415 * In this case, the return value of this function is temporary set into
416 * runtime context. After new signal(s) are available, the return value
417 * is updated with the available signal(s) and blocked thread gets to run.
418 */
419 if (timeout == PSA_BLOCK &&
420 (partition->signals_asserted & signal_mask) == 0) {
421 partition->signals_waiting = signal_mask;
422 tfm_event_wait(&partition->event);
423 } else if ((partition->signals_asserted & signal_mask) == 0) {
424 /* Activate scheduler to check if any higher priority thread to run */
425 tfm_core_thrd_activate_schedule();
426 }
427
428 return partition->signals_asserted & signal_mask;
429}
430
431psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
432{
433 struct tfm_msg_body_t *tmp_msg = NULL;
434 struct partition_t *partition = NULL;
435 uint32_t privileged;
436
437 /*
438 * Only one message could be retrieved every time for psa_get(). It is a
439 * fatal error if the input signal has more than a signal bit set.
440 */
441 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
442 tfm_core_panic();
443 }
444
445 partition = tfm_spm_get_running_partition();
446 if (!partition) {
447 tfm_core_panic();
448 }
449 privileged = tfm_spm_partition_get_privileged_mode(
450 partition->p_ldinf->flags);
451
452 /*
453 * Write the message to the service buffer. It is a fatal error if the
454 * input msg pointer is not a valid memory reference or not read-write.
455 */
456 if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
457 privileged) != SPM_SUCCESS) {
458 tfm_core_panic();
459 }
460
461 /*
462 * It is a fatal error if the caller call psa_get() when no message has
463 * been set. The caller must call this function after an RoT Service signal
464 * is returned by psa_wait().
465 */
466 if (partition->signals_asserted == 0) {
467 tfm_core_panic();
468 }
469
470 /*
471 * It is a fatal error if the RoT Service signal is not currently asserted.
472 */
473 if ((partition->signals_asserted & signal) == 0) {
474 tfm_core_panic();
475 }
476
477 /*
478 * Get message by signal from partition. It is a fatal error if getting
479 * failed, which means the input signal is not correspond to an RoT service.
480 */
481 tmp_msg = tfm_spm_get_msg_by_signal(partition, signal);
482 if (!tmp_msg) {
483 return PSA_ERROR_DOES_NOT_EXIST;
484 }
485
486 (TO_CONTAINER(tmp_msg,
487 struct tfm_conn_handle_t,
488 internal_msg))->status = TFM_HANDLE_STATUS_ACTIVE;
489
490 spm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
491
492 return PSA_SUCCESS;
493}
494
495void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
496{
497 struct tfm_msg_body_t *msg = NULL;
498 struct tfm_conn_handle_t *conn_handle;
499
500 /* It is a fatal error if message handle is invalid */
501 msg = tfm_spm_get_msg_from_handle(msg_handle);
502 if (!msg) {
503 tfm_core_panic();
504 }
505
506 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
507 if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
508 tfm_core_panic();
509 }
510
511 msg->msg.rhandle = rhandle;
512 conn_handle = tfm_spm_to_handle_instance(msg_handle);
513
514 /* Store reverse handle for following client calls. */
515 tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
516}
517
518size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
519 void *buffer, size_t num_bytes)
520{
521 size_t bytes;
522 struct tfm_msg_body_t *msg = NULL;
523 uint32_t privileged;
524 struct partition_t *partition = NULL;
525
526 /* It is a fatal error if message handle is invalid */
527 msg = tfm_spm_get_msg_from_handle(msg_handle);
528 if (!msg) {
529 tfm_core_panic();
530 }
531
532 partition = msg->service->partition;
533 privileged = tfm_spm_partition_get_privileged_mode(
534 partition->p_ldinf->flags);
535
536 /*
537 * It is a fatal error if message handle does not refer to a request
538 * message
539 */
540 if (msg->msg.type < PSA_IPC_CALL) {
541 tfm_core_panic();
542 }
543
544 /*
545 * It is a fatal error if invec_idx is equal to or greater than
546 * PSA_MAX_IOVEC
547 */
548 if (invec_idx >= PSA_MAX_IOVEC) {
549 tfm_core_panic();
550 }
551
552 /* There was no remaining data in this input vector */
553 if (msg->msg.in_size[invec_idx] == 0) {
554 return 0;
555 }
556
557 /*
558 * Copy the client data to the service buffer. It is a fatal error
559 * if the memory reference for buffer is invalid or not read-write.
560 */
561 if (tfm_memory_check(buffer, num_bytes, false,
562 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
563 tfm_core_panic();
564 }
565
566 bytes = num_bytes > msg->msg.in_size[invec_idx] ?
567 msg->msg.in_size[invec_idx] : num_bytes;
568
569 spm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
570
571 /* There maybe some remaining data */
572 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
573 msg->msg.in_size[invec_idx] -= bytes;
574
575 return bytes;
576}
577
578size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
579 size_t num_bytes)
580{
581 struct tfm_msg_body_t *msg = NULL;
582
583 /* It is a fatal error if message handle is invalid */
584 msg = tfm_spm_get_msg_from_handle(msg_handle);
585 if (!msg) {
586 tfm_core_panic();
587 }
588
589 /*
590 * It is a fatal error if message handle does not refer to a request
591 * message
592 */
593 if (msg->msg.type < PSA_IPC_CALL) {
594 tfm_core_panic();
595 }
596
597 /*
598 * It is a fatal error if invec_idx is equal to or greater than
599 * PSA_MAX_IOVEC
600 */
601 if (invec_idx >= PSA_MAX_IOVEC) {
602 tfm_core_panic();
603 }
604
605 /* There was no remaining data in this input vector */
606 if (msg->msg.in_size[invec_idx] == 0) {
607 return 0;
608 }
609
610 /*
611 * If num_bytes is greater than the remaining size of the input vector then
612 * the remaining size of the input vector is used.
613 */
614 if (num_bytes > msg->msg.in_size[invec_idx]) {
615 num_bytes = msg->msg.in_size[invec_idx];
616 }
617
618 /* There maybe some remaining data */
619 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
620 num_bytes;
621 msg->msg.in_size[invec_idx] -= num_bytes;
622
623 return num_bytes;
624}
625
626void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
627 const void *buffer, size_t num_bytes)
628{
629 struct tfm_msg_body_t *msg = NULL;
630 uint32_t privileged;
631 struct partition_t *partition = NULL;
632
633 /* It is a fatal error if message handle is invalid */
634 msg = tfm_spm_get_msg_from_handle(msg_handle);
635 if (!msg) {
636 tfm_core_panic();
637 }
638
639 partition = msg->service->partition;
640 privileged = tfm_spm_partition_get_privileged_mode(
641 partition->p_ldinf->flags);
642
643 /*
644 * It is a fatal error if message handle does not refer to a request
645 * message
646 */
647 if (msg->msg.type < PSA_IPC_CALL) {
648 tfm_core_panic();
649 }
650
651 /*
652 * It is a fatal error if outvec_idx is equal to or greater than
653 * PSA_MAX_IOVEC
654 */
655 if (outvec_idx >= PSA_MAX_IOVEC) {
656 tfm_core_panic();
657 }
658
659 /*
660 * It is a fatal error if the call attempts to write data past the end of
661 * the client output vector
662 */
663 if (num_bytes > msg->msg.out_size[outvec_idx] -
664 msg->outvec[outvec_idx].len) {
665 tfm_core_panic();
666 }
667
668 /*
669 * Copy the service buffer to client outvecs. It is a fatal error
670 * if the memory reference for buffer is invalid or not readable.
671 */
672 if (tfm_memory_check(buffer, num_bytes, false,
673 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
674 tfm_core_panic();
675 }
676
677 spm_memcpy((char *)msg->outvec[outvec_idx].base +
678 msg->outvec[outvec_idx].len, buffer, num_bytes);
679
680 /* Update the write number */
681 msg->outvec[outvec_idx].len += num_bytes;
682}
683
684void tfm_spm_partition_psa_reply(psa_handle_t msg_handle, psa_status_t status)
685{
686 struct service_t *service = NULL;
687 struct tfm_msg_body_t *msg = NULL;
688 int32_t ret = PSA_SUCCESS;
689 struct tfm_conn_handle_t *conn_handle;
690
691 /* It is a fatal error if message handle is invalid */
692 msg = tfm_spm_get_msg_from_handle(msg_handle);
693 if (!msg) {
694 tfm_core_panic();
695 }
696
697 /*
698 * RoT Service information is needed in this function, stored it in message
699 * body structure. Only two parameters are passed in this function: handle
700 * and status, so it is useful and simply to do like this.
701 */
702 service = msg->service;
703 if (!service) {
704 tfm_core_panic();
705 }
706
707 /*
708 * Three type of message are passed in this function: CONNECTION, REQUEST,
709 * DISCONNECTION. It needs to process differently for each type.
710 */
711 conn_handle = tfm_spm_to_handle_instance(msg_handle);
712 switch (msg->msg.type) {
713 case PSA_IPC_CONNECT:
714 /*
715 * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
716 * input status is PSA_SUCCESS. Others return values are based on the
717 * input status.
718 */
719 if (status == PSA_SUCCESS) {
720 ret = msg_handle;
721 } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
722 /* Refuse the client connection, indicating a permanent error. */
723 tfm_spm_free_conn_handle(service, conn_handle);
724 ret = PSA_ERROR_CONNECTION_REFUSED;
725 } else if (status == PSA_ERROR_CONNECTION_BUSY) {
726 /* Fail the client connection, indicating a transient error. */
727 ret = PSA_ERROR_CONNECTION_BUSY;
728 } else {
729 tfm_core_panic();
730 }
731 break;
732 case PSA_IPC_DISCONNECT:
733 /* Service handle is not used anymore */
734 tfm_spm_free_conn_handle(service, conn_handle);
735
736 /*
737 * If the message type is PSA_IPC_DISCONNECT, then the status code is
738 * ignored
739 */
740 break;
741 default:
742 if (msg->msg.type >= PSA_IPC_CALL) {
743 /* Reply to a request message. Return values are based on status */
744 ret = status;
745 /*
746 * The total number of bytes written to a single parameter must be
747 * reported to the client by updating the len member of the
748 * psa_outvec structure for the parameter before returning from
749 * psa_call().
750 */
751 update_caller_outvec_len(msg);
752 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
753 tfm_spm_free_conn_handle(service, conn_handle);
754 }
755 } else {
756 tfm_core_panic();
757 }
758 }
759
760 if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
761 /*
762 * If the source of the programmer error is a Secure Partition, the SPM
763 * must panic the Secure Partition in response to a PROGRAMMER ERROR.
764 */
765 if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
766 conn_handle->status = TFM_HANDLE_STATUS_CONNECT_ERROR;
767 } else {
768 tfm_core_panic();
769 }
770 } else {
771 conn_handle->status = TFM_HANDLE_STATUS_IDLE;
772 }
773
774 if (is_tfm_rpc_msg(msg)) {
775 tfm_rpc_client_call_reply(msg, ret);
776 } else {
777 tfm_event_wake(&msg->ack_evnt, ret);
778 }
779}
780
781void tfm_spm_partition_psa_notify(int32_t partition_id)
782{
783 notify_with_signal(partition_id, PSA_DOORBELL);
784}
785
786void tfm_spm_partition_psa_clear(void)
787{
788 struct partition_t *partition = NULL;
789
790 partition = tfm_spm_get_running_partition();
791 if (!partition) {
792 tfm_core_panic();
793 }
794
795 /*
796 * It is a fatal error if the Secure Partition's doorbell signal is not
797 * currently asserted.
798 */
799 if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
800 tfm_core_panic();
801 }
802 partition->signals_asserted &= ~PSA_DOORBELL;
803}
804
805void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
806{
807 struct irq_load_info_t *irq_info = NULL;
808 struct partition_t *partition = NULL;
809
810 partition = tfm_spm_get_running_partition();
811 if (!partition) {
812 tfm_core_panic();
813 }
814
815 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
816 /* It is a fatal error if passed signal is not an interrupt signal. */
817 if (!irq_info) {
818 tfm_core_panic();
819 }
820
821 if (irq_info->flih_func) {
822 /* This API is for SLIH IRQs only */
823 psa_panic();
824 }
825
826 /* It is a fatal error if passed signal is not currently asserted */
827 if ((partition->signals_asserted & irq_signal) == 0) {
828 tfm_core_panic();
829 }
830
831 partition->signals_asserted &= ~irq_signal;
832
833 tfm_spm_hal_clear_pending_irq((IRQn_Type)(irq_info->source));
834 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
835}
836
837void tfm_spm_partition_psa_panic(void)
838{
839 /*
840 * PSA FF recommends that the SPM causes the system to restart when a secure
841 * partition panics.
842 */
843 tfm_hal_system_reset();
844}
845
846void tfm_spm_partition_irq_enable(psa_signal_t irq_signal)
847{
848 struct partition_t *partition;
849 struct irq_load_info_t *irq_info;
850
851 partition = tfm_spm_get_running_partition();
852 if (!partition) {
853 tfm_core_panic();
854 }
855
856 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
857 if (!irq_info) {
858 tfm_core_panic();
859 }
860
861 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
862}
863
864psa_irq_status_t tfm_spm_partition_irq_disable(psa_signal_t irq_signal)
865{
866 struct partition_t *partition;
867 struct irq_load_info_t *irq_info;
868
869 partition = tfm_spm_get_running_partition();
870 if (!partition) {
871 tfm_core_panic();
872 }
873
874 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
875 if (!irq_info) {
876 tfm_core_panic();
877 }
878
879 tfm_spm_hal_disable_irq((IRQn_Type)(irq_info->source));
880
881 return 1;
882}
883
884void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
885{
886 struct irq_load_info_t *irq_info;
887 struct partition_t *partition;
888
889 partition = tfm_spm_get_running_partition();
890 if (!partition) {
891 tfm_core_panic();
892 }
893
894 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
895 if (!irq_info) {
896 tfm_core_panic();
897 }
898
899 if (!irq_info->flih_func) {
900 /* This API is for FLIH IRQs only */
901 tfm_core_panic();
902 }
903
904 if ((partition->signals_asserted & irq_signal) == 0) {
905 /* The signal is not asserted */
906 tfm_core_panic();
907 }
908
909 partition->signals_asserted &= ~irq_signal;
910}