blob: eee754befac17b5d0d69f9f1c27650640c2ab1b1 [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"
David Hu733d8f92019-09-23 15:32:40 +080011#include "tfm_core_utils.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080012#include "load/partition_defs.h"
Mingyang Sun2b352662021-04-21 11:35:43 +080013#include "load/service_defs.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080014#include "load/irq_defs.h"
Mingyang Sun133a7922021-07-08 16:01:26 +080015#include "psa_api.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080016#include "utilities.h"
David Hu733d8f92019-09-23 15:32:40 +080017#include "tfm_wait.h"
Summer Qin1ce712a2019-10-14 18:04:05 +080018#include "tfm_nspm.h"
Ken Liubcae38b2021-01-20 15:47:44 +080019#include "ffm/spm_error_base.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080020#include "tfm_rpc.h"
21#include "tfm_spm_hal.h"
22#include "tfm_hal_platform.h"
David Hu733d8f92019-09-23 15:32:40 +080023
Ken Liub3b2cb62021-05-22 00:39:28 +080024#define GET_STATELESS_SERVICE(index) (stateless_services_ref_tbl[index])
Xinyu Zhanga38e9b52021-06-02 17:48:01 +080025extern struct service_t *stateless_services_ref_tbl[];
Mingyang Suncb6f70e2021-03-05 23:30:25 +080026
Mingyang Sund44522a2020-01-16 16:48:37 +080027uint32_t tfm_spm_client_psa_framework_version(void)
David Hu733d8f92019-09-23 15:32:40 +080028{
29 return PSA_FRAMEWORK_VERSION;
30}
31
Mingyang Sund44522a2020-01-16 16:48:37 +080032uint32_t tfm_spm_client_psa_version(uint32_t sid, bool ns_caller)
David Hu733d8f92019-09-23 15:32:40 +080033{
Mingyang Sun783a59b2021-04-20 15:52:18 +080034 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +080035
36 /*
37 * It should return PSA_VERSION_NONE if the RoT Service is not
38 * implemented.
39 */
40 service = tfm_spm_get_service_by_sid(sid);
41 if (!service) {
42 return PSA_VERSION_NONE;
43 }
44
45 /*
Shawn Shan2365c902019-12-19 18:35:36 +080046 * It should return PSA_VERSION_NONE if the caller is not authorized
47 * to access the RoT Service.
David Hu733d8f92019-09-23 15:32:40 +080048 */
Ken Liubcae38b2021-01-20 15:47:44 +080049 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
Shawn Shan2365c902019-12-19 18:35:36 +080050 return PSA_VERSION_NONE;
David Hu733d8f92019-09-23 15:32:40 +080051 }
52
Ken Liuacd2a572021-05-12 16:19:04 +080053 return service->p_ldinf->version;
David Hu733d8f92019-09-23 15:32:40 +080054}
55
Mingyang Sund44522a2020-01-16 16:48:37 +080056psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version,
57 bool ns_caller)
David Hu733d8f92019-09-23 15:32:40 +080058{
Mingyang Sun783a59b2021-04-20 15:52:18 +080059 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +080060 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +080061 struct tfm_conn_handle_t *connect_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +080062 int32_t client_id;
Ken Liu505b1702020-05-29 13:19:58 +080063 psa_handle_t handle;
David Hu733d8f92019-09-23 15:32:40 +080064
Kevin Pengedb8ee42021-03-09 16:50:11 +080065 /*
66 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
67 * platform.
68 */
David Hu733d8f92019-09-23 15:32:40 +080069 service = tfm_spm_get_service_by_sid(sid);
70 if (!service) {
Shawn Shanb222d892021-01-04 17:41:48 +080071 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
David Hu733d8f92019-09-23 15:32:40 +080072 }
73
Mingyang Sunef42f442021-06-11 15:07:58 +080074 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
75 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
76 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
77 }
78
Kevin Pengedb8ee42021-03-09 16:50:11 +080079 /*
80 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
81 * RoT Service.
82 */
83 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
84 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
85 }
86
87 /*
88 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
89 * not supported on the platform.
90 */
91 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
92 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
93 }
94
Summer Qin1ce712a2019-10-14 18:04:05 +080095 if (ns_caller) {
96 client_id = tfm_nspm_get_current_client_id();
97 } else {
98 client_id = tfm_spm_partition_get_running_partition_id();
99 }
100
David Hu733d8f92019-09-23 15:32:40 +0800101 /*
102 * Create connection handle here since it is possible to return the error
103 * code to client when creation fails.
104 */
Summer Qin1ce712a2019-10-14 18:04:05 +0800105 connect_handle = tfm_spm_create_conn_handle(service, client_id);
Summer Qin630c76b2020-05-20 10:32:58 +0800106 if (!connect_handle) {
David Hu733d8f92019-09-23 15:32:40 +0800107 return PSA_ERROR_CONNECTION_BUSY;
108 }
109
Kevin Pengdf6aa292021-03-11 17:58:50 +0800110 msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
111 if (!msg) {
112 /* Have no enough resource to create message */
113 return PSA_ERROR_CONNECTION_BUSY;
114 }
David Hu733d8f92019-09-23 15:32:40 +0800115
Ken Liu505b1702020-05-29 13:19:58 +0800116 handle = tfm_spm_to_user_handle(connect_handle);
David Hu733d8f92019-09-23 15:32:40 +0800117 /* No input or output needed for connect message */
Ken Liu505b1702020-05-29 13:19:58 +0800118 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
Summer Qin1ce712a2019-10-14 18:04:05 +0800119 client_id, NULL, 0, NULL, 0, NULL);
David Hu733d8f92019-09-23 15:32:40 +0800120
121 /*
122 * Send message and wake up the SP who is waiting on message queue,
123 * and scheduler triggered
124 */
125 tfm_spm_send_event(service, msg);
126
127 return PSA_SUCCESS;
128}
129
Mingyang Sund44522a2020-01-16 16:48:37 +0800130psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, int32_t type,
131 const psa_invec *inptr, size_t in_num,
132 psa_outvec *outptr, size_t out_num,
133 bool ns_caller, uint32_t privileged)
David Hu733d8f92019-09-23 15:32:40 +0800134{
135 psa_invec invecs[PSA_MAX_IOVEC];
136 psa_outvec outvecs[PSA_MAX_IOVEC];
Summer Qin630c76b2020-05-20 10:32:58 +0800137 struct tfm_conn_handle_t *conn_handle;
Mingyang Sun783a59b2021-04-20 15:52:18 +0800138 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800139 struct tfm_msg_body_t *msg;
Summer Qinba2346e2019-11-12 16:26:31 +0800140 int i, j;
Summer Qin1ce712a2019-10-14 18:04:05 +0800141 int32_t client_id;
Mingyang Sun453ad402021-03-17 17:58:33 +0800142 uint32_t sid, version, index;
David Hu733d8f92019-09-23 15:32:40 +0800143
Shawn Shanb222d892021-01-04 17:41:48 +0800144 /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
David Hu733d8f92019-09-23 15:32:40 +0800145 if ((in_num > PSA_MAX_IOVEC) ||
146 (out_num > PSA_MAX_IOVEC) ||
147 (in_num + out_num > PSA_MAX_IOVEC)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800148 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800149 }
150
Summer Qin1ce712a2019-10-14 18:04:05 +0800151 if (ns_caller) {
152 client_id = tfm_nspm_get_current_client_id();
153 } else {
154 client_id = tfm_spm_partition_get_running_partition_id();
155 }
156
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800157 /* Allocate space from handle pool for static handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800158 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun453ad402021-03-17 17:58:33 +0800159 index = GET_INDEX_FROM_STATIC_HANDLE(handle);
Mingyang Sune8d38082021-03-30 18:34:40 +0800160
161 if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
162 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
163 }
164
Mingyang Sun453ad402021-03-17 17:58:33 +0800165 service = GET_STATELESS_SERVICE(index);
Mingyang Sun86213242021-07-14 10:26:43 +0800166 if (!service) {
167 tfm_core_panic();
168 }
169
Ken Liub3b2cb62021-05-22 00:39:28 +0800170 sid = service->p_ldinf->sid;
Mingyang Sun453ad402021-03-17 17:58:33 +0800171
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800172 /*
173 * It is a PROGRAMMER ERROR if the caller is not authorized to access
174 * the RoT Service.
175 */
176 if (tfm_spm_check_authorization(sid, service, ns_caller)
177 != SPM_SUCCESS) {
178 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
179 }
180
Mingyang Sun453ad402021-03-17 17:58:33 +0800181 version = GET_VERSION_FROM_STATIC_HANDLE(handle);
182
183 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
184 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
185 }
186
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800187 conn_handle = tfm_spm_create_conn_handle(service, client_id);
188
189 if (!conn_handle) {
190 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_BUSY);
191 }
192
Mingyang Sun6d5dc3d2021-03-15 15:34:44 +0800193 conn_handle->rhandle = NULL;
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800194 handle = tfm_spm_to_user_handle(conn_handle);
195 } else {
196 conn_handle = tfm_spm_to_handle_instance(handle);
197
198 /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
199 if (tfm_spm_validate_conn_handle(conn_handle, client_id)
200 != SPM_SUCCESS) {
201 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
202 }
203
204 /*
205 * It is a PROGRAMMER ERROR if the connection is currently
206 * handling a request.
207 */
208 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
209 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
210 }
211
212 /*
213 * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
214 * has been terminated by the RoT Service.
215 */
216 if (conn_handle->status == TFM_HANDLE_STATUS_CONNECT_ERROR) {
217 return PSA_ERROR_PROGRAMMER_ERROR;
218 }
219
220 service = conn_handle->service;
Summer Qin1ce712a2019-10-14 18:04:05 +0800221 }
Shawn Shanb222d892021-01-04 17:41:48 +0800222
David Hu733d8f92019-09-23 15:32:40 +0800223 if (!service) {
224 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800225 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800226 }
227
Kevin Pengedb8ee42021-03-09 16:50:11 +0800228 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800229 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
David Hu733d8f92019-09-23 15:32:40 +0800230 * if the memory reference for the wrap input vector is invalid or not
231 * readable.
232 */
233 if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800234 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800235 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800236 }
Summer Qinba2346e2019-11-12 16:26:31 +0800237
David Hu733d8f92019-09-23 15:32:40 +0800238 /*
239 * Read client outvecs from the wrap output vector and will update the
Shawn Shanb222d892021-01-04 17:41:48 +0800240 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
David Hu733d8f92019-09-23 15:32:40 +0800241 * the wrap output vector is invalid or not read-write.
242 */
243 if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800244 TFM_MEMORY_ACCESS_RW, 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 }
247
Summer Qinf24dbb52020-07-23 14:53:54 +0800248 spm_memset(invecs, 0, sizeof(invecs));
249 spm_memset(outvecs, 0, sizeof(outvecs));
David Hu733d8f92019-09-23 15:32:40 +0800250
251 /* Copy the address out to avoid TOCTOU attacks. */
Summer Qinf24dbb52020-07-23 14:53:54 +0800252 spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
253 spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
David Hu733d8f92019-09-23 15:32:40 +0800254
255 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800256 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
David Hu733d8f92019-09-23 15:32:40 +0800257 * memory reference was invalid or not readable.
258 */
259 for (i = 0; i < in_num; i++) {
260 if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800261 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800262 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800263 }
264 }
Summer Qinba2346e2019-11-12 16:26:31 +0800265
266 /*
267 * Clients must never overlap input parameters because of the risk of a
268 * double-fetch inconsistency.
269 * Overflow is checked in tfm_memory_check functions.
270 */
271 for (i = 0; i + 1 < in_num; i++) {
272 for (j = i+1; j < in_num; j++) {
TTornblom83d96372019-11-19 12:53:16 +0100273 if (!((char *) invecs[j].base + invecs[j].len <=
274 (char *) invecs[i].base ||
275 (char *) invecs[j].base >=
276 (char *) invecs[i].base + invecs[i].len)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800277 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
Summer Qinba2346e2019-11-12 16:26:31 +0800278 }
279 }
280 }
281
David Hu733d8f92019-09-23 15:32:40 +0800282 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800283 * For client output vector, it is a PROGRAMMER ERROR if the provided
284 * payload memory reference was invalid or not read-write.
David Hu733d8f92019-09-23 15:32:40 +0800285 */
286 for (i = 0; i < out_num; i++) {
287 if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
Ken Liubcae38b2021-01-20 15:47:44 +0800288 ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800289 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800290 }
291 }
292
293 /*
294 * FixMe: Need to check if the message is unrecognized by the RoT
295 * Service or incorrectly formatted.
296 */
Kevin Pengdf6aa292021-03-11 17:58:50 +0800297 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
298 if (!msg) {
299 /* FixMe: Need to implement one mechanism to resolve this failure. */
300 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
301 }
David Hu733d8f92019-09-23 15:32:40 +0800302
Ken Liu505b1702020-05-29 13:19:58 +0800303 tfm_spm_fill_msg(msg, service, handle, type, client_id,
Summer Qin630c76b2020-05-20 10:32:58 +0800304 invecs, in_num, outvecs, out_num, outptr);
David Hu733d8f92019-09-23 15:32:40 +0800305
306 /*
307 * Send message and wake up the SP who is waiting on message queue,
308 * and scheduler triggered
309 */
Kevin Peng8dac6102021-03-09 16:44:00 +0800310 tfm_spm_send_event(service, msg);
311
David Hu733d8f92019-09-23 15:32:40 +0800312 return PSA_SUCCESS;
313}
314
Mingyang Sund44522a2020-01-16 16:48:37 +0800315void tfm_spm_client_psa_close(psa_handle_t handle, bool ns_caller)
David Hu733d8f92019-09-23 15:32:40 +0800316{
Mingyang Sun783a59b2021-04-20 15:52:18 +0800317 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800318 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +0800319 struct tfm_conn_handle_t *conn_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +0800320 int32_t client_id;
David Hu733d8f92019-09-23 15:32:40 +0800321
322 /* It will have no effect if called with the NULL handle */
323 if (handle == PSA_NULL_HANDLE) {
324 return;
325 }
326
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800327 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800328 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800329 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
330 }
331
Summer Qin1ce712a2019-10-14 18:04:05 +0800332 if (ns_caller) {
333 client_id = tfm_nspm_get_current_client_id();
334 } else {
335 client_id = tfm_spm_partition_get_running_partition_id();
336 }
337
Summer Qin373feb12020-03-27 15:35:33 +0800338 conn_handle = tfm_spm_to_handle_instance(handle);
David Hu733d8f92019-09-23 15:32:40 +0800339 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800340 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
341 * the null handle.
David Hu733d8f92019-09-23 15:32:40 +0800342 */
Ken Liubcae38b2021-01-20 15:47:44 +0800343 if (tfm_spm_validate_conn_handle(conn_handle, client_id) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800344 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Summer Qin1ce712a2019-10-14 18:04:05 +0800345 }
Shawn Shanb222d892021-01-04 17:41:48 +0800346
Summer Qin630c76b2020-05-20 10:32:58 +0800347 service = conn_handle->service;
David Hu733d8f92019-09-23 15:32:40 +0800348 if (!service) {
349 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800350 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800351 }
352
Kevin Pengdf6aa292021-03-11 17:58:50 +0800353 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
354 if (!msg) {
355 /* FixMe: Need to implement one mechanism to resolve this failure. */
356 tfm_core_panic();
357 }
David Hu733d8f92019-09-23 15:32:40 +0800358
Shawn Shanb222d892021-01-04 17:41:48 +0800359 /*
360 * It is a PROGRAMMER ERROR if the connection is currently handling a
361 * request.
362 */
Summer Qin630c76b2020-05-20 10:32:58 +0800363 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
Shawn Shanb222d892021-01-04 17:41:48 +0800364 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Shawn Shancc39fcb2019-11-13 15:38:16 +0800365 }
366
David Hu733d8f92019-09-23 15:32:40 +0800367 /* No input or output needed for close message */
Ken Liu505b1702020-05-29 13:19:58 +0800368 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
David Hu733d8f92019-09-23 15:32:40 +0800369 NULL, 0, NULL, 0, NULL);
370
371 /*
372 * Send message and wake up the SP who is waiting on message queue,
373 * and scheduler triggered
374 */
375 tfm_spm_send_event(service, msg);
376}
Mingyang Sunb26b2802021-07-07 11:25:00 +0800377
378psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
379 uint32_t timeout)
380{
381 struct partition_t *partition = NULL;
382
383 /*
384 * Timeout[30:0] are reserved for future use.
385 * SPM must ignore the value of RES.
386 */
387 timeout &= PSA_TIMEOUT_MASK;
388
389 partition = tfm_spm_get_running_partition();
390 if (!partition) {
391 tfm_core_panic();
392 }
393
394 /*
395 * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
396 * signals.
397 */
398 if ((partition->signals_allowed & signal_mask) == 0) {
399 tfm_core_panic();
400 }
401
402 /*
403 * tfm_event_wait() blocks the caller thread if no signals are available.
404 * In this case, the return value of this function is temporary set into
405 * runtime context. After new signal(s) are available, the return value
406 * is updated with the available signal(s) and blocked thread gets to run.
407 */
408 if (timeout == PSA_BLOCK &&
409 (partition->signals_asserted & signal_mask) == 0) {
410 partition->signals_waiting = signal_mask;
411 tfm_event_wait(&partition->event);
412 } else if ((partition->signals_asserted & signal_mask) == 0) {
413 /* Activate scheduler to check if any higher priority thread to run */
414 tfm_core_thrd_activate_schedule();
415 }
416
417 return partition->signals_asserted & signal_mask;
418}
419
420psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
421{
422 struct tfm_msg_body_t *tmp_msg = NULL;
423 struct partition_t *partition = NULL;
424 uint32_t privileged;
425
426 /*
427 * Only one message could be retrieved every time for psa_get(). It is a
428 * fatal error if the input signal has more than a signal bit set.
429 */
430 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
431 tfm_core_panic();
432 }
433
434 partition = tfm_spm_get_running_partition();
435 if (!partition) {
436 tfm_core_panic();
437 }
438 privileged = tfm_spm_partition_get_privileged_mode(
439 partition->p_ldinf->flags);
440
441 /*
442 * Write the message to the service buffer. It is a fatal error if the
443 * input msg pointer is not a valid memory reference or not read-write.
444 */
445 if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
446 privileged) != SPM_SUCCESS) {
447 tfm_core_panic();
448 }
449
450 /*
451 * It is a fatal error if the caller call psa_get() when no message has
452 * been set. The caller must call this function after an RoT Service signal
453 * is returned by psa_wait().
454 */
455 if (partition->signals_asserted == 0) {
456 tfm_core_panic();
457 }
458
459 /*
460 * It is a fatal error if the RoT Service signal is not currently asserted.
461 */
462 if ((partition->signals_asserted & signal) == 0) {
463 tfm_core_panic();
464 }
465
466 /*
467 * Get message by signal from partition. It is a fatal error if getting
468 * failed, which means the input signal is not correspond to an RoT service.
469 */
470 tmp_msg = tfm_spm_get_msg_by_signal(partition, signal);
471 if (!tmp_msg) {
472 return PSA_ERROR_DOES_NOT_EXIST;
473 }
474
475 (TO_CONTAINER(tmp_msg,
476 struct tfm_conn_handle_t,
477 internal_msg))->status = TFM_HANDLE_STATUS_ACTIVE;
478
479 spm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
480
481 return PSA_SUCCESS;
482}
483
484void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
485{
486 struct tfm_msg_body_t *msg = NULL;
487 struct tfm_conn_handle_t *conn_handle;
488
489 /* It is a fatal error if message handle is invalid */
490 msg = tfm_spm_get_msg_from_handle(msg_handle);
491 if (!msg) {
492 tfm_core_panic();
493 }
494
495 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
496 if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
497 tfm_core_panic();
498 }
499
500 msg->msg.rhandle = rhandle;
501 conn_handle = tfm_spm_to_handle_instance(msg_handle);
502
503 /* Store reverse handle for following client calls. */
504 tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
505}
506
507size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
508 void *buffer, size_t num_bytes)
509{
510 size_t bytes;
511 struct tfm_msg_body_t *msg = NULL;
512 uint32_t privileged;
513 struct partition_t *partition = NULL;
514
515 /* It is a fatal error if message handle is invalid */
516 msg = tfm_spm_get_msg_from_handle(msg_handle);
517 if (!msg) {
518 tfm_core_panic();
519 }
520
521 partition = msg->service->partition;
522 privileged = tfm_spm_partition_get_privileged_mode(
523 partition->p_ldinf->flags);
524
525 /*
526 * It is a fatal error if message handle does not refer to a request
527 * message
528 */
529 if (msg->msg.type < PSA_IPC_CALL) {
530 tfm_core_panic();
531 }
532
533 /*
534 * It is a fatal error if invec_idx is equal to or greater than
535 * PSA_MAX_IOVEC
536 */
537 if (invec_idx >= PSA_MAX_IOVEC) {
538 tfm_core_panic();
539 }
540
541 /* There was no remaining data in this input vector */
542 if (msg->msg.in_size[invec_idx] == 0) {
543 return 0;
544 }
545
546 /*
547 * Copy the client data to the service buffer. It is a fatal error
548 * if the memory reference for buffer is invalid or not read-write.
549 */
550 if (tfm_memory_check(buffer, num_bytes, false,
551 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
552 tfm_core_panic();
553 }
554
555 bytes = num_bytes > msg->msg.in_size[invec_idx] ?
556 msg->msg.in_size[invec_idx] : num_bytes;
557
558 spm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
559
560 /* There maybe some remaining data */
561 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
562 msg->msg.in_size[invec_idx] -= bytes;
563
564 return bytes;
565}
566
567size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
568 size_t num_bytes)
569{
570 struct tfm_msg_body_t *msg = NULL;
571
572 /* It is a fatal error if message handle is invalid */
573 msg = tfm_spm_get_msg_from_handle(msg_handle);
574 if (!msg) {
575 tfm_core_panic();
576 }
577
578 /*
579 * It is a fatal error if message handle does not refer to a request
580 * message
581 */
582 if (msg->msg.type < PSA_IPC_CALL) {
583 tfm_core_panic();
584 }
585
586 /*
587 * It is a fatal error if invec_idx is equal to or greater than
588 * PSA_MAX_IOVEC
589 */
590 if (invec_idx >= PSA_MAX_IOVEC) {
591 tfm_core_panic();
592 }
593
594 /* There was no remaining data in this input vector */
595 if (msg->msg.in_size[invec_idx] == 0) {
596 return 0;
597 }
598
599 /*
600 * If num_bytes is greater than the remaining size of the input vector then
601 * the remaining size of the input vector is used.
602 */
603 if (num_bytes > msg->msg.in_size[invec_idx]) {
604 num_bytes = msg->msg.in_size[invec_idx];
605 }
606
607 /* There maybe some remaining data */
608 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
609 num_bytes;
610 msg->msg.in_size[invec_idx] -= num_bytes;
611
612 return num_bytes;
613}
614
615void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
616 const void *buffer, size_t num_bytes)
617{
618 struct tfm_msg_body_t *msg = NULL;
619 uint32_t privileged;
620 struct partition_t *partition = NULL;
621
622 /* It is a fatal error if message handle is invalid */
623 msg = tfm_spm_get_msg_from_handle(msg_handle);
624 if (!msg) {
625 tfm_core_panic();
626 }
627
628 partition = msg->service->partition;
629 privileged = tfm_spm_partition_get_privileged_mode(
630 partition->p_ldinf->flags);
631
632 /*
633 * It is a fatal error if message handle does not refer to a request
634 * message
635 */
636 if (msg->msg.type < PSA_IPC_CALL) {
637 tfm_core_panic();
638 }
639
640 /*
641 * It is a fatal error if outvec_idx is equal to or greater than
642 * PSA_MAX_IOVEC
643 */
644 if (outvec_idx >= PSA_MAX_IOVEC) {
645 tfm_core_panic();
646 }
647
648 /*
649 * It is a fatal error if the call attempts to write data past the end of
650 * the client output vector
651 */
652 if (num_bytes > msg->msg.out_size[outvec_idx] -
653 msg->outvec[outvec_idx].len) {
654 tfm_core_panic();
655 }
656
657 /*
658 * Copy the service buffer to client outvecs. It is a fatal error
659 * if the memory reference for buffer is invalid or not readable.
660 */
661 if (tfm_memory_check(buffer, num_bytes, false,
662 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
663 tfm_core_panic();
664 }
665
666 spm_memcpy((char *)msg->outvec[outvec_idx].base +
667 msg->outvec[outvec_idx].len, buffer, num_bytes);
668
669 /* Update the write number */
670 msg->outvec[outvec_idx].len += num_bytes;
671}
672
673void tfm_spm_partition_psa_reply(psa_handle_t msg_handle, psa_status_t status)
674{
675 struct service_t *service = NULL;
676 struct tfm_msg_body_t *msg = NULL;
677 int32_t ret = PSA_SUCCESS;
678 struct tfm_conn_handle_t *conn_handle;
679
680 /* It is a fatal error if message handle is invalid */
681 msg = tfm_spm_get_msg_from_handle(msg_handle);
682 if (!msg) {
683 tfm_core_panic();
684 }
685
686 /*
687 * RoT Service information is needed in this function, stored it in message
688 * body structure. Only two parameters are passed in this function: handle
689 * and status, so it is useful and simply to do like this.
690 */
691 service = msg->service;
692 if (!service) {
693 tfm_core_panic();
694 }
695
696 /*
697 * Three type of message are passed in this function: CONNECTION, REQUEST,
698 * DISCONNECTION. It needs to process differently for each type.
699 */
700 conn_handle = tfm_spm_to_handle_instance(msg_handle);
701 switch (msg->msg.type) {
702 case PSA_IPC_CONNECT:
703 /*
704 * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
705 * input status is PSA_SUCCESS. Others return values are based on the
706 * input status.
707 */
708 if (status == PSA_SUCCESS) {
709 ret = msg_handle;
710 } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
711 /* Refuse the client connection, indicating a permanent error. */
712 tfm_spm_free_conn_handle(service, conn_handle);
713 ret = PSA_ERROR_CONNECTION_REFUSED;
714 } else if (status == PSA_ERROR_CONNECTION_BUSY) {
715 /* Fail the client connection, indicating a transient error. */
716 ret = PSA_ERROR_CONNECTION_BUSY;
717 } else {
718 tfm_core_panic();
719 }
720 break;
721 case PSA_IPC_DISCONNECT:
722 /* Service handle is not used anymore */
723 tfm_spm_free_conn_handle(service, conn_handle);
724
725 /*
726 * If the message type is PSA_IPC_DISCONNECT, then the status code is
727 * ignored
728 */
729 break;
730 default:
731 if (msg->msg.type >= PSA_IPC_CALL) {
732 /* Reply to a request message. Return values are based on status */
733 ret = status;
734 /*
735 * The total number of bytes written to a single parameter must be
736 * reported to the client by updating the len member of the
737 * psa_outvec structure for the parameter before returning from
738 * psa_call().
739 */
740 update_caller_outvec_len(msg);
741 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
742 tfm_spm_free_conn_handle(service, conn_handle);
743 }
744 } else {
745 tfm_core_panic();
746 }
747 }
748
749 if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
750 /*
751 * If the source of the programmer error is a Secure Partition, the SPM
752 * must panic the Secure Partition in response to a PROGRAMMER ERROR.
753 */
754 if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
755 conn_handle->status = TFM_HANDLE_STATUS_CONNECT_ERROR;
756 } else {
757 tfm_core_panic();
758 }
759 } else {
760 conn_handle->status = TFM_HANDLE_STATUS_IDLE;
761 }
762
763 if (is_tfm_rpc_msg(msg)) {
764 tfm_rpc_client_call_reply(msg, ret);
765 } else {
766 tfm_event_wake(&msg->ack_evnt, ret);
767 }
768}
769
770void tfm_spm_partition_psa_notify(int32_t partition_id)
771{
772 notify_with_signal(partition_id, PSA_DOORBELL);
773}
774
775void tfm_spm_partition_psa_clear(void)
776{
777 struct partition_t *partition = NULL;
778
779 partition = tfm_spm_get_running_partition();
780 if (!partition) {
781 tfm_core_panic();
782 }
783
784 /*
785 * It is a fatal error if the Secure Partition's doorbell signal is not
786 * currently asserted.
787 */
788 if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
789 tfm_core_panic();
790 }
791 partition->signals_asserted &= ~PSA_DOORBELL;
792}
793
794void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
795{
796 struct irq_load_info_t *irq_info = NULL;
797 struct partition_t *partition = NULL;
798
799 partition = tfm_spm_get_running_partition();
800 if (!partition) {
801 tfm_core_panic();
802 }
803
804 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
805 /* It is a fatal error if passed signal is not an interrupt signal. */
806 if (!irq_info) {
807 tfm_core_panic();
808 }
809
810 if (irq_info->flih_func) {
811 /* This API is for SLIH IRQs only */
812 psa_panic();
813 }
814
815 /* It is a fatal error if passed signal is not currently asserted */
816 if ((partition->signals_asserted & irq_signal) == 0) {
817 tfm_core_panic();
818 }
819
820 partition->signals_asserted &= ~irq_signal;
821
822 tfm_spm_hal_clear_pending_irq((IRQn_Type)(irq_info->source));
823 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
824}
825
826void tfm_spm_partition_psa_panic(void)
827{
828 /*
829 * PSA FF recommends that the SPM causes the system to restart when a secure
830 * partition panics.
831 */
832 tfm_hal_system_reset();
833}
834
835void tfm_spm_partition_irq_enable(psa_signal_t irq_signal)
836{
837 struct partition_t *partition;
838 struct irq_load_info_t *irq_info;
839
840 partition = tfm_spm_get_running_partition();
841 if (!partition) {
842 tfm_core_panic();
843 }
844
845 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
846 if (!irq_info) {
847 tfm_core_panic();
848 }
849
850 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
851}
852
853psa_irq_status_t tfm_spm_partition_irq_disable(psa_signal_t irq_signal)
854{
855 struct partition_t *partition;
856 struct irq_load_info_t *irq_info;
857
858 partition = tfm_spm_get_running_partition();
859 if (!partition) {
860 tfm_core_panic();
861 }
862
863 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
864 if (!irq_info) {
865 tfm_core_panic();
866 }
867
868 tfm_spm_hal_disable_irq((IRQn_Type)(irq_info->source));
869
870 return 1;
871}
872
873void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
874{
875 struct irq_load_info_t *irq_info;
876 struct partition_t *partition;
877
878 partition = tfm_spm_get_running_partition();
879 if (!partition) {
880 tfm_core_panic();
881 }
882
883 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
884 if (!irq_info) {
885 tfm_core_panic();
886 }
887
888 if (!irq_info->flih_func) {
889 /* This API is for FLIH IRQs only */
890 tfm_core_panic();
891 }
892
893 if ((partition->signals_asserted & irq_signal) == 0) {
894 /* The signal is not asserted */
895 tfm_core_panic();
896 }
897
898 partition->signals_asserted &= ~irq_signal;
899}