blob: f41dc4c46ae5cac88063440c5525738a81f99d46 [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 Suneeca4652021-07-15 15:19:16 +08008#include <stdint.h>
Mingyang Sunb26b2802021-07-07 11:25:00 +08009#include "bitops.h"
Mingyang Suneeca4652021-07-15 15:19:16 +080010#include "psa/lifecycle.h"
David Hu733d8f92019-09-23 15:32:40 +080011#include "psa/service.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080012#include "spm_ipc.h"
Mingyang Sun22a3faf2021-07-09 15:32:47 +080013#include "tfm_arch.h"
David Hu733d8f92019-09-23 15:32:40 +080014#include "tfm_core_utils.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080015#include "load/partition_defs.h"
Mingyang Sun2b352662021-04-21 11:35:43 +080016#include "load/service_defs.h"
Ken Liu3dd92562021-08-17 16:22:54 +080017#include "load/interrupt_defs.h"
Mingyang Sun133a7922021-07-08 16:01:26 +080018#include "psa_api.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080019#include "utilities.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"
Mingyang Suneeca4652021-07-15 15:19:16 +080024#include "tfm_psa_call_param.h"
David Hu733d8f92019-09-23 15:32:40 +080025
Ken Liub3b2cb62021-05-22 00:39:28 +080026#define GET_STATELESS_SERVICE(index) (stateless_services_ref_tbl[index])
Xinyu Zhanga38e9b52021-06-02 17:48:01 +080027extern struct service_t *stateless_services_ref_tbl[];
Mingyang Suncb6f70e2021-03-05 23:30:25 +080028
Mingyang Suneeca4652021-07-15 15:19:16 +080029
30uint32_t tfm_spm_get_lifecycle_state(void)
31{
32 /*
33 * FixMe: return PSA_LIFECYCLE_UNKNOWN to the caller directly. It will be
34 * implemented in the future.
35 */
36 return PSA_LIFECYCLE_UNKNOWN;
37}
38
39/* PSA Client API function body */
40
Mingyang Sund44522a2020-01-16 16:48:37 +080041uint32_t tfm_spm_client_psa_framework_version(void)
David Hu733d8f92019-09-23 15:32:40 +080042{
43 return PSA_FRAMEWORK_VERSION;
44}
45
Mingyang Sun22a3faf2021-07-09 15:32:47 +080046uint32_t tfm_spm_client_psa_version(uint32_t sid)
David Hu733d8f92019-09-23 15:32:40 +080047{
Mingyang Sun783a59b2021-04-20 15:52:18 +080048 struct service_t *service;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080049 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080050
51 /*
52 * It should return PSA_VERSION_NONE if the RoT Service is not
53 * implemented.
54 */
55 service = tfm_spm_get_service_by_sid(sid);
56 if (!service) {
57 return PSA_VERSION_NONE;
58 }
59
60 /*
Shawn Shan2365c902019-12-19 18:35:36 +080061 * It should return PSA_VERSION_NONE if the caller is not authorized
62 * to access the RoT Service.
David Hu733d8f92019-09-23 15:32:40 +080063 */
Ken Liubcae38b2021-01-20 15:47:44 +080064 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
Shawn Shan2365c902019-12-19 18:35:36 +080065 return PSA_VERSION_NONE;
David Hu733d8f92019-09-23 15:32:40 +080066 }
67
Ken Liuacd2a572021-05-12 16:19:04 +080068 return service->p_ldinf->version;
David Hu733d8f92019-09-23 15:32:40 +080069}
70
Mingyang Sun22a3faf2021-07-09 15:32:47 +080071psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
David Hu733d8f92019-09-23 15:32:40 +080072{
Mingyang Sun783a59b2021-04-20 15:52:18 +080073 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +080074 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +080075 struct tfm_conn_handle_t *connect_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +080076 int32_t client_id;
Ken Liu505b1702020-05-29 13:19:58 +080077 psa_handle_t handle;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080078 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080079
Kevin Pengedb8ee42021-03-09 16:50:11 +080080 /*
81 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
82 * platform.
83 */
David Hu733d8f92019-09-23 15:32:40 +080084 service = tfm_spm_get_service_by_sid(sid);
85 if (!service) {
Shawn Shanb222d892021-01-04 17:41:48 +080086 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
David Hu733d8f92019-09-23 15:32:40 +080087 }
88
Mingyang Sunef42f442021-06-11 15:07:58 +080089 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
90 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
91 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
92 }
93
Kevin Pengedb8ee42021-03-09 16:50:11 +080094 /*
95 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
96 * RoT Service.
97 */
98 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
99 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
100 }
101
102 /*
103 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
104 * not supported on the platform.
105 */
106 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
107 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
108 }
109
Kevin Peng385fda82021-08-18 10:41:19 +0800110 client_id = tfm_spm_get_client_id(ns_caller);
Summer Qin1ce712a2019-10-14 18:04:05 +0800111
David Hu733d8f92019-09-23 15:32:40 +0800112 /*
113 * Create connection handle here since it is possible to return the error
114 * code to client when creation fails.
115 */
Summer Qin1ce712a2019-10-14 18:04:05 +0800116 connect_handle = tfm_spm_create_conn_handle(service, client_id);
Summer Qin630c76b2020-05-20 10:32:58 +0800117 if (!connect_handle) {
David Hu733d8f92019-09-23 15:32:40 +0800118 return PSA_ERROR_CONNECTION_BUSY;
119 }
120
Kevin Pengdf6aa292021-03-11 17:58:50 +0800121 msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
122 if (!msg) {
123 /* Have no enough resource to create message */
124 return PSA_ERROR_CONNECTION_BUSY;
125 }
David Hu733d8f92019-09-23 15:32:40 +0800126
Ken Liu505b1702020-05-29 13:19:58 +0800127 handle = tfm_spm_to_user_handle(connect_handle);
David Hu733d8f92019-09-23 15:32:40 +0800128 /* No input or output needed for connect message */
Ken Liu505b1702020-05-29 13:19:58 +0800129 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
Summer Qin1ce712a2019-10-14 18:04:05 +0800130 client_id, NULL, 0, NULL, 0, NULL);
David Hu733d8f92019-09-23 15:32:40 +0800131
132 /*
133 * Send message and wake up the SP who is waiting on message queue,
134 * and scheduler triggered
135 */
136 tfm_spm_send_event(service, msg);
137
138 return PSA_SUCCESS;
139}
140
Mingyang Suneeca4652021-07-15 15:19:16 +0800141psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
142 uint32_t ctrl_param,
143 const psa_invec *inptr,
144 psa_outvec *outptr)
David Hu733d8f92019-09-23 15:32:40 +0800145{
146 psa_invec invecs[PSA_MAX_IOVEC];
147 psa_outvec outvecs[PSA_MAX_IOVEC];
Summer Qin630c76b2020-05-20 10:32:58 +0800148 struct tfm_conn_handle_t *conn_handle;
Mingyang Sun783a59b2021-04-20 15:52:18 +0800149 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800150 struct tfm_msg_body_t *msg;
Summer Qinba2346e2019-11-12 16:26:31 +0800151 int i, j;
Summer Qin1ce712a2019-10-14 18:04:05 +0800152 int32_t client_id;
Mingyang Sun453ad402021-03-17 17:58:33 +0800153 uint32_t sid, version, index;
Mingyang Sune529e3b2021-07-12 14:46:30 +0800154 uint32_t privileged;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800155 bool ns_caller = tfm_spm_is_ns_caller();
Mingyang Suneeca4652021-07-15 15:19:16 +0800156 int32_t type = (int32_t)(int16_t)((ctrl_param & TYPE_MASK) >> TYPE_OFFSET);
157 size_t in_num = (size_t)((ctrl_param & IN_LEN_MASK) >> IN_LEN_OFFSET);
158 size_t out_num = (size_t)((ctrl_param & OUT_LEN_MASK) >> OUT_LEN_OFFSET);
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800159
160 /* The request type must be zero or positive. */
161 if (type < 0) {
162 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
163 }
David Hu733d8f92019-09-23 15:32:40 +0800164
Shawn Shanb222d892021-01-04 17:41:48 +0800165 /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
David Hu733d8f92019-09-23 15:32:40 +0800166 if ((in_num > PSA_MAX_IOVEC) ||
167 (out_num > PSA_MAX_IOVEC) ||
168 (in_num + out_num > PSA_MAX_IOVEC)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800169 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800170 }
171
Kevin Peng385fda82021-08-18 10:41:19 +0800172 client_id = tfm_spm_get_client_id(ns_caller);
Summer Qin1ce712a2019-10-14 18:04:05 +0800173
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800174 /* Allocate space from handle pool for static handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800175 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun453ad402021-03-17 17:58:33 +0800176 index = GET_INDEX_FROM_STATIC_HANDLE(handle);
Mingyang Sune8d38082021-03-30 18:34:40 +0800177
178 if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
179 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
180 }
181
Mingyang Sun453ad402021-03-17 17:58:33 +0800182 service = GET_STATELESS_SERVICE(index);
Mingyang Sun86213242021-07-14 10:26:43 +0800183 if (!service) {
184 tfm_core_panic();
185 }
186
Ken Liub3b2cb62021-05-22 00:39:28 +0800187 sid = service->p_ldinf->sid;
Mingyang Sun453ad402021-03-17 17:58:33 +0800188
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800189 /*
190 * It is a PROGRAMMER ERROR if the caller is not authorized to access
191 * the RoT Service.
192 */
193 if (tfm_spm_check_authorization(sid, service, ns_caller)
194 != SPM_SUCCESS) {
195 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
196 }
197
Mingyang Sun453ad402021-03-17 17:58:33 +0800198 version = GET_VERSION_FROM_STATIC_HANDLE(handle);
199
200 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
201 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
202 }
203
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800204 conn_handle = tfm_spm_create_conn_handle(service, client_id);
205
206 if (!conn_handle) {
207 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_BUSY);
208 }
209
Mingyang Sun6d5dc3d2021-03-15 15:34:44 +0800210 conn_handle->rhandle = NULL;
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800211 handle = tfm_spm_to_user_handle(conn_handle);
212 } else {
213 conn_handle = tfm_spm_to_handle_instance(handle);
214
215 /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
216 if (tfm_spm_validate_conn_handle(conn_handle, client_id)
217 != SPM_SUCCESS) {
218 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
219 }
220
221 /*
222 * It is a PROGRAMMER ERROR if the connection is currently
223 * handling a request.
224 */
225 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
226 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
227 }
228
229 /*
230 * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
231 * has been terminated by the RoT Service.
232 */
233 if (conn_handle->status == TFM_HANDLE_STATUS_CONNECT_ERROR) {
234 return PSA_ERROR_PROGRAMMER_ERROR;
235 }
236
237 service = conn_handle->service;
Summer Qin1ce712a2019-10-14 18:04:05 +0800238 }
Shawn Shanb222d892021-01-04 17:41:48 +0800239
David Hu733d8f92019-09-23 15:32:40 +0800240 if (!service) {
241 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800242 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800243 }
244
Mingyang Sune529e3b2021-07-12 14:46:30 +0800245 privileged = tfm_spm_get_caller_privilege_mode();
246
Kevin Pengedb8ee42021-03-09 16:50:11 +0800247 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800248 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
David Hu733d8f92019-09-23 15:32:40 +0800249 * if the memory reference for the wrap input vector is invalid or not
250 * readable.
251 */
252 if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800253 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800254 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800255 }
Summer Qinba2346e2019-11-12 16:26:31 +0800256
David Hu733d8f92019-09-23 15:32:40 +0800257 /*
258 * Read client outvecs from the wrap output vector and will update the
Shawn Shanb222d892021-01-04 17:41:48 +0800259 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
David Hu733d8f92019-09-23 15:32:40 +0800260 * the wrap output vector is invalid or not read-write.
261 */
262 if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800263 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800264 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800265 }
266
Summer Qinf24dbb52020-07-23 14:53:54 +0800267 spm_memset(invecs, 0, sizeof(invecs));
268 spm_memset(outvecs, 0, sizeof(outvecs));
David Hu733d8f92019-09-23 15:32:40 +0800269
270 /* Copy the address out to avoid TOCTOU attacks. */
Summer Qinf24dbb52020-07-23 14:53:54 +0800271 spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
272 spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
David Hu733d8f92019-09-23 15:32:40 +0800273
274 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800275 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
David Hu733d8f92019-09-23 15:32:40 +0800276 * memory reference was invalid or not readable.
277 */
278 for (i = 0; i < in_num; i++) {
279 if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800280 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800281 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800282 }
283 }
Summer Qinba2346e2019-11-12 16:26:31 +0800284
285 /*
286 * Clients must never overlap input parameters because of the risk of a
287 * double-fetch inconsistency.
288 * Overflow is checked in tfm_memory_check functions.
289 */
290 for (i = 0; i + 1 < in_num; i++) {
291 for (j = i+1; j < in_num; j++) {
TTornblom83d96372019-11-19 12:53:16 +0100292 if (!((char *) invecs[j].base + invecs[j].len <=
293 (char *) invecs[i].base ||
294 (char *) invecs[j].base >=
295 (char *) invecs[i].base + invecs[i].len)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800296 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
Summer Qinba2346e2019-11-12 16:26:31 +0800297 }
298 }
299 }
300
David Hu733d8f92019-09-23 15:32:40 +0800301 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800302 * For client output vector, it is a PROGRAMMER ERROR if the provided
303 * payload memory reference was invalid or not read-write.
David Hu733d8f92019-09-23 15:32:40 +0800304 */
305 for (i = 0; i < out_num; i++) {
306 if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
Ken Liubcae38b2021-01-20 15:47:44 +0800307 ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800308 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800309 }
310 }
311
312 /*
313 * FixMe: Need to check if the message is unrecognized by the RoT
314 * Service or incorrectly formatted.
315 */
Kevin Pengdf6aa292021-03-11 17:58:50 +0800316 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
317 if (!msg) {
318 /* FixMe: Need to implement one mechanism to resolve this failure. */
319 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
320 }
David Hu733d8f92019-09-23 15:32:40 +0800321
Ken Liu505b1702020-05-29 13:19:58 +0800322 tfm_spm_fill_msg(msg, service, handle, type, client_id,
Summer Qin630c76b2020-05-20 10:32:58 +0800323 invecs, in_num, outvecs, out_num, outptr);
David Hu733d8f92019-09-23 15:32:40 +0800324
325 /*
326 * Send message and wake up the SP who is waiting on message queue,
327 * and scheduler triggered
328 */
Kevin Peng8dac6102021-03-09 16:44:00 +0800329 tfm_spm_send_event(service, msg);
330
David Hu733d8f92019-09-23 15:32:40 +0800331 return PSA_SUCCESS;
332}
333
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800334void tfm_spm_client_psa_close(psa_handle_t handle)
David Hu733d8f92019-09-23 15:32:40 +0800335{
Mingyang Sun783a59b2021-04-20 15:52:18 +0800336 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800337 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +0800338 struct tfm_conn_handle_t *conn_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +0800339 int32_t client_id;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800340 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +0800341
342 /* It will have no effect if called with the NULL handle */
343 if (handle == PSA_NULL_HANDLE) {
344 return;
345 }
346
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800347 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800348 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800349 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
350 }
351
Kevin Peng385fda82021-08-18 10:41:19 +0800352 client_id = tfm_spm_get_client_id(ns_caller);
Summer Qin1ce712a2019-10-14 18:04:05 +0800353
Summer Qin373feb12020-03-27 15:35:33 +0800354 conn_handle = tfm_spm_to_handle_instance(handle);
David Hu733d8f92019-09-23 15:32:40 +0800355 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800356 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
357 * the null handle.
David Hu733d8f92019-09-23 15:32:40 +0800358 */
Ken Liubcae38b2021-01-20 15:47:44 +0800359 if (tfm_spm_validate_conn_handle(conn_handle, client_id) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800360 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Summer Qin1ce712a2019-10-14 18:04:05 +0800361 }
Shawn Shanb222d892021-01-04 17:41:48 +0800362
Summer Qin630c76b2020-05-20 10:32:58 +0800363 service = conn_handle->service;
David Hu733d8f92019-09-23 15:32:40 +0800364 if (!service) {
365 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800366 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800367 }
368
Kevin Pengdf6aa292021-03-11 17:58:50 +0800369 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
370 if (!msg) {
371 /* FixMe: Need to implement one mechanism to resolve this failure. */
372 tfm_core_panic();
373 }
David Hu733d8f92019-09-23 15:32:40 +0800374
Shawn Shanb222d892021-01-04 17:41:48 +0800375 /*
376 * It is a PROGRAMMER ERROR if the connection is currently handling a
377 * request.
378 */
Summer Qin630c76b2020-05-20 10:32:58 +0800379 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
Shawn Shanb222d892021-01-04 17:41:48 +0800380 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Shawn Shancc39fcb2019-11-13 15:38:16 +0800381 }
382
David Hu733d8f92019-09-23 15:32:40 +0800383 /* No input or output needed for close message */
Ken Liu505b1702020-05-29 13:19:58 +0800384 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
David Hu733d8f92019-09-23 15:32:40 +0800385 NULL, 0, NULL, 0, NULL);
386
387 /*
388 * Send message and wake up the SP who is waiting on message queue,
389 * and scheduler triggered
390 */
391 tfm_spm_send_event(service, msg);
392}
Mingyang Sunb26b2802021-07-07 11:25:00 +0800393
Mingyang Suneeca4652021-07-15 15:19:16 +0800394/* PSA Partition API function body */
395
Mingyang Sunb26b2802021-07-07 11:25:00 +0800396psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
397 uint32_t timeout)
398{
399 struct partition_t *partition = NULL;
400
401 /*
402 * Timeout[30:0] are reserved for future use.
403 * SPM must ignore the value of RES.
404 */
405 timeout &= PSA_TIMEOUT_MASK;
406
407 partition = tfm_spm_get_running_partition();
408 if (!partition) {
409 tfm_core_panic();
410 }
411
412 /*
413 * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
414 * signals.
415 */
416 if ((partition->signals_allowed & signal_mask) == 0) {
417 tfm_core_panic();
418 }
419
420 /*
Ken Liu5d73c872021-08-19 19:23:17 +0800421 * thrd_wait_on() blocks the caller thread if no signals are available.
Mingyang Sunb26b2802021-07-07 11:25:00 +0800422 * In this case, the return value of this function is temporary set into
423 * runtime context. After new signal(s) are available, the return value
424 * is updated with the available signal(s) and blocked thread gets to run.
425 */
426 if (timeout == PSA_BLOCK &&
427 (partition->signals_asserted & signal_mask) == 0) {
428 partition->signals_waiting = signal_mask;
Ken Liu5d73c872021-08-19 19:23:17 +0800429 thrd_wait_on(&partition->waitobj,
430 &(tfm_spm_get_running_partition()->thrd));
Mingyang Sunb26b2802021-07-07 11:25:00 +0800431 } else if ((partition->signals_asserted & signal_mask) == 0) {
432 /* Activate scheduler to check if any higher priority thread to run */
Ken Liu5d73c872021-08-19 19:23:17 +0800433 tfm_arch_trigger_pendsv();
Mingyang Sunb26b2802021-07-07 11:25:00 +0800434 }
435
436 return partition->signals_asserted & signal_mask;
437}
438
439psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
440{
441 struct tfm_msg_body_t *tmp_msg = NULL;
442 struct partition_t *partition = NULL;
443 uint32_t privileged;
444
445 /*
446 * Only one message could be retrieved every time for psa_get(). It is a
447 * fatal error if the input signal has more than a signal bit set.
448 */
449 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
450 tfm_core_panic();
451 }
452
453 partition = tfm_spm_get_running_partition();
454 if (!partition) {
455 tfm_core_panic();
456 }
457 privileged = tfm_spm_partition_get_privileged_mode(
458 partition->p_ldinf->flags);
459
460 /*
461 * Write the message to the service buffer. It is a fatal error if the
462 * input msg pointer is not a valid memory reference or not read-write.
463 */
464 if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
465 privileged) != SPM_SUCCESS) {
466 tfm_core_panic();
467 }
468
469 /*
470 * It is a fatal error if the caller call psa_get() when no message has
471 * been set. The caller must call this function after an RoT Service signal
472 * is returned by psa_wait().
473 */
474 if (partition->signals_asserted == 0) {
475 tfm_core_panic();
476 }
477
478 /*
479 * It is a fatal error if the RoT Service signal is not currently asserted.
480 */
481 if ((partition->signals_asserted & signal) == 0) {
482 tfm_core_panic();
483 }
484
485 /*
486 * Get message by signal from partition. It is a fatal error if getting
487 * failed, which means the input signal is not correspond to an RoT service.
488 */
489 tmp_msg = tfm_spm_get_msg_by_signal(partition, signal);
490 if (!tmp_msg) {
491 return PSA_ERROR_DOES_NOT_EXIST;
492 }
493
494 (TO_CONTAINER(tmp_msg,
495 struct tfm_conn_handle_t,
496 internal_msg))->status = TFM_HANDLE_STATUS_ACTIVE;
497
498 spm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
499
500 return PSA_SUCCESS;
501}
502
503void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
504{
505 struct tfm_msg_body_t *msg = NULL;
506 struct tfm_conn_handle_t *conn_handle;
507
508 /* It is a fatal error if message handle is invalid */
509 msg = tfm_spm_get_msg_from_handle(msg_handle);
510 if (!msg) {
511 tfm_core_panic();
512 }
513
514 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
515 if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
516 tfm_core_panic();
517 }
518
519 msg->msg.rhandle = rhandle;
520 conn_handle = tfm_spm_to_handle_instance(msg_handle);
521
522 /* Store reverse handle for following client calls. */
523 tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
524}
525
526size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
527 void *buffer, size_t num_bytes)
528{
529 size_t bytes;
530 struct tfm_msg_body_t *msg = NULL;
531 uint32_t privileged;
532 struct partition_t *partition = NULL;
533
534 /* It is a fatal error if message handle is invalid */
535 msg = tfm_spm_get_msg_from_handle(msg_handle);
536 if (!msg) {
537 tfm_core_panic();
538 }
539
540 partition = msg->service->partition;
541 privileged = tfm_spm_partition_get_privileged_mode(
542 partition->p_ldinf->flags);
543
544 /*
545 * It is a fatal error if message handle does not refer to a request
546 * message
547 */
548 if (msg->msg.type < PSA_IPC_CALL) {
549 tfm_core_panic();
550 }
551
552 /*
553 * It is a fatal error if invec_idx is equal to or greater than
554 * PSA_MAX_IOVEC
555 */
556 if (invec_idx >= PSA_MAX_IOVEC) {
557 tfm_core_panic();
558 }
559
560 /* There was no remaining data in this input vector */
561 if (msg->msg.in_size[invec_idx] == 0) {
562 return 0;
563 }
564
565 /*
566 * Copy the client data to the service buffer. It is a fatal error
567 * if the memory reference for buffer is invalid or not read-write.
568 */
569 if (tfm_memory_check(buffer, num_bytes, false,
570 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
571 tfm_core_panic();
572 }
573
574 bytes = num_bytes > msg->msg.in_size[invec_idx] ?
575 msg->msg.in_size[invec_idx] : num_bytes;
576
577 spm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
578
579 /* There maybe some remaining data */
580 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
581 msg->msg.in_size[invec_idx] -= bytes;
582
583 return bytes;
584}
585
586size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
587 size_t num_bytes)
588{
589 struct tfm_msg_body_t *msg = NULL;
590
591 /* It is a fatal error if message handle is invalid */
592 msg = tfm_spm_get_msg_from_handle(msg_handle);
593 if (!msg) {
594 tfm_core_panic();
595 }
596
597 /*
598 * It is a fatal error if message handle does not refer to a request
599 * message
600 */
601 if (msg->msg.type < PSA_IPC_CALL) {
602 tfm_core_panic();
603 }
604
605 /*
606 * It is a fatal error if invec_idx is equal to or greater than
607 * PSA_MAX_IOVEC
608 */
609 if (invec_idx >= PSA_MAX_IOVEC) {
610 tfm_core_panic();
611 }
612
613 /* There was no remaining data in this input vector */
614 if (msg->msg.in_size[invec_idx] == 0) {
615 return 0;
616 }
617
618 /*
619 * If num_bytes is greater than the remaining size of the input vector then
620 * the remaining size of the input vector is used.
621 */
622 if (num_bytes > msg->msg.in_size[invec_idx]) {
623 num_bytes = msg->msg.in_size[invec_idx];
624 }
625
626 /* There maybe some remaining data */
627 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
628 num_bytes;
629 msg->msg.in_size[invec_idx] -= num_bytes;
630
631 return num_bytes;
632}
633
634void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
635 const void *buffer, size_t num_bytes)
636{
637 struct tfm_msg_body_t *msg = NULL;
638 uint32_t privileged;
639 struct partition_t *partition = NULL;
640
641 /* It is a fatal error if message handle is invalid */
642 msg = tfm_spm_get_msg_from_handle(msg_handle);
643 if (!msg) {
644 tfm_core_panic();
645 }
646
647 partition = msg->service->partition;
648 privileged = tfm_spm_partition_get_privileged_mode(
649 partition->p_ldinf->flags);
650
651 /*
652 * It is a fatal error if message handle does not refer to a request
653 * message
654 */
655 if (msg->msg.type < PSA_IPC_CALL) {
656 tfm_core_panic();
657 }
658
659 /*
660 * It is a fatal error if outvec_idx is equal to or greater than
661 * PSA_MAX_IOVEC
662 */
663 if (outvec_idx >= PSA_MAX_IOVEC) {
664 tfm_core_panic();
665 }
666
667 /*
668 * It is a fatal error if the call attempts to write data past the end of
669 * the client output vector
670 */
671 if (num_bytes > msg->msg.out_size[outvec_idx] -
672 msg->outvec[outvec_idx].len) {
673 tfm_core_panic();
674 }
675
676 /*
677 * Copy the service buffer to client outvecs. It is a fatal error
678 * if the memory reference for buffer is invalid or not readable.
679 */
680 if (tfm_memory_check(buffer, num_bytes, false,
681 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
682 tfm_core_panic();
683 }
684
685 spm_memcpy((char *)msg->outvec[outvec_idx].base +
686 msg->outvec[outvec_idx].len, buffer, num_bytes);
687
688 /* Update the write number */
689 msg->outvec[outvec_idx].len += num_bytes;
690}
691
692void tfm_spm_partition_psa_reply(psa_handle_t msg_handle, psa_status_t status)
693{
694 struct service_t *service = NULL;
695 struct tfm_msg_body_t *msg = NULL;
696 int32_t ret = PSA_SUCCESS;
697 struct tfm_conn_handle_t *conn_handle;
698
699 /* It is a fatal error if message handle is invalid */
700 msg = tfm_spm_get_msg_from_handle(msg_handle);
701 if (!msg) {
702 tfm_core_panic();
703 }
704
705 /*
706 * RoT Service information is needed in this function, stored it in message
707 * body structure. Only two parameters are passed in this function: handle
708 * and status, so it is useful and simply to do like this.
709 */
710 service = msg->service;
711 if (!service) {
712 tfm_core_panic();
713 }
714
715 /*
716 * Three type of message are passed in this function: CONNECTION, REQUEST,
717 * DISCONNECTION. It needs to process differently for each type.
718 */
719 conn_handle = tfm_spm_to_handle_instance(msg_handle);
720 switch (msg->msg.type) {
721 case PSA_IPC_CONNECT:
722 /*
723 * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
724 * input status is PSA_SUCCESS. Others return values are based on the
725 * input status.
726 */
727 if (status == PSA_SUCCESS) {
728 ret = msg_handle;
729 } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
730 /* Refuse the client connection, indicating a permanent error. */
731 tfm_spm_free_conn_handle(service, conn_handle);
732 ret = PSA_ERROR_CONNECTION_REFUSED;
733 } else if (status == PSA_ERROR_CONNECTION_BUSY) {
734 /* Fail the client connection, indicating a transient error. */
735 ret = PSA_ERROR_CONNECTION_BUSY;
736 } else {
737 tfm_core_panic();
738 }
739 break;
740 case PSA_IPC_DISCONNECT:
741 /* Service handle is not used anymore */
742 tfm_spm_free_conn_handle(service, conn_handle);
743
744 /*
745 * If the message type is PSA_IPC_DISCONNECT, then the status code is
746 * ignored
747 */
748 break;
749 default:
750 if (msg->msg.type >= PSA_IPC_CALL) {
751 /* Reply to a request message. Return values are based on status */
752 ret = status;
753 /*
754 * The total number of bytes written to a single parameter must be
755 * reported to the client by updating the len member of the
756 * psa_outvec structure for the parameter before returning from
757 * psa_call().
758 */
759 update_caller_outvec_len(msg);
760 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
761 tfm_spm_free_conn_handle(service, conn_handle);
762 }
763 } else {
764 tfm_core_panic();
765 }
766 }
767
768 if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
769 /*
770 * If the source of the programmer error is a Secure Partition, the SPM
771 * must panic the Secure Partition in response to a PROGRAMMER ERROR.
772 */
773 if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
774 conn_handle->status = TFM_HANDLE_STATUS_CONNECT_ERROR;
775 } else {
776 tfm_core_panic();
777 }
778 } else {
779 conn_handle->status = TFM_HANDLE_STATUS_IDLE;
780 }
781
782 if (is_tfm_rpc_msg(msg)) {
783 tfm_rpc_client_call_reply(msg, ret);
784 } else {
Ken Liu5d73c872021-08-19 19:23:17 +0800785 thrd_wake_up(&msg->ack_evnt, ret);
Mingyang Sunb26b2802021-07-07 11:25:00 +0800786 }
787}
788
789void tfm_spm_partition_psa_notify(int32_t partition_id)
790{
Ken Liu5d73c872021-08-19 19:23:17 +0800791 struct partition_t *p_pt = tfm_spm_get_partition_by_id(partition_id);
792
793 spm_assert_signal(p_pt, PSA_DOORBELL);
Mingyang Sunb26b2802021-07-07 11:25:00 +0800794}
795
796void tfm_spm_partition_psa_clear(void)
797{
798 struct partition_t *partition = NULL;
799
800 partition = tfm_spm_get_running_partition();
801 if (!partition) {
802 tfm_core_panic();
803 }
804
805 /*
806 * It is a fatal error if the Secure Partition's doorbell signal is not
807 * currently asserted.
808 */
809 if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
810 tfm_core_panic();
811 }
812 partition->signals_asserted &= ~PSA_DOORBELL;
813}
814
815void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
816{
817 struct irq_load_info_t *irq_info = NULL;
818 struct partition_t *partition = NULL;
819
820 partition = tfm_spm_get_running_partition();
821 if (!partition) {
822 tfm_core_panic();
823 }
824
825 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
826 /* It is a fatal error if passed signal is not an interrupt signal. */
827 if (!irq_info) {
828 tfm_core_panic();
829 }
830
831 if (irq_info->flih_func) {
832 /* This API is for SLIH IRQs only */
833 psa_panic();
834 }
835
836 /* It is a fatal error if passed signal is not currently asserted */
837 if ((partition->signals_asserted & irq_signal) == 0) {
838 tfm_core_panic();
839 }
840
841 partition->signals_asserted &= ~irq_signal;
842
843 tfm_spm_hal_clear_pending_irq((IRQn_Type)(irq_info->source));
844 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
845}
846
847void tfm_spm_partition_psa_panic(void)
848{
849 /*
850 * PSA FF recommends that the SPM causes the system to restart when a secure
851 * partition panics.
852 */
853 tfm_hal_system_reset();
854}
855
856void tfm_spm_partition_irq_enable(psa_signal_t irq_signal)
857{
858 struct partition_t *partition;
859 struct irq_load_info_t *irq_info;
860
861 partition = tfm_spm_get_running_partition();
862 if (!partition) {
863 tfm_core_panic();
864 }
865
866 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
867 if (!irq_info) {
868 tfm_core_panic();
869 }
870
871 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
872}
873
874psa_irq_status_t tfm_spm_partition_irq_disable(psa_signal_t irq_signal)
875{
876 struct partition_t *partition;
877 struct irq_load_info_t *irq_info;
878
879 partition = tfm_spm_get_running_partition();
880 if (!partition) {
881 tfm_core_panic();
882 }
883
884 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
885 if (!irq_info) {
886 tfm_core_panic();
887 }
888
889 tfm_spm_hal_disable_irq((IRQn_Type)(irq_info->source));
890
891 return 1;
892}
893
894void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
895{
896 struct irq_load_info_t *irq_info;
897 struct partition_t *partition;
898
899 partition = tfm_spm_get_running_partition();
900 if (!partition) {
901 tfm_core_panic();
902 }
903
904 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
905 if (!irq_info) {
906 tfm_core_panic();
907 }
908
909 if (!irq_info->flih_func) {
910 /* This API is for FLIH IRQs only */
911 tfm_core_panic();
912 }
913
914 if ((partition->signals_asserted & irq_signal) == 0) {
915 /* The signal is not asserted */
916 tfm_core_panic();
917 }
918
919 partition->signals_asserted &= ~irq_signal;
920}