blob: 54ea1d62ebfd98ab1ce4a7cad877d91a1a0905ee [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,
134 psa_outvec *outptr, size_t out_num,
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800135 uint32_t privileged)
David Hu733d8f92019-09-23 15:32:40 +0800136{
137 psa_invec invecs[PSA_MAX_IOVEC];
138 psa_outvec outvecs[PSA_MAX_IOVEC];
Summer Qin630c76b2020-05-20 10:32:58 +0800139 struct tfm_conn_handle_t *conn_handle;
Mingyang Sun783a59b2021-04-20 15:52:18 +0800140 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800141 struct tfm_msg_body_t *msg;
Summer Qinba2346e2019-11-12 16:26:31 +0800142 int i, j;
Summer Qin1ce712a2019-10-14 18:04:05 +0800143 int32_t client_id;
Mingyang Sun453ad402021-03-17 17:58:33 +0800144 uint32_t sid, version, index;
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
Kevin Pengedb8ee42021-03-09 16:50:11 +0800236 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800237 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
David Hu733d8f92019-09-23 15:32:40 +0800238 * if the memory reference for the wrap input vector is invalid or not
239 * readable.
240 */
241 if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800242 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800243 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800244 }
Summer Qinba2346e2019-11-12 16:26:31 +0800245
David Hu733d8f92019-09-23 15:32:40 +0800246 /*
247 * Read client outvecs from the wrap output vector and will update the
Shawn Shanb222d892021-01-04 17:41:48 +0800248 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
David Hu733d8f92019-09-23 15:32:40 +0800249 * the wrap output vector is invalid or not read-write.
250 */
251 if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800252 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800253 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800254 }
255
Summer Qinf24dbb52020-07-23 14:53:54 +0800256 spm_memset(invecs, 0, sizeof(invecs));
257 spm_memset(outvecs, 0, sizeof(outvecs));
David Hu733d8f92019-09-23 15:32:40 +0800258
259 /* Copy the address out to avoid TOCTOU attacks. */
Summer Qinf24dbb52020-07-23 14:53:54 +0800260 spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
261 spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
David Hu733d8f92019-09-23 15:32:40 +0800262
263 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800264 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
David Hu733d8f92019-09-23 15:32:40 +0800265 * memory reference was invalid or not readable.
266 */
267 for (i = 0; i < in_num; i++) {
268 if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800269 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800270 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800271 }
272 }
Summer Qinba2346e2019-11-12 16:26:31 +0800273
274 /*
275 * Clients must never overlap input parameters because of the risk of a
276 * double-fetch inconsistency.
277 * Overflow is checked in tfm_memory_check functions.
278 */
279 for (i = 0; i + 1 < in_num; i++) {
280 for (j = i+1; j < in_num; j++) {
TTornblom83d96372019-11-19 12:53:16 +0100281 if (!((char *) invecs[j].base + invecs[j].len <=
282 (char *) invecs[i].base ||
283 (char *) invecs[j].base >=
284 (char *) invecs[i].base + invecs[i].len)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800285 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
Summer Qinba2346e2019-11-12 16:26:31 +0800286 }
287 }
288 }
289
David Hu733d8f92019-09-23 15:32:40 +0800290 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800291 * For client output vector, it is a PROGRAMMER ERROR if the provided
292 * payload memory reference was invalid or not read-write.
David Hu733d8f92019-09-23 15:32:40 +0800293 */
294 for (i = 0; i < out_num; i++) {
295 if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
Ken Liubcae38b2021-01-20 15:47:44 +0800296 ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800297 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800298 }
299 }
300
301 /*
302 * FixMe: Need to check if the message is unrecognized by the RoT
303 * Service or incorrectly formatted.
304 */
Kevin Pengdf6aa292021-03-11 17:58:50 +0800305 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
306 if (!msg) {
307 /* FixMe: Need to implement one mechanism to resolve this failure. */
308 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
309 }
David Hu733d8f92019-09-23 15:32:40 +0800310
Ken Liu505b1702020-05-29 13:19:58 +0800311 tfm_spm_fill_msg(msg, service, handle, type, client_id,
Summer Qin630c76b2020-05-20 10:32:58 +0800312 invecs, in_num, outvecs, out_num, outptr);
David Hu733d8f92019-09-23 15:32:40 +0800313
314 /*
315 * Send message and wake up the SP who is waiting on message queue,
316 * and scheduler triggered
317 */
Kevin Peng8dac6102021-03-09 16:44:00 +0800318 tfm_spm_send_event(service, msg);
319
David Hu733d8f92019-09-23 15:32:40 +0800320 return PSA_SUCCESS;
321}
322
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800323void tfm_spm_client_psa_close(psa_handle_t handle)
David Hu733d8f92019-09-23 15:32:40 +0800324{
Mingyang Sun783a59b2021-04-20 15:52:18 +0800325 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800326 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +0800327 struct tfm_conn_handle_t *conn_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +0800328 int32_t client_id;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800329 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +0800330
331 /* It will have no effect if called with the NULL handle */
332 if (handle == PSA_NULL_HANDLE) {
333 return;
334 }
335
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800336 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800337 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800338 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
339 }
340
Summer Qin1ce712a2019-10-14 18:04:05 +0800341 if (ns_caller) {
342 client_id = tfm_nspm_get_current_client_id();
343 } else {
344 client_id = tfm_spm_partition_get_running_partition_id();
345 }
346
Summer Qin373feb12020-03-27 15:35:33 +0800347 conn_handle = tfm_spm_to_handle_instance(handle);
David Hu733d8f92019-09-23 15:32:40 +0800348 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800349 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
350 * the null handle.
David Hu733d8f92019-09-23 15:32:40 +0800351 */
Ken Liubcae38b2021-01-20 15:47:44 +0800352 if (tfm_spm_validate_conn_handle(conn_handle, client_id) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800353 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Summer Qin1ce712a2019-10-14 18:04:05 +0800354 }
Shawn Shanb222d892021-01-04 17:41:48 +0800355
Summer Qin630c76b2020-05-20 10:32:58 +0800356 service = conn_handle->service;
David Hu733d8f92019-09-23 15:32:40 +0800357 if (!service) {
358 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800359 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800360 }
361
Kevin Pengdf6aa292021-03-11 17:58:50 +0800362 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
363 if (!msg) {
364 /* FixMe: Need to implement one mechanism to resolve this failure. */
365 tfm_core_panic();
366 }
David Hu733d8f92019-09-23 15:32:40 +0800367
Shawn Shanb222d892021-01-04 17:41:48 +0800368 /*
369 * It is a PROGRAMMER ERROR if the connection is currently handling a
370 * request.
371 */
Summer Qin630c76b2020-05-20 10:32:58 +0800372 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
Shawn Shanb222d892021-01-04 17:41:48 +0800373 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Shawn Shancc39fcb2019-11-13 15:38:16 +0800374 }
375
David Hu733d8f92019-09-23 15:32:40 +0800376 /* No input or output needed for close message */
Ken Liu505b1702020-05-29 13:19:58 +0800377 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
David Hu733d8f92019-09-23 15:32:40 +0800378 NULL, 0, NULL, 0, NULL);
379
380 /*
381 * Send message and wake up the SP who is waiting on message queue,
382 * and scheduler triggered
383 */
384 tfm_spm_send_event(service, msg);
385}
Mingyang Sunb26b2802021-07-07 11:25:00 +0800386
387psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
388 uint32_t timeout)
389{
390 struct partition_t *partition = NULL;
391
392 /*
393 * Timeout[30:0] are reserved for future use.
394 * SPM must ignore the value of RES.
395 */
396 timeout &= PSA_TIMEOUT_MASK;
397
398 partition = tfm_spm_get_running_partition();
399 if (!partition) {
400 tfm_core_panic();
401 }
402
403 /*
404 * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
405 * signals.
406 */
407 if ((partition->signals_allowed & signal_mask) == 0) {
408 tfm_core_panic();
409 }
410
411 /*
412 * tfm_event_wait() blocks the caller thread if no signals are available.
413 * In this case, the return value of this function is temporary set into
414 * runtime context. After new signal(s) are available, the return value
415 * is updated with the available signal(s) and blocked thread gets to run.
416 */
417 if (timeout == PSA_BLOCK &&
418 (partition->signals_asserted & signal_mask) == 0) {
419 partition->signals_waiting = signal_mask;
420 tfm_event_wait(&partition->event);
421 } else if ((partition->signals_asserted & signal_mask) == 0) {
422 /* Activate scheduler to check if any higher priority thread to run */
423 tfm_core_thrd_activate_schedule();
424 }
425
426 return partition->signals_asserted & signal_mask;
427}
428
429psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
430{
431 struct tfm_msg_body_t *tmp_msg = NULL;
432 struct partition_t *partition = NULL;
433 uint32_t privileged;
434
435 /*
436 * Only one message could be retrieved every time for psa_get(). It is a
437 * fatal error if the input signal has more than a signal bit set.
438 */
439 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
440 tfm_core_panic();
441 }
442
443 partition = tfm_spm_get_running_partition();
444 if (!partition) {
445 tfm_core_panic();
446 }
447 privileged = tfm_spm_partition_get_privileged_mode(
448 partition->p_ldinf->flags);
449
450 /*
451 * Write the message to the service buffer. It is a fatal error if the
452 * input msg pointer is not a valid memory reference or not read-write.
453 */
454 if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
455 privileged) != SPM_SUCCESS) {
456 tfm_core_panic();
457 }
458
459 /*
460 * It is a fatal error if the caller call psa_get() when no message has
461 * been set. The caller must call this function after an RoT Service signal
462 * is returned by psa_wait().
463 */
464 if (partition->signals_asserted == 0) {
465 tfm_core_panic();
466 }
467
468 /*
469 * It is a fatal error if the RoT Service signal is not currently asserted.
470 */
471 if ((partition->signals_asserted & signal) == 0) {
472 tfm_core_panic();
473 }
474
475 /*
476 * Get message by signal from partition. It is a fatal error if getting
477 * failed, which means the input signal is not correspond to an RoT service.
478 */
479 tmp_msg = tfm_spm_get_msg_by_signal(partition, signal);
480 if (!tmp_msg) {
481 return PSA_ERROR_DOES_NOT_EXIST;
482 }
483
484 (TO_CONTAINER(tmp_msg,
485 struct tfm_conn_handle_t,
486 internal_msg))->status = TFM_HANDLE_STATUS_ACTIVE;
487
488 spm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
489
490 return PSA_SUCCESS;
491}
492
493void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
494{
495 struct tfm_msg_body_t *msg = NULL;
496 struct tfm_conn_handle_t *conn_handle;
497
498 /* It is a fatal error if message handle is invalid */
499 msg = tfm_spm_get_msg_from_handle(msg_handle);
500 if (!msg) {
501 tfm_core_panic();
502 }
503
504 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
505 if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
506 tfm_core_panic();
507 }
508
509 msg->msg.rhandle = rhandle;
510 conn_handle = tfm_spm_to_handle_instance(msg_handle);
511
512 /* Store reverse handle for following client calls. */
513 tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
514}
515
516size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
517 void *buffer, size_t num_bytes)
518{
519 size_t bytes;
520 struct tfm_msg_body_t *msg = NULL;
521 uint32_t privileged;
522 struct partition_t *partition = NULL;
523
524 /* It is a fatal error if message handle is invalid */
525 msg = tfm_spm_get_msg_from_handle(msg_handle);
526 if (!msg) {
527 tfm_core_panic();
528 }
529
530 partition = msg->service->partition;
531 privileged = tfm_spm_partition_get_privileged_mode(
532 partition->p_ldinf->flags);
533
534 /*
535 * It is a fatal error if message handle does not refer to a request
536 * message
537 */
538 if (msg->msg.type < PSA_IPC_CALL) {
539 tfm_core_panic();
540 }
541
542 /*
543 * It is a fatal error if invec_idx is equal to or greater than
544 * PSA_MAX_IOVEC
545 */
546 if (invec_idx >= PSA_MAX_IOVEC) {
547 tfm_core_panic();
548 }
549
550 /* There was no remaining data in this input vector */
551 if (msg->msg.in_size[invec_idx] == 0) {
552 return 0;
553 }
554
555 /*
556 * Copy the client data to the service buffer. It is a fatal error
557 * if the memory reference for buffer is invalid or not read-write.
558 */
559 if (tfm_memory_check(buffer, num_bytes, false,
560 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
561 tfm_core_panic();
562 }
563
564 bytes = num_bytes > msg->msg.in_size[invec_idx] ?
565 msg->msg.in_size[invec_idx] : num_bytes;
566
567 spm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
568
569 /* There maybe some remaining data */
570 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
571 msg->msg.in_size[invec_idx] -= bytes;
572
573 return bytes;
574}
575
576size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
577 size_t num_bytes)
578{
579 struct tfm_msg_body_t *msg = NULL;
580
581 /* It is a fatal error if message handle is invalid */
582 msg = tfm_spm_get_msg_from_handle(msg_handle);
583 if (!msg) {
584 tfm_core_panic();
585 }
586
587 /*
588 * It is a fatal error if message handle does not refer to a request
589 * message
590 */
591 if (msg->msg.type < PSA_IPC_CALL) {
592 tfm_core_panic();
593 }
594
595 /*
596 * It is a fatal error if invec_idx is equal to or greater than
597 * PSA_MAX_IOVEC
598 */
599 if (invec_idx >= PSA_MAX_IOVEC) {
600 tfm_core_panic();
601 }
602
603 /* There was no remaining data in this input vector */
604 if (msg->msg.in_size[invec_idx] == 0) {
605 return 0;
606 }
607
608 /*
609 * If num_bytes is greater than the remaining size of the input vector then
610 * the remaining size of the input vector is used.
611 */
612 if (num_bytes > msg->msg.in_size[invec_idx]) {
613 num_bytes = msg->msg.in_size[invec_idx];
614 }
615
616 /* There maybe some remaining data */
617 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
618 num_bytes;
619 msg->msg.in_size[invec_idx] -= num_bytes;
620
621 return num_bytes;
622}
623
624void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
625 const void *buffer, size_t num_bytes)
626{
627 struct tfm_msg_body_t *msg = NULL;
628 uint32_t privileged;
629 struct partition_t *partition = NULL;
630
631 /* It is a fatal error if message handle is invalid */
632 msg = tfm_spm_get_msg_from_handle(msg_handle);
633 if (!msg) {
634 tfm_core_panic();
635 }
636
637 partition = msg->service->partition;
638 privileged = tfm_spm_partition_get_privileged_mode(
639 partition->p_ldinf->flags);
640
641 /*
642 * It is a fatal error if message handle does not refer to a request
643 * message
644 */
645 if (msg->msg.type < PSA_IPC_CALL) {
646 tfm_core_panic();
647 }
648
649 /*
650 * It is a fatal error if outvec_idx is equal to or greater than
651 * PSA_MAX_IOVEC
652 */
653 if (outvec_idx >= PSA_MAX_IOVEC) {
654 tfm_core_panic();
655 }
656
657 /*
658 * It is a fatal error if the call attempts to write data past the end of
659 * the client output vector
660 */
661 if (num_bytes > msg->msg.out_size[outvec_idx] -
662 msg->outvec[outvec_idx].len) {
663 tfm_core_panic();
664 }
665
666 /*
667 * Copy the service buffer to client outvecs. It is a fatal error
668 * if the memory reference for buffer is invalid or not readable.
669 */
670 if (tfm_memory_check(buffer, num_bytes, false,
671 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
672 tfm_core_panic();
673 }
674
675 spm_memcpy((char *)msg->outvec[outvec_idx].base +
676 msg->outvec[outvec_idx].len, buffer, num_bytes);
677
678 /* Update the write number */
679 msg->outvec[outvec_idx].len += num_bytes;
680}
681
682void tfm_spm_partition_psa_reply(psa_handle_t msg_handle, psa_status_t status)
683{
684 struct service_t *service = NULL;
685 struct tfm_msg_body_t *msg = NULL;
686 int32_t ret = PSA_SUCCESS;
687 struct tfm_conn_handle_t *conn_handle;
688
689 /* It is a fatal error if message handle is invalid */
690 msg = tfm_spm_get_msg_from_handle(msg_handle);
691 if (!msg) {
692 tfm_core_panic();
693 }
694
695 /*
696 * RoT Service information is needed in this function, stored it in message
697 * body structure. Only two parameters are passed in this function: handle
698 * and status, so it is useful and simply to do like this.
699 */
700 service = msg->service;
701 if (!service) {
702 tfm_core_panic();
703 }
704
705 /*
706 * Three type of message are passed in this function: CONNECTION, REQUEST,
707 * DISCONNECTION. It needs to process differently for each type.
708 */
709 conn_handle = tfm_spm_to_handle_instance(msg_handle);
710 switch (msg->msg.type) {
711 case PSA_IPC_CONNECT:
712 /*
713 * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
714 * input status is PSA_SUCCESS. Others return values are based on the
715 * input status.
716 */
717 if (status == PSA_SUCCESS) {
718 ret = msg_handle;
719 } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
720 /* Refuse the client connection, indicating a permanent error. */
721 tfm_spm_free_conn_handle(service, conn_handle);
722 ret = PSA_ERROR_CONNECTION_REFUSED;
723 } else if (status == PSA_ERROR_CONNECTION_BUSY) {
724 /* Fail the client connection, indicating a transient error. */
725 ret = PSA_ERROR_CONNECTION_BUSY;
726 } else {
727 tfm_core_panic();
728 }
729 break;
730 case PSA_IPC_DISCONNECT:
731 /* Service handle is not used anymore */
732 tfm_spm_free_conn_handle(service, conn_handle);
733
734 /*
735 * If the message type is PSA_IPC_DISCONNECT, then the status code is
736 * ignored
737 */
738 break;
739 default:
740 if (msg->msg.type >= PSA_IPC_CALL) {
741 /* Reply to a request message. Return values are based on status */
742 ret = status;
743 /*
744 * The total number of bytes written to a single parameter must be
745 * reported to the client by updating the len member of the
746 * psa_outvec structure for the parameter before returning from
747 * psa_call().
748 */
749 update_caller_outvec_len(msg);
750 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
751 tfm_spm_free_conn_handle(service, conn_handle);
752 }
753 } else {
754 tfm_core_panic();
755 }
756 }
757
758 if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
759 /*
760 * If the source of the programmer error is a Secure Partition, the SPM
761 * must panic the Secure Partition in response to a PROGRAMMER ERROR.
762 */
763 if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
764 conn_handle->status = TFM_HANDLE_STATUS_CONNECT_ERROR;
765 } else {
766 tfm_core_panic();
767 }
768 } else {
769 conn_handle->status = TFM_HANDLE_STATUS_IDLE;
770 }
771
772 if (is_tfm_rpc_msg(msg)) {
773 tfm_rpc_client_call_reply(msg, ret);
774 } else {
775 tfm_event_wake(&msg->ack_evnt, ret);
776 }
777}
778
779void tfm_spm_partition_psa_notify(int32_t partition_id)
780{
781 notify_with_signal(partition_id, PSA_DOORBELL);
782}
783
784void tfm_spm_partition_psa_clear(void)
785{
786 struct partition_t *partition = NULL;
787
788 partition = tfm_spm_get_running_partition();
789 if (!partition) {
790 tfm_core_panic();
791 }
792
793 /*
794 * It is a fatal error if the Secure Partition's doorbell signal is not
795 * currently asserted.
796 */
797 if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
798 tfm_core_panic();
799 }
800 partition->signals_asserted &= ~PSA_DOORBELL;
801}
802
803void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
804{
805 struct irq_load_info_t *irq_info = NULL;
806 struct partition_t *partition = NULL;
807
808 partition = tfm_spm_get_running_partition();
809 if (!partition) {
810 tfm_core_panic();
811 }
812
813 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
814 /* It is a fatal error if passed signal is not an interrupt signal. */
815 if (!irq_info) {
816 tfm_core_panic();
817 }
818
819 if (irq_info->flih_func) {
820 /* This API is for SLIH IRQs only */
821 psa_panic();
822 }
823
824 /* It is a fatal error if passed signal is not currently asserted */
825 if ((partition->signals_asserted & irq_signal) == 0) {
826 tfm_core_panic();
827 }
828
829 partition->signals_asserted &= ~irq_signal;
830
831 tfm_spm_hal_clear_pending_irq((IRQn_Type)(irq_info->source));
832 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
833}
834
835void tfm_spm_partition_psa_panic(void)
836{
837 /*
838 * PSA FF recommends that the SPM causes the system to restart when a secure
839 * partition panics.
840 */
841 tfm_hal_system_reset();
842}
843
844void tfm_spm_partition_irq_enable(psa_signal_t irq_signal)
845{
846 struct partition_t *partition;
847 struct irq_load_info_t *irq_info;
848
849 partition = tfm_spm_get_running_partition();
850 if (!partition) {
851 tfm_core_panic();
852 }
853
854 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
855 if (!irq_info) {
856 tfm_core_panic();
857 }
858
859 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
860}
861
862psa_irq_status_t tfm_spm_partition_irq_disable(psa_signal_t irq_signal)
863{
864 struct partition_t *partition;
865 struct irq_load_info_t *irq_info;
866
867 partition = tfm_spm_get_running_partition();
868 if (!partition) {
869 tfm_core_panic();
870 }
871
872 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
873 if (!irq_info) {
874 tfm_core_panic();
875 }
876
877 tfm_spm_hal_disable_irq((IRQn_Type)(irq_info->source));
878
879 return 1;
880}
881
882void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
883{
884 struct irq_load_info_t *irq_info;
885 struct partition_t *partition;
886
887 partition = tfm_spm_get_running_partition();
888 if (!partition) {
889 tfm_core_panic();
890 }
891
892 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
893 if (!irq_info) {
894 tfm_core_panic();
895 }
896
897 if (!irq_info->flih_func) {
898 /* This API is for FLIH IRQs only */
899 tfm_core_panic();
900 }
901
902 if ((partition->signals_asserted & irq_signal) == 0) {
903 /* The signal is not asserted */
904 tfm_core_panic();
905 }
906
907 partition->signals_asserted &= ~irq_signal;
908}