blob: 6d5b746aef032c4ebf6584dc398f98b81dccae3d [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"
Mingyang Sunb26b2802021-07-07 11:25:00 +080017#include "load/irq_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"
David Hu733d8f92019-09-23 15:32:40 +080020#include "tfm_wait.h"
Summer Qin1ce712a2019-10-14 18:04:05 +080021#include "tfm_nspm.h"
Ken Liubcae38b2021-01-20 15:47:44 +080022#include "ffm/spm_error_base.h"
Mingyang Sunb26b2802021-07-07 11:25:00 +080023#include "tfm_rpc.h"
24#include "tfm_spm_hal.h"
25#include "tfm_hal_platform.h"
Mingyang Suneeca4652021-07-15 15:19:16 +080026#include "tfm_psa_call_param.h"
David Hu733d8f92019-09-23 15:32:40 +080027
Ken Liub3b2cb62021-05-22 00:39:28 +080028#define GET_STATELESS_SERVICE(index) (stateless_services_ref_tbl[index])
Xinyu Zhanga38e9b52021-06-02 17:48:01 +080029extern struct service_t *stateless_services_ref_tbl[];
Mingyang Suncb6f70e2021-03-05 23:30:25 +080030
Mingyang Suneeca4652021-07-15 15:19:16 +080031
32uint32_t tfm_spm_get_lifecycle_state(void)
33{
34 /*
35 * FixMe: return PSA_LIFECYCLE_UNKNOWN to the caller directly. It will be
36 * implemented in the future.
37 */
38 return PSA_LIFECYCLE_UNKNOWN;
39}
40
41/* PSA Client API function body */
42
Mingyang Sund44522a2020-01-16 16:48:37 +080043uint32_t tfm_spm_client_psa_framework_version(void)
David Hu733d8f92019-09-23 15:32:40 +080044{
45 return PSA_FRAMEWORK_VERSION;
46}
47
Mingyang Sun22a3faf2021-07-09 15:32:47 +080048uint32_t tfm_spm_client_psa_version(uint32_t sid)
David Hu733d8f92019-09-23 15:32:40 +080049{
Mingyang Sun783a59b2021-04-20 15:52:18 +080050 struct service_t *service;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080051 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080052
53 /*
54 * It should return PSA_VERSION_NONE if the RoT Service is not
55 * implemented.
56 */
57 service = tfm_spm_get_service_by_sid(sid);
58 if (!service) {
59 return PSA_VERSION_NONE;
60 }
61
62 /*
Shawn Shan2365c902019-12-19 18:35:36 +080063 * It should return PSA_VERSION_NONE if the caller is not authorized
64 * to access the RoT Service.
David Hu733d8f92019-09-23 15:32:40 +080065 */
Ken Liubcae38b2021-01-20 15:47:44 +080066 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
Shawn Shan2365c902019-12-19 18:35:36 +080067 return PSA_VERSION_NONE;
David Hu733d8f92019-09-23 15:32:40 +080068 }
69
Ken Liuacd2a572021-05-12 16:19:04 +080070 return service->p_ldinf->version;
David Hu733d8f92019-09-23 15:32:40 +080071}
72
Mingyang Sun22a3faf2021-07-09 15:32:47 +080073psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
David Hu733d8f92019-09-23 15:32:40 +080074{
Mingyang Sun783a59b2021-04-20 15:52:18 +080075 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +080076 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +080077 struct tfm_conn_handle_t *connect_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +080078 int32_t client_id;
Ken Liu505b1702020-05-29 13:19:58 +080079 psa_handle_t handle;
Mingyang Sun22a3faf2021-07-09 15:32:47 +080080 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +080081
Kevin Pengedb8ee42021-03-09 16:50:11 +080082 /*
83 * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
84 * platform.
85 */
David Hu733d8f92019-09-23 15:32:40 +080086 service = tfm_spm_get_service_by_sid(sid);
87 if (!service) {
Shawn Shanb222d892021-01-04 17:41:48 +080088 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
David Hu733d8f92019-09-23 15:32:40 +080089 }
90
Mingyang Sunef42f442021-06-11 15:07:58 +080091 /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
92 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
93 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
94 }
95
Kevin Pengedb8ee42021-03-09 16:50:11 +080096 /*
97 * It is a PROGRAMMER ERROR if the caller is not authorized to access the
98 * RoT Service.
99 */
100 if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
101 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
102 }
103
104 /*
105 * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
106 * not supported on the platform.
107 */
108 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
109 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
110 }
111
Summer Qin1ce712a2019-10-14 18:04:05 +0800112 if (ns_caller) {
113 client_id = tfm_nspm_get_current_client_id();
114 } else {
115 client_id = tfm_spm_partition_get_running_partition_id();
116 }
117
David Hu733d8f92019-09-23 15:32:40 +0800118 /*
119 * Create connection handle here since it is possible to return the error
120 * code to client when creation fails.
121 */
Summer Qin1ce712a2019-10-14 18:04:05 +0800122 connect_handle = tfm_spm_create_conn_handle(service, client_id);
Summer Qin630c76b2020-05-20 10:32:58 +0800123 if (!connect_handle) {
David Hu733d8f92019-09-23 15:32:40 +0800124 return PSA_ERROR_CONNECTION_BUSY;
125 }
126
Kevin Pengdf6aa292021-03-11 17:58:50 +0800127 msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
128 if (!msg) {
129 /* Have no enough resource to create message */
130 return PSA_ERROR_CONNECTION_BUSY;
131 }
David Hu733d8f92019-09-23 15:32:40 +0800132
Ken Liu505b1702020-05-29 13:19:58 +0800133 handle = tfm_spm_to_user_handle(connect_handle);
David Hu733d8f92019-09-23 15:32:40 +0800134 /* No input or output needed for connect message */
Ken Liu505b1702020-05-29 13:19:58 +0800135 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
Summer Qin1ce712a2019-10-14 18:04:05 +0800136 client_id, NULL, 0, NULL, 0, NULL);
David Hu733d8f92019-09-23 15:32:40 +0800137
138 /*
139 * Send message and wake up the SP who is waiting on message queue,
140 * and scheduler triggered
141 */
142 tfm_spm_send_event(service, msg);
143
144 return PSA_SUCCESS;
145}
146
Mingyang Suneeca4652021-07-15 15:19:16 +0800147psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
148 uint32_t ctrl_param,
149 const psa_invec *inptr,
150 psa_outvec *outptr)
David Hu733d8f92019-09-23 15:32:40 +0800151{
152 psa_invec invecs[PSA_MAX_IOVEC];
153 psa_outvec outvecs[PSA_MAX_IOVEC];
Summer Qin630c76b2020-05-20 10:32:58 +0800154 struct tfm_conn_handle_t *conn_handle;
Mingyang Sun783a59b2021-04-20 15:52:18 +0800155 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800156 struct tfm_msg_body_t *msg;
Summer Qinba2346e2019-11-12 16:26:31 +0800157 int i, j;
Summer Qin1ce712a2019-10-14 18:04:05 +0800158 int32_t client_id;
Mingyang Sun453ad402021-03-17 17:58:33 +0800159 uint32_t sid, version, index;
Mingyang Sune529e3b2021-07-12 14:46:30 +0800160 uint32_t privileged;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800161 bool ns_caller = tfm_spm_is_ns_caller();
Mingyang Suneeca4652021-07-15 15:19:16 +0800162 int32_t type = (int32_t)(int16_t)((ctrl_param & TYPE_MASK) >> TYPE_OFFSET);
163 size_t in_num = (size_t)((ctrl_param & IN_LEN_MASK) >> IN_LEN_OFFSET);
164 size_t out_num = (size_t)((ctrl_param & OUT_LEN_MASK) >> OUT_LEN_OFFSET);
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800165
166 /* The request type must be zero or positive. */
167 if (type < 0) {
168 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
169 }
David Hu733d8f92019-09-23 15:32:40 +0800170
Shawn Shanb222d892021-01-04 17:41:48 +0800171 /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
David Hu733d8f92019-09-23 15:32:40 +0800172 if ((in_num > PSA_MAX_IOVEC) ||
173 (out_num > PSA_MAX_IOVEC) ||
174 (in_num + out_num > PSA_MAX_IOVEC)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800175 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800176 }
177
Summer Qin1ce712a2019-10-14 18:04:05 +0800178 if (ns_caller) {
179 client_id = tfm_nspm_get_current_client_id();
180 } else {
181 client_id = tfm_spm_partition_get_running_partition_id();
182 }
183
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800184 /* Allocate space from handle pool for static handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800185 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun453ad402021-03-17 17:58:33 +0800186 index = GET_INDEX_FROM_STATIC_HANDLE(handle);
Mingyang Sune8d38082021-03-30 18:34:40 +0800187
188 if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
189 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
190 }
191
Mingyang Sun453ad402021-03-17 17:58:33 +0800192 service = GET_STATELESS_SERVICE(index);
Mingyang Sun86213242021-07-14 10:26:43 +0800193 if (!service) {
194 tfm_core_panic();
195 }
196
Ken Liub3b2cb62021-05-22 00:39:28 +0800197 sid = service->p_ldinf->sid;
Mingyang Sun453ad402021-03-17 17:58:33 +0800198
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800199 /*
200 * It is a PROGRAMMER ERROR if the caller is not authorized to access
201 * the RoT Service.
202 */
203 if (tfm_spm_check_authorization(sid, service, ns_caller)
204 != SPM_SUCCESS) {
205 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_REFUSED);
206 }
207
Mingyang Sun453ad402021-03-17 17:58:33 +0800208 version = GET_VERSION_FROM_STATIC_HANDLE(handle);
209
210 if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
211 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
212 }
213
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800214 conn_handle = tfm_spm_create_conn_handle(service, client_id);
215
216 if (!conn_handle) {
217 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_CONNECTION_BUSY);
218 }
219
Mingyang Sun6d5dc3d2021-03-15 15:34:44 +0800220 conn_handle->rhandle = NULL;
Mingyang Suncb6f70e2021-03-05 23:30:25 +0800221 handle = tfm_spm_to_user_handle(conn_handle);
222 } else {
223 conn_handle = tfm_spm_to_handle_instance(handle);
224
225 /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
226 if (tfm_spm_validate_conn_handle(conn_handle, client_id)
227 != SPM_SUCCESS) {
228 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
229 }
230
231 /*
232 * It is a PROGRAMMER ERROR if the connection is currently
233 * handling a request.
234 */
235 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
236 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
237 }
238
239 /*
240 * Return PSA_ERROR_PROGRAMMER_ERROR immediately for the connection
241 * has been terminated by the RoT Service.
242 */
243 if (conn_handle->status == TFM_HANDLE_STATUS_CONNECT_ERROR) {
244 return PSA_ERROR_PROGRAMMER_ERROR;
245 }
246
247 service = conn_handle->service;
Summer Qin1ce712a2019-10-14 18:04:05 +0800248 }
Shawn Shanb222d892021-01-04 17:41:48 +0800249
David Hu733d8f92019-09-23 15:32:40 +0800250 if (!service) {
251 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800252 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800253 }
254
Mingyang Sune529e3b2021-07-12 14:46:30 +0800255 privileged = tfm_spm_get_caller_privilege_mode();
256
Kevin Pengedb8ee42021-03-09 16:50:11 +0800257 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800258 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
David Hu733d8f92019-09-23 15:32:40 +0800259 * if the memory reference for the wrap input vector is invalid or not
260 * readable.
261 */
262 if (tfm_memory_check(inptr, in_num * sizeof(psa_invec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800263 TFM_MEMORY_ACCESS_RO, 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 }
Summer Qinba2346e2019-11-12 16:26:31 +0800266
David Hu733d8f92019-09-23 15:32:40 +0800267 /*
268 * Read client outvecs from the wrap output vector and will update the
Shawn Shanb222d892021-01-04 17:41:48 +0800269 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
David Hu733d8f92019-09-23 15:32:40 +0800270 * the wrap output vector is invalid or not read-write.
271 */
272 if (tfm_memory_check(outptr, out_num * sizeof(psa_outvec), ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800273 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800274 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800275 }
276
Summer Qinf24dbb52020-07-23 14:53:54 +0800277 spm_memset(invecs, 0, sizeof(invecs));
278 spm_memset(outvecs, 0, sizeof(outvecs));
David Hu733d8f92019-09-23 15:32:40 +0800279
280 /* Copy the address out to avoid TOCTOU attacks. */
Summer Qinf24dbb52020-07-23 14:53:54 +0800281 spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
282 spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
David Hu733d8f92019-09-23 15:32:40 +0800283
284 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800285 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
David Hu733d8f92019-09-23 15:32:40 +0800286 * memory reference was invalid or not readable.
287 */
288 for (i = 0; i < in_num; i++) {
289 if (tfm_memory_check(invecs[i].base, invecs[i].len, ns_caller,
Ken Liubcae38b2021-01-20 15:47:44 +0800290 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800291 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800292 }
293 }
Summer Qinba2346e2019-11-12 16:26:31 +0800294
295 /*
296 * Clients must never overlap input parameters because of the risk of a
297 * double-fetch inconsistency.
298 * Overflow is checked in tfm_memory_check functions.
299 */
300 for (i = 0; i + 1 < in_num; i++) {
301 for (j = i+1; j < in_num; j++) {
TTornblom83d96372019-11-19 12:53:16 +0100302 if (!((char *) invecs[j].base + invecs[j].len <=
303 (char *) invecs[i].base ||
304 (char *) invecs[j].base >=
305 (char *) invecs[i].base + invecs[i].len)) {
Shawn Shanb222d892021-01-04 17:41:48 +0800306 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
Summer Qinba2346e2019-11-12 16:26:31 +0800307 }
308 }
309 }
310
David Hu733d8f92019-09-23 15:32:40 +0800311 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800312 * For client output vector, it is a PROGRAMMER ERROR if the provided
313 * payload memory reference was invalid or not read-write.
David Hu733d8f92019-09-23 15:32:40 +0800314 */
315 for (i = 0; i < out_num; i++) {
316 if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
Ken Liubcae38b2021-01-20 15:47:44 +0800317 ns_caller, TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800318 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
David Hu733d8f92019-09-23 15:32:40 +0800319 }
320 }
321
322 /*
323 * FixMe: Need to check if the message is unrecognized by the RoT
324 * Service or incorrectly formatted.
325 */
Kevin Pengdf6aa292021-03-11 17:58:50 +0800326 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
327 if (!msg) {
328 /* FixMe: Need to implement one mechanism to resolve this failure. */
329 TFM_PROGRAMMER_ERROR(ns_caller, PSA_ERROR_PROGRAMMER_ERROR);
330 }
David Hu733d8f92019-09-23 15:32:40 +0800331
Ken Liu505b1702020-05-29 13:19:58 +0800332 tfm_spm_fill_msg(msg, service, handle, type, client_id,
Summer Qin630c76b2020-05-20 10:32:58 +0800333 invecs, in_num, outvecs, out_num, outptr);
David Hu733d8f92019-09-23 15:32:40 +0800334
335 /*
336 * Send message and wake up the SP who is waiting on message queue,
337 * and scheduler triggered
338 */
Kevin Peng8dac6102021-03-09 16:44:00 +0800339 tfm_spm_send_event(service, msg);
340
David Hu733d8f92019-09-23 15:32:40 +0800341 return PSA_SUCCESS;
342}
343
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800344void tfm_spm_client_psa_close(psa_handle_t handle)
David Hu733d8f92019-09-23 15:32:40 +0800345{
Mingyang Sun783a59b2021-04-20 15:52:18 +0800346 struct service_t *service;
David Hu733d8f92019-09-23 15:32:40 +0800347 struct tfm_msg_body_t *msg;
Summer Qin630c76b2020-05-20 10:32:58 +0800348 struct tfm_conn_handle_t *conn_handle;
Summer Qin1ce712a2019-10-14 18:04:05 +0800349 int32_t client_id;
Mingyang Sun22a3faf2021-07-09 15:32:47 +0800350 bool ns_caller = tfm_spm_is_ns_caller();
David Hu733d8f92019-09-23 15:32:40 +0800351
352 /* It will have no effect if called with the NULL handle */
353 if (handle == PSA_NULL_HANDLE) {
354 return;
355 }
356
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800357 /* It is a PROGRAMMER ERROR if called with a stateless handle. */
Mingyang Sune8d38082021-03-30 18:34:40 +0800358 if (IS_STATIC_HANDLE(handle)) {
Mingyang Sun00cef5e2021-03-04 13:41:56 +0800359 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
360 }
361
Summer Qin1ce712a2019-10-14 18:04:05 +0800362 if (ns_caller) {
363 client_id = tfm_nspm_get_current_client_id();
364 } else {
365 client_id = tfm_spm_partition_get_running_partition_id();
366 }
367
Summer Qin373feb12020-03-27 15:35:33 +0800368 conn_handle = tfm_spm_to_handle_instance(handle);
David Hu733d8f92019-09-23 15:32:40 +0800369 /*
Shawn Shanb222d892021-01-04 17:41:48 +0800370 * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
371 * the null handle.
David Hu733d8f92019-09-23 15:32:40 +0800372 */
Ken Liubcae38b2021-01-20 15:47:44 +0800373 if (tfm_spm_validate_conn_handle(conn_handle, client_id) != SPM_SUCCESS) {
Shawn Shanb222d892021-01-04 17:41:48 +0800374 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Summer Qin1ce712a2019-10-14 18:04:05 +0800375 }
Shawn Shanb222d892021-01-04 17:41:48 +0800376
Summer Qin630c76b2020-05-20 10:32:58 +0800377 service = conn_handle->service;
David Hu733d8f92019-09-23 15:32:40 +0800378 if (!service) {
379 /* FixMe: Need to implement one mechanism to resolve this failure. */
Edison Ai9059ea02019-11-28 13:46:14 +0800380 tfm_core_panic();
David Hu733d8f92019-09-23 15:32:40 +0800381 }
382
Kevin Pengdf6aa292021-03-11 17:58:50 +0800383 msg = tfm_spm_get_msg_buffer_from_conn_handle(conn_handle);
384 if (!msg) {
385 /* FixMe: Need to implement one mechanism to resolve this failure. */
386 tfm_core_panic();
387 }
David Hu733d8f92019-09-23 15:32:40 +0800388
Shawn Shanb222d892021-01-04 17:41:48 +0800389 /*
390 * It is a PROGRAMMER ERROR if the connection is currently handling a
391 * request.
392 */
Summer Qin630c76b2020-05-20 10:32:58 +0800393 if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
Shawn Shanb222d892021-01-04 17:41:48 +0800394 TFM_PROGRAMMER_ERROR(ns_caller, PROGRAMMER_ERROR_NULL);
Shawn Shancc39fcb2019-11-13 15:38:16 +0800395 }
396
David Hu733d8f92019-09-23 15:32:40 +0800397 /* No input or output needed for close message */
Ken Liu505b1702020-05-29 13:19:58 +0800398 tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
David Hu733d8f92019-09-23 15:32:40 +0800399 NULL, 0, NULL, 0, NULL);
400
401 /*
402 * Send message and wake up the SP who is waiting on message queue,
403 * and scheduler triggered
404 */
405 tfm_spm_send_event(service, msg);
406}
Mingyang Sunb26b2802021-07-07 11:25:00 +0800407
Mingyang Suneeca4652021-07-15 15:19:16 +0800408/* PSA Partition API function body */
409
Mingyang Sunb26b2802021-07-07 11:25:00 +0800410psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
411 uint32_t timeout)
412{
413 struct partition_t *partition = NULL;
414
415 /*
416 * Timeout[30:0] are reserved for future use.
417 * SPM must ignore the value of RES.
418 */
419 timeout &= PSA_TIMEOUT_MASK;
420
421 partition = tfm_spm_get_running_partition();
422 if (!partition) {
423 tfm_core_panic();
424 }
425
426 /*
427 * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
428 * signals.
429 */
430 if ((partition->signals_allowed & signal_mask) == 0) {
431 tfm_core_panic();
432 }
433
434 /*
435 * tfm_event_wait() blocks the caller thread if no signals are available.
436 * In this case, the return value of this function is temporary set into
437 * runtime context. After new signal(s) are available, the return value
438 * is updated with the available signal(s) and blocked thread gets to run.
439 */
440 if (timeout == PSA_BLOCK &&
441 (partition->signals_asserted & signal_mask) == 0) {
442 partition->signals_waiting = signal_mask;
443 tfm_event_wait(&partition->event);
444 } else if ((partition->signals_asserted & signal_mask) == 0) {
445 /* Activate scheduler to check if any higher priority thread to run */
446 tfm_core_thrd_activate_schedule();
447 }
448
449 return partition->signals_asserted & signal_mask;
450}
451
452psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
453{
454 struct tfm_msg_body_t *tmp_msg = NULL;
455 struct partition_t *partition = NULL;
456 uint32_t privileged;
457
458 /*
459 * Only one message could be retrieved every time for psa_get(). It is a
460 * fatal error if the input signal has more than a signal bit set.
461 */
462 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
463 tfm_core_panic();
464 }
465
466 partition = tfm_spm_get_running_partition();
467 if (!partition) {
468 tfm_core_panic();
469 }
470 privileged = tfm_spm_partition_get_privileged_mode(
471 partition->p_ldinf->flags);
472
473 /*
474 * Write the message to the service buffer. It is a fatal error if the
475 * input msg pointer is not a valid memory reference or not read-write.
476 */
477 if (tfm_memory_check(msg, sizeof(psa_msg_t), false, TFM_MEMORY_ACCESS_RW,
478 privileged) != SPM_SUCCESS) {
479 tfm_core_panic();
480 }
481
482 /*
483 * It is a fatal error if the caller call psa_get() when no message has
484 * been set. The caller must call this function after an RoT Service signal
485 * is returned by psa_wait().
486 */
487 if (partition->signals_asserted == 0) {
488 tfm_core_panic();
489 }
490
491 /*
492 * It is a fatal error if the RoT Service signal is not currently asserted.
493 */
494 if ((partition->signals_asserted & signal) == 0) {
495 tfm_core_panic();
496 }
497
498 /*
499 * Get message by signal from partition. It is a fatal error if getting
500 * failed, which means the input signal is not correspond to an RoT service.
501 */
502 tmp_msg = tfm_spm_get_msg_by_signal(partition, signal);
503 if (!tmp_msg) {
504 return PSA_ERROR_DOES_NOT_EXIST;
505 }
506
507 (TO_CONTAINER(tmp_msg,
508 struct tfm_conn_handle_t,
509 internal_msg))->status = TFM_HANDLE_STATUS_ACTIVE;
510
511 spm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
512
513 return PSA_SUCCESS;
514}
515
516void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
517{
518 struct tfm_msg_body_t *msg = NULL;
519 struct tfm_conn_handle_t *conn_handle;
520
521 /* It is a fatal error if message handle is invalid */
522 msg = tfm_spm_get_msg_from_handle(msg_handle);
523 if (!msg) {
524 tfm_core_panic();
525 }
526
527 /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
528 if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
529 tfm_core_panic();
530 }
531
532 msg->msg.rhandle = rhandle;
533 conn_handle = tfm_spm_to_handle_instance(msg_handle);
534
535 /* Store reverse handle for following client calls. */
536 tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
537}
538
539size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
540 void *buffer, size_t num_bytes)
541{
542 size_t bytes;
543 struct tfm_msg_body_t *msg = NULL;
544 uint32_t privileged;
545 struct partition_t *partition = NULL;
546
547 /* It is a fatal error if message handle is invalid */
548 msg = tfm_spm_get_msg_from_handle(msg_handle);
549 if (!msg) {
550 tfm_core_panic();
551 }
552
553 partition = msg->service->partition;
554 privileged = tfm_spm_partition_get_privileged_mode(
555 partition->p_ldinf->flags);
556
557 /*
558 * It is a fatal error if message handle does not refer to a request
559 * message
560 */
561 if (msg->msg.type < PSA_IPC_CALL) {
562 tfm_core_panic();
563 }
564
565 /*
566 * It is a fatal error if invec_idx is equal to or greater than
567 * PSA_MAX_IOVEC
568 */
569 if (invec_idx >= PSA_MAX_IOVEC) {
570 tfm_core_panic();
571 }
572
573 /* There was no remaining data in this input vector */
574 if (msg->msg.in_size[invec_idx] == 0) {
575 return 0;
576 }
577
578 /*
579 * Copy the client data to the service buffer. It is a fatal error
580 * if the memory reference for buffer is invalid or not read-write.
581 */
582 if (tfm_memory_check(buffer, num_bytes, false,
583 TFM_MEMORY_ACCESS_RW, privileged) != SPM_SUCCESS) {
584 tfm_core_panic();
585 }
586
587 bytes = num_bytes > msg->msg.in_size[invec_idx] ?
588 msg->msg.in_size[invec_idx] : num_bytes;
589
590 spm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
591
592 /* There maybe some remaining data */
593 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base + bytes;
594 msg->msg.in_size[invec_idx] -= bytes;
595
596 return bytes;
597}
598
599size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
600 size_t num_bytes)
601{
602 struct tfm_msg_body_t *msg = NULL;
603
604 /* It is a fatal error if message handle is invalid */
605 msg = tfm_spm_get_msg_from_handle(msg_handle);
606 if (!msg) {
607 tfm_core_panic();
608 }
609
610 /*
611 * It is a fatal error if message handle does not refer to a request
612 * message
613 */
614 if (msg->msg.type < PSA_IPC_CALL) {
615 tfm_core_panic();
616 }
617
618 /*
619 * It is a fatal error if invec_idx is equal to or greater than
620 * PSA_MAX_IOVEC
621 */
622 if (invec_idx >= PSA_MAX_IOVEC) {
623 tfm_core_panic();
624 }
625
626 /* There was no remaining data in this input vector */
627 if (msg->msg.in_size[invec_idx] == 0) {
628 return 0;
629 }
630
631 /*
632 * If num_bytes is greater than the remaining size of the input vector then
633 * the remaining size of the input vector is used.
634 */
635 if (num_bytes > msg->msg.in_size[invec_idx]) {
636 num_bytes = msg->msg.in_size[invec_idx];
637 }
638
639 /* There maybe some remaining data */
640 msg->invec[invec_idx].base = (char *)msg->invec[invec_idx].base +
641 num_bytes;
642 msg->msg.in_size[invec_idx] -= num_bytes;
643
644 return num_bytes;
645}
646
647void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
648 const void *buffer, size_t num_bytes)
649{
650 struct tfm_msg_body_t *msg = NULL;
651 uint32_t privileged;
652 struct partition_t *partition = NULL;
653
654 /* It is a fatal error if message handle is invalid */
655 msg = tfm_spm_get_msg_from_handle(msg_handle);
656 if (!msg) {
657 tfm_core_panic();
658 }
659
660 partition = msg->service->partition;
661 privileged = tfm_spm_partition_get_privileged_mode(
662 partition->p_ldinf->flags);
663
664 /*
665 * It is a fatal error if message handle does not refer to a request
666 * message
667 */
668 if (msg->msg.type < PSA_IPC_CALL) {
669 tfm_core_panic();
670 }
671
672 /*
673 * It is a fatal error if outvec_idx is equal to or greater than
674 * PSA_MAX_IOVEC
675 */
676 if (outvec_idx >= PSA_MAX_IOVEC) {
677 tfm_core_panic();
678 }
679
680 /*
681 * It is a fatal error if the call attempts to write data past the end of
682 * the client output vector
683 */
684 if (num_bytes > msg->msg.out_size[outvec_idx] -
685 msg->outvec[outvec_idx].len) {
686 tfm_core_panic();
687 }
688
689 /*
690 * Copy the service buffer to client outvecs. It is a fatal error
691 * if the memory reference for buffer is invalid or not readable.
692 */
693 if (tfm_memory_check(buffer, num_bytes, false,
694 TFM_MEMORY_ACCESS_RO, privileged) != SPM_SUCCESS) {
695 tfm_core_panic();
696 }
697
698 spm_memcpy((char *)msg->outvec[outvec_idx].base +
699 msg->outvec[outvec_idx].len, buffer, num_bytes);
700
701 /* Update the write number */
702 msg->outvec[outvec_idx].len += num_bytes;
703}
704
705void tfm_spm_partition_psa_reply(psa_handle_t msg_handle, psa_status_t status)
706{
707 struct service_t *service = NULL;
708 struct tfm_msg_body_t *msg = NULL;
709 int32_t ret = PSA_SUCCESS;
710 struct tfm_conn_handle_t *conn_handle;
711
712 /* It is a fatal error if message handle is invalid */
713 msg = tfm_spm_get_msg_from_handle(msg_handle);
714 if (!msg) {
715 tfm_core_panic();
716 }
717
718 /*
719 * RoT Service information is needed in this function, stored it in message
720 * body structure. Only two parameters are passed in this function: handle
721 * and status, so it is useful and simply to do like this.
722 */
723 service = msg->service;
724 if (!service) {
725 tfm_core_panic();
726 }
727
728 /*
729 * Three type of message are passed in this function: CONNECTION, REQUEST,
730 * DISCONNECTION. It needs to process differently for each type.
731 */
732 conn_handle = tfm_spm_to_handle_instance(msg_handle);
733 switch (msg->msg.type) {
734 case PSA_IPC_CONNECT:
735 /*
736 * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
737 * input status is PSA_SUCCESS. Others return values are based on the
738 * input status.
739 */
740 if (status == PSA_SUCCESS) {
741 ret = msg_handle;
742 } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
743 /* Refuse the client connection, indicating a permanent error. */
744 tfm_spm_free_conn_handle(service, conn_handle);
745 ret = PSA_ERROR_CONNECTION_REFUSED;
746 } else if (status == PSA_ERROR_CONNECTION_BUSY) {
747 /* Fail the client connection, indicating a transient error. */
748 ret = PSA_ERROR_CONNECTION_BUSY;
749 } else {
750 tfm_core_panic();
751 }
752 break;
753 case PSA_IPC_DISCONNECT:
754 /* Service handle is not used anymore */
755 tfm_spm_free_conn_handle(service, conn_handle);
756
757 /*
758 * If the message type is PSA_IPC_DISCONNECT, then the status code is
759 * ignored
760 */
761 break;
762 default:
763 if (msg->msg.type >= PSA_IPC_CALL) {
764 /* Reply to a request message. Return values are based on status */
765 ret = status;
766 /*
767 * The total number of bytes written to a single parameter must be
768 * reported to the client by updating the len member of the
769 * psa_outvec structure for the parameter before returning from
770 * psa_call().
771 */
772 update_caller_outvec_len(msg);
773 if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
774 tfm_spm_free_conn_handle(service, conn_handle);
775 }
776 } else {
777 tfm_core_panic();
778 }
779 }
780
781 if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
782 /*
783 * If the source of the programmer error is a Secure Partition, the SPM
784 * must panic the Secure Partition in response to a PROGRAMMER ERROR.
785 */
786 if (TFM_CLIENT_ID_IS_NS(msg->msg.client_id)) {
787 conn_handle->status = TFM_HANDLE_STATUS_CONNECT_ERROR;
788 } else {
789 tfm_core_panic();
790 }
791 } else {
792 conn_handle->status = TFM_HANDLE_STATUS_IDLE;
793 }
794
795 if (is_tfm_rpc_msg(msg)) {
796 tfm_rpc_client_call_reply(msg, ret);
797 } else {
798 tfm_event_wake(&msg->ack_evnt, ret);
799 }
800}
801
802void tfm_spm_partition_psa_notify(int32_t partition_id)
803{
804 notify_with_signal(partition_id, PSA_DOORBELL);
805}
806
807void tfm_spm_partition_psa_clear(void)
808{
809 struct partition_t *partition = NULL;
810
811 partition = tfm_spm_get_running_partition();
812 if (!partition) {
813 tfm_core_panic();
814 }
815
816 /*
817 * It is a fatal error if the Secure Partition's doorbell signal is not
818 * currently asserted.
819 */
820 if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
821 tfm_core_panic();
822 }
823 partition->signals_asserted &= ~PSA_DOORBELL;
824}
825
826void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
827{
828 struct irq_load_info_t *irq_info = NULL;
829 struct partition_t *partition = NULL;
830
831 partition = tfm_spm_get_running_partition();
832 if (!partition) {
833 tfm_core_panic();
834 }
835
836 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
837 /* It is a fatal error if passed signal is not an interrupt signal. */
838 if (!irq_info) {
839 tfm_core_panic();
840 }
841
842 if (irq_info->flih_func) {
843 /* This API is for SLIH IRQs only */
844 psa_panic();
845 }
846
847 /* It is a fatal error if passed signal is not currently asserted */
848 if ((partition->signals_asserted & irq_signal) == 0) {
849 tfm_core_panic();
850 }
851
852 partition->signals_asserted &= ~irq_signal;
853
854 tfm_spm_hal_clear_pending_irq((IRQn_Type)(irq_info->source));
855 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
856}
857
858void tfm_spm_partition_psa_panic(void)
859{
860 /*
861 * PSA FF recommends that the SPM causes the system to restart when a secure
862 * partition panics.
863 */
864 tfm_hal_system_reset();
865}
866
867void tfm_spm_partition_irq_enable(psa_signal_t irq_signal)
868{
869 struct partition_t *partition;
870 struct irq_load_info_t *irq_info;
871
872 partition = tfm_spm_get_running_partition();
873 if (!partition) {
874 tfm_core_panic();
875 }
876
877 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
878 if (!irq_info) {
879 tfm_core_panic();
880 }
881
882 tfm_spm_hal_enable_irq((IRQn_Type)(irq_info->source));
883}
884
885psa_irq_status_t tfm_spm_partition_irq_disable(psa_signal_t irq_signal)
886{
887 struct partition_t *partition;
888 struct irq_load_info_t *irq_info;
889
890 partition = tfm_spm_get_running_partition();
891 if (!partition) {
892 tfm_core_panic();
893 }
894
895 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
896 if (!irq_info) {
897 tfm_core_panic();
898 }
899
900 tfm_spm_hal_disable_irq((IRQn_Type)(irq_info->source));
901
902 return 1;
903}
904
905void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
906{
907 struct irq_load_info_t *irq_info;
908 struct partition_t *partition;
909
910 partition = tfm_spm_get_running_partition();
911 if (!partition) {
912 tfm_core_panic();
913 }
914
915 irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
916 if (!irq_info) {
917 tfm_core_panic();
918 }
919
920 if (!irq_info->flih_func) {
921 /* This API is for FLIH IRQs only */
922 tfm_core_panic();
923 }
924
925 if ((partition->signals_asserted & irq_signal) == 0) {
926 /* The signal is not asserted */
927 tfm_core_panic();
928 }
929
930 partition->signals_asserted &= ~irq_signal;
931}