blob: 252716e483724b07537c51cf1f48d7569e789778 [file] [log] [blame]
Mingyang Sunda01a972019-07-12 17:32:59 +08001/*
Kevin Penga20b5af2021-01-11 11:20:52 +08002 * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
Mingyang Sunda01a972019-07-12 17:32:59 +08003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
Mingyang Sunabb1aab2020-02-18 13:49:08 +08008#include <stdint.h>
Mingyang Sunda01a972019-07-12 17:32:59 +08009#include <stdbool.h>
Mingyang Sunabb1aab2020-02-18 13:49:08 +080010#include <arm_cmse.h>
Antonio de Angelisa4f23f82021-05-05 22:40:39 +010011#include "arch.h"
Ken Liu24dffb22021-02-10 11:03:58 +080012#include "bitops.h"
David Hu9804b6a2021-02-15 21:23:06 +080013#include "fih.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080014#include "tfm_nspm.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080015#include "tfm_api.h"
16#include "tfm_arch.h"
17#include "tfm_irq_list.h"
18#include "psa/service.h"
19#include "tfm_core_mem_check.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080020#include "tfm_peripherals_def.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080021#include "tfm_secure_api.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080022#include "tfm_spm_hal.h"
Soby Mathew960521a2020-09-29 12:48:50 +010023#include "tfm_core_trustzone.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080024#include "spm_func.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080025#include "region_defs.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080026#include "region.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080027#include "spm_partition_defs.h"
28#include "psa_manifest/pid.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080029#include "tfm/tfm_spm_services.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080030#include "tfm_spm_db_func.inc"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080031
David Hu5da82de2020-12-02 16:41:30 +080032/* Structure to temporarily save iovec parameters from PSA client */
33struct iovec_params_t {
34 psa_invec in_vec[PSA_MAX_IOVEC];
35 size_t in_len;
36 psa_outvec out_vec[PSA_MAX_IOVEC];
37 size_t out_len;
38
39 psa_outvec *orig_outvec;
40};
41
Mingyang Sunabb1aab2020-02-18 13:49:08 +080042#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
43#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
44
45#ifndef TFM_LVL
46#error TFM_LVL is not defined!
47#endif
48
Soby Mathew960521a2020-09-29 12:48:50 +010049#ifdef TFM_MULTI_CORE_TOPOLOGY
50#error Multi core is not supported by Function mode
51#endif
52
Mingyang Sunabb1aab2020-02-18 13:49:08 +080053REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Base, uint32_t);
54REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Limit, struct iovec_args_t)[];
55
Soby Mathew960521a2020-09-29 12:48:50 +010056static uint32_t *tfm_secure_stack_seal =
57 ((uint32_t *)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1]) - 2;
58
shejia0101a497c2021-04-21 10:04:07 +080059REGION_DECLARE_T(Image$$, ARM_LIB_STACK_SEAL, $$ZI$$Base, uint32_t)[];
Soby Mathew960521a2020-09-29 12:48:50 +010060
61/*
62 * Function to seal the psp stacks for Function model of TF-M.
63 */
64void tfm_spm_seal_psp_stacks(void)
65{
66 /*
67 * The top of TFM_SECURE_STACK is used for iovec parameters, we need to
68 * place the seal between iovec parameters and partition stack.
69 *
70 * Image$$TFM_SECURE_STACK$$ZI$$Limit-> +-------------------------+
71 * | |
72 * | iovec parameters for |
73 * | partition |
74 * (Image$$TFM_SECURE_STACK$$ZI$$Limit -| |
75 * sizeof(iovec_args_t)) -> +-------------------------+
76 * | Stack Seal |
77 * +-------------------------+
78 * | |
79 * | Partition stack |
80 * | |
81 * Image$$TFM_SECURE_STACK$$ZI$$Base-> +-------------------------+
82 */
83 *(tfm_secure_stack_seal) = TFM_STACK_SEAL_VALUE;
84 *(tfm_secure_stack_seal + 1) = TFM_STACK_SEAL_VALUE;
85
86 /*
87 * Seal the ARM_LIB_STACK by writing the seal value to the reserved
88 * region.
89 */
shejia0101a497c2021-04-21 10:04:07 +080090 uint32_t *arm_lib_stck_seal_base =
91 ((uint32_t *)&REGION_NAME(Image$$, ARM_LIB_STACK_SEAL, $$ZI$$Base)[-1]) - 2;
Soby Mathew960521a2020-09-29 12:48:50 +010092
93 *(arm_lib_stck_seal_base) = TFM_STACK_SEAL_VALUE;
94 *(arm_lib_stck_seal_base + 1) = TFM_STACK_SEAL_VALUE;
95}
96
Mingyang Sunabb1aab2020-02-18 13:49:08 +080097/*
98 * This is the "Big Lock" on the secure side, to guarantee single entry
99 * to SPE
100 */
Summer Qin5fdcf632020-06-22 16:49:24 +0800101static int32_t tfm_secure_lock;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800102static int32_t tfm_secure_api_initializing = 1;
Mingyang Sunda01a972019-07-12 17:32:59 +0800103
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800104static uint32_t *prepare_partition_iovec_ctx(
105 const struct tfm_state_context_t *svc_ctx,
106 const struct tfm_sfn_req_s *desc_ptr,
107 const struct iovec_args_t *iovec_args,
108 uint32_t *dst)
109{
110 /* XPSR = as was when called, but make sure it's thread mode */
111 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00U;
112 /* ReturnAddress = resume veneer in new context */
113 *(--dst) = svc_ctx->ra;
114 /* LR = sfn address */
115 *(--dst) = (uint32_t)desc_ptr->sfn;
116 /* R12 = don't care */
117 *(--dst) = 0U;
118
119 /* R0-R3 = sfn arguments */
120 *(--dst) = iovec_args->out_len;
121 *(--dst) = (uint32_t)iovec_args->out_vec;
122 *(--dst) = iovec_args->in_len;
123 *(--dst) = (uint32_t)iovec_args->in_vec;
124
125 return dst;
126}
127
128/**
129 * \brief Create a stack frame that sets the execution environment to thread
130 * mode on exception return.
131 *
132 * \param[in] svc_ctx The stacked SVC context
133 * \param[in] unpriv_handler The unprivileged IRQ handler to be called
134 * \param[in] dst A pointer where the context is to be created. (the
135 * pointer is considered to be a stack pointer, and
136 * the frame is created below it)
137 *
138 * \return A pointer pointing at the created stack frame.
139 */
140static int32_t *prepare_partition_irq_ctx(
141 const struct tfm_state_context_t *svc_ctx,
142 sfn_t unpriv_handler,
143 int32_t *dst)
144{
145 int i;
146
147 /* XPSR = as was when called, but make sure it's thread mode */
148 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00;
149 /* ReturnAddress = resume to the privileged handler code, but execute it
150 * unprivileged.
151 */
152 *(--dst) = svc_ctx->ra;
153 /* LR = start address */
154 *(--dst) = (int32_t)unpriv_handler;
155
156 /* R12, R0-R3 unused arguments */
157 for (i = 0; i < 5; ++i) {
158 *(--dst) = 0;
159 }
160
161 return dst;
162}
163
164static void restore_caller_ctx(const struct tfm_state_context_t *svc_ctx,
165 struct tfm_state_context_t *target_ctx)
166{
167 /* ReturnAddress = resume veneer after second SVC */
168 target_ctx->ra = svc_ctx->ra;
169
170 /* R0 = function return value */
171 target_ctx->r0 = svc_ctx->r0;
172
173 return;
174}
175
176/**
177 * \brief Check whether the iovec parameters are valid, and the memory ranges
178 * are in the possession of the calling partition.
179 *
David Hu5da82de2020-12-02 16:41:30 +0800180 * \param[in] desc_ptr The secure function request descriptor
181 * \param[out] iovec_ptr The local buffer to store iovec arguments
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800182 *
183 * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
184 * otherwise as in /ref tfm_status_e
185 */
186static enum tfm_status_e tfm_core_check_sfn_parameters(
David Hu5da82de2020-12-02 16:41:30 +0800187 const struct tfm_sfn_req_s *desc_ptr,
188 struct iovec_params_t *iovec_ptr)
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800189{
190 struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
191 size_t in_len;
192 struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
193 size_t out_len;
194 uint32_t i;
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800195 uint32_t privileged_mode = TFM_PARTITION_UNPRIVILEGED_MODE;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800196
197 if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
198 return TFM_ERROR_INVALID_PARAMETER;
199 }
200
201 in_len = (size_t)(desc_ptr->args[1]);
202 out_len = (size_t)(desc_ptr->args[3]);
203
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800204 /*
205 * Get caller's privileged mode:
206 * The privileged mode of NS Secure Service caller will be decided by the
207 * tfm_core_has_xxx_access_to_region functions.
208 * Secure caller can be only privileged mode because the whole SPE is
209 * running under privileged mode
210 */
211 if (!desc_ptr->ns_caller) {
212 privileged_mode = TFM_PARTITION_PRIVILEGED_MODE;
213 }
214
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800215 /* The number of vectors are within range. Extra checks to avoid overflow */
216 if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
217 (in_len + out_len > PSA_MAX_IOVEC)) {
218 return TFM_ERROR_INVALID_PARAMETER;
219 }
220
221 /* Check whether the caller partition has at write access to the iovec
222 * structures themselves. Use the TT instruction for this.
223 */
224 if (in_len > 0) {
225 if ((in_vec == NULL) ||
226 (tfm_core_has_write_access_to_region(in_vec,
227 sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800228 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800229 return TFM_ERROR_INVALID_PARAMETER;
230 }
231 } else {
232 if (in_vec != NULL) {
233 return TFM_ERROR_INVALID_PARAMETER;
234 }
235 }
236 if (out_len > 0) {
237 if ((out_vec == NULL) ||
238 (tfm_core_has_write_access_to_region(out_vec,
239 sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800240 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800241 return TFM_ERROR_INVALID_PARAMETER;
242 }
243 } else {
244 if (out_vec != NULL) {
245 return TFM_ERROR_INVALID_PARAMETER;
246 }
247 }
248
David Hu5da82de2020-12-02 16:41:30 +0800249 /* Copy iovec parameters into a local buffer before validating them */
250 iovec_ptr->in_len = in_len;
251 for (i = 0; i < in_len; ++i) {
252 iovec_ptr->in_vec[i].base = in_vec[i].base;
253 iovec_ptr->in_vec[i].len = in_vec[i].len;
254 }
255 iovec_ptr->out_len = out_len;
256 for (i = 0; i < out_len; ++i) {
257 iovec_ptr->out_vec[i].base = out_vec[i].base;
258 iovec_ptr->out_vec[i].len = out_vec[i].len;
259 }
260 iovec_ptr->orig_outvec = out_vec;
261
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800262 /* Check whether the caller partition has access to the data inside the
263 * iovecs
264 */
265 for (i = 0; i < in_len; ++i) {
David Hu5da82de2020-12-02 16:41:30 +0800266 if (iovec_ptr->in_vec[i].len > 0) {
267 if ((iovec_ptr->in_vec[i].base == NULL) ||
268 (tfm_core_has_read_access_to_region(iovec_ptr->in_vec[i].base,
269 iovec_ptr->in_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800270 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800271 return TFM_ERROR_INVALID_PARAMETER;
272 }
273 }
274 }
275 for (i = 0; i < out_len; ++i) {
David Hu5da82de2020-12-02 16:41:30 +0800276 if (iovec_ptr->out_vec[i].len > 0) {
277 if ((iovec_ptr->out_vec[i].base == NULL) ||
278 (tfm_core_has_write_access_to_region(iovec_ptr->out_vec[i].base,
279 iovec_ptr->out_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800280 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800281 return TFM_ERROR_INVALID_PARAMETER;
282 }
283 }
284 }
285
286 return TFM_SUCCESS;
287}
288
289static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
290 const struct iovec_args_t *source)
291{
292 size_t i;
293
294 /* The vectors have been sanity checked already, and since then the
295 * interrupts have been kept disabled. So we can be sure that the
296 * vectors haven't been tampered with since the check. So it is safe to pass
297 * it to the called partition.
298 */
299
300 target->in_len = source->in_len;
301 for (i = 0; i < source->in_len; ++i) {
302 target->in_vec[i].base = source->in_vec[i].base;
303 target->in_vec[i].len = source->in_vec[i].len;
304 }
305 target->out_len = source->out_len;
306 for (i = 0; i < source->out_len; ++i) {
307 target->out_vec[i].base = source->out_vec[i].base;
308 target->out_vec[i].len = source->out_vec[i].len;
309 }
310}
311
312static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
313{
314 int i;
315
316 args->in_len = 0;
317 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
318 args->in_vec[i].base = NULL;
319 args->in_vec[i].len = 0;
320 }
321 args->out_len = 0;
322 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
323 args->out_vec[i].base = NULL;
324 args->out_vec[i].len = 0;
325 }
326}
327
328/**
329 * \brief Check whether the partitions for the secure function call are in a
330 * proper state.
331 *
332 * \param[in] curr_partition_state State of the partition to be called
333 * \param[in] caller_partition_state State of the caller partition
334 *
335 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
336 */
337static enum tfm_status_e check_partition_state(uint32_t curr_partition_state,
338 uint32_t caller_partition_state)
339{
340 if (caller_partition_state != SPM_PARTITION_STATE_RUNNING) {
341 /* Calling partition from non-running state (e.g. during handling IRQ)
342 * is not allowed.
343 */
344 return TFM_ERROR_INVALID_EXC_MODE;
345 }
346
347 if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
348 curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
349 curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
350 curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
351 /* Active partitions cannot be called! */
352 return TFM_ERROR_PARTITION_NON_REENTRANT;
353 } else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
354 /* The partition to be called is not in a proper state */
355 return TFM_SECURE_LOCK_FAILED;
356 }
357 return TFM_SUCCESS;
358}
359
360/**
361 * \brief Check whether the partitions for the secure function call of irq are
362 * in a proper state.
363 *
364 * \param[in] called_partition_state State of the partition to be called
365 *
366 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
367 */
368static enum tfm_status_e check_irq_partition_state(
369 uint32_t called_partition_state)
370{
371 if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
372 called_partition_state == SPM_PARTITION_STATE_RUNNING ||
373 called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
374 called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
375 called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
376 return TFM_SUCCESS;
377 }
378 return TFM_SECURE_LOCK_FAILED;
379}
380
381/**
382 * \brief Calculate the address where the iovec parameters are to be saved for
383 * the called partition.
384 *
385 * \param[in] partition_idx The index of the partition to be called.
386 *
387 * \return The address where the iovec parameters should be saved.
388 */
389static struct iovec_args_t *get_iovec_args_stack_address(uint32_t partition_idx)
390{
391 /* Save the iovecs on the common stack. */
TTornblom99f0be22019-12-17 16:22:38 +0100392 return &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800393}
394
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800395/**
396 * \brief Returns the index of the partition with the given partition ID.
397 *
398 * \param[in] partition_id Partition id
399 *
400 * \return the partition idx if partition_id is valid,
401 * \ref SPM_INVALID_PARTITION_IDX othervise
402 */
403static uint32_t get_partition_idx(uint32_t partition_id)
404{
405 uint32_t i;
406
407 if (partition_id == INVALID_PARTITION_ID) {
408 return SPM_INVALID_PARTITION_IDX;
409 }
410
411 for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
412 if (g_spm_partition_db.partitions[i].static_data->partition_id ==
413 partition_id) {
414 return i;
415 }
416 }
417 return SPM_INVALID_PARTITION_IDX;
418}
419
420/**
David Hu5da82de2020-12-02 16:41:30 +0800421 * \brief Set the iovec parameters for the partition
422 *
423 * \param[in] partition_idx Partition index
424 * \param[in] iovec_ptr The arguments of the secure function
425 *
426 * \return Error code \ref spm_err_t
427 *
428 * \note This function doesn't check if partition_idx is valid.
429 * \note This function assumes that the iovecs that are passed in iovec_ptr are
430 * valid, and does no sanity check on them at all.
431 */
432static enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
433 const struct iovec_params_t *iovec_ptr)
434{
435 struct spm_partition_runtime_data_t *runtime_data =
436 &g_spm_partition_db.partitions[partition_idx].runtime_data;
437 size_t i;
438
439 if ((iovec_ptr->in_len < 0) || (iovec_ptr->out_len < 0)) {
440 return SPM_ERR_INVALID_PARAMETER;
441 }
442
443 runtime_data->iovec_args.in_len = iovec_ptr->in_len;
444 for (i = 0U; i < runtime_data->iovec_args.in_len; ++i) {
445 runtime_data->iovec_args.in_vec[i].base = iovec_ptr->in_vec[i].base;
446 runtime_data->iovec_args.in_vec[i].len = iovec_ptr->in_vec[i].len;
447 }
448 runtime_data->iovec_args.out_len = iovec_ptr->out_len;
449 for (i = 0U; i < runtime_data->iovec_args.out_len; ++i) {
450 runtime_data->iovec_args.out_vec[i].base = iovec_ptr->out_vec[i].base;
451 runtime_data->iovec_args.out_vec[i].len = iovec_ptr->out_vec[i].len;
452 }
453 runtime_data->orig_outvec = iovec_ptr->orig_outvec;
454
455 return SPM_ERR_OK;
456}
457
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800458static enum tfm_status_e tfm_start_partition(
David Hu5da82de2020-12-02 16:41:30 +0800459 const struct tfm_sfn_req_s *desc_ptr,
460 const struct iovec_params_t *iovec_ptr,
461 uint32_t excReturn)
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800462{
Xinyu Zhang3a453242021-04-16 17:57:09 +0800463 register uint32_t partition_idx;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800464 enum tfm_status_e res;
465 uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
466 const struct spm_partition_runtime_data_t *curr_part_data;
467 const struct spm_partition_runtime_data_t *caller_part_data;
468 uint32_t caller_flags;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800469 uint32_t psp;
470 uint32_t partition_psp, partition_psplim;
471 uint32_t partition_state;
472 uint32_t caller_partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800473 struct tfm_state_context_t *svc_ctx;
474 uint32_t caller_partition_id;
475 int32_t client_id;
476 struct iovec_args_t *iovec_args;
477
478 psp = __get_PSP();
479 svc_ctx = (struct tfm_state_context_t *)psp;
480 caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
481
482 /* Check partition state consistency */
483 if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
484 != (!desc_ptr->ns_caller)) {
485 /* Partition state inconsistency detected */
486 return TFM_SECURE_LOCK_FAILED;
487 }
488
489 partition_idx = get_partition_idx(desc_ptr->sp_id);
490
491 curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
492 caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
493 partition_state = curr_part_data->partition_state;
494 caller_partition_state = caller_part_data->partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800495 caller_partition_id = tfm_spm_partition_get_partition_id(
496 caller_partition_idx);
497
498 if (!tfm_secure_api_initializing) {
499 res = check_partition_state(partition_state, caller_partition_state);
500 if (res != TFM_SUCCESS) {
501 return res;
502 }
503 }
504
505 /* Prepare switch to shared secure partition stack */
506 /* In case the call is coming from the non-secure world, we save the iovecs
Soby Mathew960521a2020-09-29 12:48:50 +0100507 * on the stop of the stack. Also the stack seal is present below this region.
508 * So the memory area, that can actually be used as stack by the partitions
509 * starts at a lower address.
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800510 */
Soby Mathew960521a2020-09-29 12:48:50 +0100511 partition_psp = (uint32_t) tfm_secure_stack_seal;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800512 partition_psplim =
513 (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
514
515 /* Store the context for the partition call */
516 tfm_spm_partition_set_caller_partition_idx(partition_idx,
517 caller_partition_idx);
518 tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
519
520 if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
521 tfm_spm_partition_set_caller_client_id(partition_idx,
522 caller_partition_id);
523 } else {
524 client_id = tfm_nspm_get_current_client_id();
525 if (client_id >= 0) {
526 return TFM_SECURE_LOCK_FAILED;
527 }
528 tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
529 }
530
531 /* In level one, only switch context and return from exception if in
532 * handler mode
533 */
534 if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
David Hu5da82de2020-12-02 16:41:30 +0800535 if (tfm_spm_partition_set_iovec(partition_idx, iovec_ptr) !=
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800536 SPM_ERR_OK) {
537 return TFM_ERROR_GENERIC;
538 }
539 iovec_args = get_iovec_args_stack_address(partition_idx);
540 tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
541
542 /* Prepare the partition context, update stack ptr */
543 psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
544 iovec_args,
545 (uint32_t *)partition_psp);
546 __set_PSP(psp);
547 tfm_arch_set_psplim(partition_psplim);
548 }
549
550 tfm_spm_partition_set_state(caller_partition_idx,
551 SPM_PARTITION_STATE_BLOCKED);
552 tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
553 tfm_secure_lock++;
554
555 return TFM_SUCCESS;
556}
557
558static enum tfm_status_e tfm_start_partition_for_irq_handling(
559 uint32_t excReturn,
560 struct tfm_state_context_t *svc_ctx)
561{
562 uint32_t handler_partition_id = svc_ctx->r0;
563 sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
564 uint32_t irq_signal = svc_ctx->r2;
Kevin Penga20b5af2021-01-11 11:20:52 +0800565 uint32_t irq_line = svc_ctx->r3;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800566 enum tfm_status_e res;
567 uint32_t psp = __get_PSP();
568 uint32_t handler_partition_psp;
569 uint32_t handler_partition_state;
570 uint32_t interrupted_partition_idx =
571 tfm_spm_partition_get_running_partition_idx();
572 const struct spm_partition_runtime_data_t *handler_part_data;
573 uint32_t handler_partition_idx;
574
575 handler_partition_idx = get_partition_idx(handler_partition_id);
576 handler_part_data = tfm_spm_partition_get_runtime_data(
577 handler_partition_idx);
578 handler_partition_state = handler_part_data->partition_state;
579
580 res = check_irq_partition_state(handler_partition_state);
581 if (res != TFM_SUCCESS) {
582 return res;
583 }
584
585 /* set mask for the partition */
586 tfm_spm_partition_set_signal_mask(
587 handler_partition_idx,
588 handler_part_data->signal_mask | irq_signal);
589
590 tfm_spm_hal_disable_irq(irq_line);
591
592 /* save the current context of the interrupted partition */
593 tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
594
595 handler_partition_psp = psp;
596
597 /* save the current context of the handler partition */
598 tfm_spm_partition_push_handler_ctx(handler_partition_idx);
599
600 /* Store caller for the partition */
601 tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
602 interrupted_partition_idx);
603
604 psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
605 (int32_t *)handler_partition_psp);
606 __set_PSP(psp);
607
608 tfm_spm_partition_set_state(interrupted_partition_idx,
609 SPM_PARTITION_STATE_SUSPENDED);
610 tfm_spm_partition_set_state(handler_partition_idx,
611 SPM_PARTITION_STATE_HANDLING_IRQ);
612
613 return TFM_SUCCESS;
614}
615
616static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
617{
618 uint32_t current_partition_idx =
619 tfm_spm_partition_get_running_partition_idx();
620 const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800621 uint32_t return_partition_idx;
622 uint32_t return_partition_flags;
623 uint32_t psp = __get_PSP();
624 size_t i;
625 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
626 struct iovec_args_t *iovec_args;
627
628 if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
629 return TFM_SECURE_UNLOCK_FAILED;
630 }
631
632 curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
633 return_partition_idx = curr_part_data->caller_partition_idx;
634
635 if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
636 return TFM_SECURE_UNLOCK_FAILED;
637 }
638
639 ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
640
641 return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800642
643 tfm_secure_lock--;
644
645 if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
646 (tfm_secure_api_initializing)) {
647 /* In TFM level 1 context restore is only done when
648 * returning to NS or after initialization
649 */
650 /* Restore caller context */
651 restore_caller_ctx(svc_ctx,
652 (struct tfm_state_context_t *)ret_part_data->stack_ptr);
653 *excReturn = ret_part_data->lr;
654 __set_PSP(ret_part_data->stack_ptr);
TTornblom99f0be22019-12-17 16:22:38 +0100655 REGION_DECLARE_T(Image$$, ARM_LIB_STACK, $$ZI$$Base, uint32_t)[];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800656 uint32_t psp_stack_bottom =
657 (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
658 tfm_arch_set_psplim(psp_stack_bottom);
659
TTornblom99f0be22019-12-17 16:22:38 +0100660 iovec_args = &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800661
662 for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
663 curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
664 }
665 tfm_clear_iovec_parameters(iovec_args);
666 }
667
668 tfm_spm_partition_cleanup_context(current_partition_idx);
669
670 tfm_spm_partition_set_state(current_partition_idx,
671 SPM_PARTITION_STATE_IDLE);
672 tfm_spm_partition_set_state(return_partition_idx,
673 SPM_PARTITION_STATE_RUNNING);
674
675 return TFM_SUCCESS;
676}
677
678static enum tfm_status_e tfm_return_from_partition_irq_handling(
679 uint32_t *excReturn)
680{
681 uint32_t handler_partition_idx =
682 tfm_spm_partition_get_running_partition_idx();
683 const struct spm_partition_runtime_data_t *handler_part_data;
684 uint32_t interrupted_partition_idx;
685 uint32_t psp = __get_PSP();
686 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
687
688 if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
689 return TFM_SECURE_UNLOCK_FAILED;
690 }
691
692 handler_part_data = tfm_spm_partition_get_runtime_data(
693 handler_partition_idx);
694 interrupted_partition_idx = handler_part_data->caller_partition_idx;
695
696 if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
697 return TFM_SECURE_UNLOCK_FAILED;
698 }
699
700 /* For level 1, modify PSP, so that the SVC stack frame disappears,
701 * and return to the privileged handler using the stack frame still on the
702 * MSP stack.
703 */
704 *excReturn = svc_ctx->ra;
705 psp += sizeof(struct tfm_state_context_t);
706
707 tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
708 tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
709
710 __set_PSP(psp);
711
712 return TFM_SUCCESS;
713}
714
715static enum tfm_status_e tfm_check_sfn_req_integrity(
716 const struct tfm_sfn_req_s *desc_ptr)
717{
718 if ((desc_ptr == NULL) ||
719 (desc_ptr->sp_id == 0) ||
720 (desc_ptr->sfn == NULL)) {
721 /* invalid parameter */
722 return TFM_ERROR_INVALID_PARAMETER;
723 }
724 return TFM_SUCCESS;
725}
726
727static enum tfm_status_e tfm_core_check_sfn_req_rules(
728 const struct tfm_sfn_req_s *desc_ptr)
729{
730 /* Check partition idx validity */
731 if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
732 return TFM_ERROR_NO_ACTIVE_PARTITION;
733 }
734
735 if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
736 /* Secure domain is already locked!
737 * This should only happen if caller is secure partition!
738 */
739 /* This scenario is a potential security breach.
740 * Error is handled in caller.
741 */
742 return TFM_ERROR_SECURE_DOMAIN_LOCKED;
743 }
744
745 if (tfm_secure_api_initializing) {
746 int32_t id =
747 tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
748
749 if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
750 /* Invalid request during system initialization */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100751 SPMLOG_ERRMSG("Invalid service request during initialization!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800752 return TFM_ERROR_NOT_INITIALIZED;
753 }
754 }
755
756 return TFM_SUCCESS;
757}
758
Antonio de Angelis5b64bb72021-04-27 08:37:14 +0100759uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
760{
761 return g_spm_partition_db.partitions[partition_idx].static_data->
762 partition_flags;
763}
764
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800765uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
766{
767 return g_spm_partition_db.partitions[partition_idx].static_data->
768 partition_id;
769}
770
771uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
772{
773 if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
774 return TFM_PARTITION_PRIVILEGED_MODE;
775 } else {
776 return TFM_PARTITION_UNPRIVILEGED_MODE;
777 }
778}
779
780bool tfm_is_partition_privileged(uint32_t partition_idx)
781{
782 uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
783
784 return tfm_spm_partition_get_privileged_mode(flags) ==
785 TFM_PARTITION_PRIVILEGED_MODE;
786}
787
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800788void tfm_spm_secure_api_init_done(void)
789{
790 tfm_secure_api_initializing = 0;
791}
792
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100793static enum tfm_status_e tfm_spm_sfn_request_handler(
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800794 struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
795{
796 enum tfm_status_e res;
shejia0101a497c2021-04-21 10:04:07 +0800797 struct iovec_params_t iovecs = {0};
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800798
799 res = tfm_check_sfn_req_integrity(desc_ptr);
800 if (res != TFM_SUCCESS) {
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100801 SPMLOG_ERRMSG("Invalid service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800802 tfm_secure_api_error_handler();
803 }
804
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800805 desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
806
David Hu5da82de2020-12-02 16:41:30 +0800807 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800808 if (res != TFM_SUCCESS) {
809 /* The sanity check of iovecs failed. */
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800810 tfm_secure_api_error_handler();
811 }
812
813 res = tfm_core_check_sfn_req_rules(desc_ptr);
814 if (res != TFM_SUCCESS) {
815 /* FixMe: error compartmentalization TBD */
816 tfm_spm_partition_set_state(
817 desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100818 SPMLOG_ERRMSG("Unauthorized service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800819 tfm_secure_api_error_handler();
820 }
821
David Hu5da82de2020-12-02 16:41:30 +0800822 res = tfm_start_partition(desc_ptr, &iovecs, excReturn);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800823 if (res != TFM_SUCCESS) {
824 /* FixMe: consider possible fault scenarios */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100825 SPMLOG_ERRMSG("Failed to process service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800826 tfm_secure_api_error_handler();
827 }
828
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800829 return res;
830}
831
832int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
833{
834 enum tfm_status_e res;
835 int32_t *args;
836 int32_t retVal;
David Hu5da82de2020-12-02 16:41:30 +0800837 struct iovec_params_t iovecs;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800838
David Hu5da82de2020-12-02 16:41:30 +0800839 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800840 if (res != TFM_SUCCESS) {
841 /* The sanity check of iovecs failed. */
842 return (int32_t)res;
843 }
844
845 /* No excReturn value is needed as no exception handling is used */
846 res = tfm_spm_sfn_request_handler(desc_ptr, 0);
847
848 if (res != TFM_SUCCESS) {
849 tfm_secure_api_error_handler();
850 }
851
852 /* Secure partition to secure partition call in TFM level 1 */
853 args = desc_ptr->args;
854 retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
855
856 /* return handler should restore original exc_return value... */
857 res = tfm_return_from_partition(NULL);
858 if (res == TFM_SUCCESS) {
859 /* If unlock successful, pass SS return value to caller */
860 return retVal;
861 } else {
862 /* Unlock errors indicate ctx database corruption or unknown
863 * anomalies. Halt execution
864 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100865 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800866 tfm_secure_api_error_handler();
867 }
868 return (int32_t)res;
869}
870
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800871int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
872 void *start_addr,
873 size_t len,
874 uint32_t alignment)
875{
876 uintptr_t start_addr_value = (uintptr_t)start_addr;
877 uintptr_t end_addr_value = (uintptr_t)start_addr + len;
878 uintptr_t alignment_mask;
879
880 alignment_mask = (((uintptr_t)1) << alignment) - 1;
881
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100882 /* Check pointer alignment and protect against overflow and zero len */
883 if (!(start_addr_value & alignment_mask) &&
884 (end_addr_value > start_addr_value)) {
885 /* Check that the range is in S_DATA */
886 if ((start_addr_value >= S_DATA_START) &&
887 (end_addr_value <= (S_DATA_START + S_DATA_SIZE))) {
888 return TFM_SUCCESS;
889 } else {
890 return TFM_ERROR_NOT_IN_RANGE;
891 }
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800892 }
893
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100894 return TFM_ERROR_INVALID_PARAMETER;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800895}
896
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100897static void tfm_spm_partition_requests_thread(struct tfm_sfn_req_s *desc_ptr,
898 uint32_t exc_return,
899 uint32_t is_return,
900 uintptr_t msp)
Antonio de Angelis00667fc2021-05-05 22:40:39 +0100901{
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100902 enum tfm_status_e res;
903 uint32_t exc_ret;
Antonio de Angelis0ac5bb42021-06-30 11:47:07 +0100904
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100905 if (!is_return) {
906 res = tfm_spm_sfn_request_handler(desc_ptr, exc_return);
907 exc_ret = EXC_RETURN_SECURE_FUNCTION;
908 } else {
909 res = tfm_return_from_partition(&exc_return);
910 exc_ret = exc_return;
911 }
912 /* Reset MSP at top of stack and do TFM_SVC_SFN_COMPLETION */
913 tfm_sfn_completion(res, exc_ret, msp);
914}
915
916/* This SVC handler is called if veneer is running in thread mode */
917void tfm_spm_partition_request_return_handler(
918 const uint32_t *svc_ctx, uint32_t exc_return, uint32_t *msp)
919{
920 if (!(exc_return & EXC_RETURN_STACK_PROCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800921 /* Service request SVC called with MSP active.
922 * Either invalid configuration for Thread mode or SVC called
923 * from Handler mode, which is not supported.
924 * FixMe: error severity TBD
925 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100926 SPMLOG_ERRMSG("Service request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800927 tfm_secure_api_error_handler();
928 }
929
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100930 /* Setup a context on the stack to trigger exception return */
931 struct tfm_state_context_t ctx = {0};
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800932
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100933 ctx.r0 = svc_ctx ? svc_ctx[0] : (uintptr_t) NULL;
934 ctx.r1 = exc_return;
935 ctx.r2 = svc_ctx ? 0 : 1;
936 ctx.r3 = (uintptr_t) msp;
937 ctx.xpsr = XPSR_T32;
938 ctx.ra = (uint32_t) tfm_spm_partition_requests_thread & ~0x1UL;
939
940 __set_MSP((uint32_t)&ctx);
941
942 tfm_arch_trigger_exc_return(EXC_RETURN_THREAD_S_MSP);
943}
944
945void tfm_spm_partition_completion_handler(enum tfm_status_e res, uint32_t exc_return, uint32_t *msp)
946{
947 if (res != TFM_SUCCESS) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800948 tfm_secure_api_error_handler();
949 }
950
Antonio de Angelisa4f23f82021-05-05 22:40:39 +0100951 uint32_t msp_stack_val = (uint32_t)msp + sizeof(struct tfm_state_context_t);
952
953 /* Equivalent to a call to __set_MSP() and then tfm_arch_trigger_exc_return
954 * with the exc_return value received as parameter in the handler
955 */
956 __ASM volatile (
957 "MSR msp, %0\n"
958 "MOV R0, %1\n"
959 "BX R0"
960 : : "r" (msp_stack_val), "r" (exc_return) : );
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800961}
962
963/* This SVC handler is called, if a thread mode execution environment is to
964 * be set up, to run an unprivileged IRQ handler
965 */
966uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
967{
968 struct tfm_state_context_t *svc_ctx =
969 (struct tfm_state_context_t *)svc_args;
970
971 enum tfm_status_e res;
972
973 if (excReturn & EXC_RETURN_STACK_PROCESS) {
974 /* FixMe: error severity TBD */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100975 SPMLOG_ERRMSG("Partition request SVC called with PSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800976 tfm_secure_api_error_handler();
977 }
978
979 res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
980 if (res != TFM_SUCCESS) {
981 /* The partition is in an invalid state (UNINIT or CLOSED), so none of
982 * its code can be run
983 */
984 /* FixMe: For now this case is handled with TF-M panic, however it would
985 * be possible to skip the execution of the interrupt handler, and
986 * resume the execution of the interrupted code.
987 */
988 tfm_secure_api_error_handler();
989 }
990 return EXC_RETURN_SECURE_FUNCTION;
991}
992
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800993/* This SVC handler is called if a deprivileged IRQ handler was executed, and
994 * the execution environment is to be set back for the privileged handler mode
995 */
996uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
997{
998 enum tfm_status_e res;
Ken Liue0af44c2020-07-25 22:51:30 +0800999 struct tfm_state_context_t *irq_svc_ctx;
1000
1001 /* Take into account the sealed stack*/
1002 irq_svc_args += 2;
1003
1004 irq_svc_ctx = (struct tfm_state_context_t *)irq_svc_args;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001005
1006 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
1007 /* Partition request SVC called with MSP active.
1008 * FixMe: error severity TBD
1009 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001010 SPMLOG_ERRMSG("Partition request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001011 tfm_secure_api_error_handler();
1012 }
1013
1014 res = tfm_return_from_partition_irq_handling(&lr);
1015 if (res != TFM_SUCCESS) {
1016 /* Unlock errors indicate ctx database corruption or unknown anomalies
1017 * Halt execution
1018 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001019 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001020 tfm_secure_api_error_handler();
1021 }
1022
1023 irq_svc_ctx->ra = lr;
1024
1025 return EXC_RETURN_SECURE_HANDLER;
1026}
1027
1028/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
1029/**
1030 * \brief Return the IRQ line number associated with a signal
1031 *
1032 * \param[in] partition_id The ID of the partition in which we look for the
1033 * signal
1034 * \param[in] signal The signal we do the query for
1035 *
1036 * \retval >=0 The IRQ line number associated with a signal in the partition
1037 * \retval <0 error
1038 */
Kevin Penga20b5af2021-01-11 11:20:52 +08001039static int32_t get_irq_line_for_signal(int32_t partition_id,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001040 psa_signal_t signal)
1041{
1042 size_t i;
1043
Ken Liu24dffb22021-02-10 11:03:58 +08001044 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
Kevin Peng410bee52021-01-13 16:27:17 +08001045 return -1;
1046 }
1047
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001048 for (i = 0; i < tfm_core_irq_signals_count; ++i) {
1049 if (tfm_core_irq_signals[i].partition_id == partition_id &&
1050 tfm_core_irq_signals[i].signal_value == signal) {
1051 return tfm_core_irq_signals[i].irq_line;
1052 }
1053 }
Kevin Penga20b5af2021-01-11 11:20:52 +08001054 return -1;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001055}
1056
1057void tfm_spm_enable_irq_handler(uint32_t *svc_args)
1058{
1059 struct tfm_state_context_t *svc_ctx =
1060 (struct tfm_state_context_t *)svc_args;
1061 psa_signal_t irq_signal = svc_ctx->r0;
1062 uint32_t running_partition_idx =
1063 tfm_spm_partition_get_running_partition_idx();
1064 uint32_t running_partition_id =
1065 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001066 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001067
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001068 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1069
1070 if (irq_line < 0) {
1071 /* FixMe: error severity TBD */
1072 tfm_secure_api_error_handler();
1073 }
1074
1075 tfm_spm_hal_enable_irq(irq_line);
1076}
1077
1078void tfm_spm_disable_irq_handler(uint32_t *svc_args)
1079{
1080 struct tfm_state_context_t *svc_ctx =
1081 (struct tfm_state_context_t *)svc_args;
1082 psa_signal_t irq_signal = svc_ctx->r0;
1083 uint32_t running_partition_idx =
1084 tfm_spm_partition_get_running_partition_idx();
1085 uint32_t running_partition_id =
1086 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001087 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001088
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001089 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1090
1091 if (irq_line < 0) {
1092 /* FixMe: error severity TBD */
1093 tfm_secure_api_error_handler();
1094 }
1095
1096 tfm_spm_hal_disable_irq(irq_line);
1097}
1098
1099void tfm_spm_psa_wait(uint32_t *svc_args)
1100{
1101 /* Look for partition that is ready for run */
1102 struct tfm_state_context_t *svc_ctx =
1103 (struct tfm_state_context_t *)svc_args;
1104 uint32_t running_partition_idx;
1105 const struct spm_partition_runtime_data_t *curr_part_data;
1106
1107 psa_signal_t signal_mask = svc_ctx->r0;
1108 uint32_t timeout = svc_ctx->r1;
1109
1110 /*
1111 * Timeout[30:0] are reserved for future use.
1112 * SPM must ignore the value of RES.
1113 */
1114 timeout &= PSA_TIMEOUT_MASK;
1115
1116 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1117 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1118
1119 if (timeout == PSA_BLOCK) {
1120 /* FIXME: Scheduling is not available in library model, and busy wait is
1121 * also not possible as this code is running in SVC context, and it
1122 * cannot be pre-empted by interrupts. So do nothing here for now
1123 */
1124 (void) signal_mask;
1125 }
1126
1127 svc_ctx->r0 = curr_part_data->signal_mask;
1128}
1129
1130void tfm_spm_psa_eoi(uint32_t *svc_args)
1131{
1132 struct tfm_state_context_t *svc_ctx =
1133 (struct tfm_state_context_t *)svc_args;
1134 psa_signal_t irq_signal = svc_ctx->r0;
1135 uint32_t signal_mask;
1136 uint32_t running_partition_idx;
1137 uint32_t running_partition_id;
1138 const struct spm_partition_runtime_data_t *curr_part_data;
Kevin Penga20b5af2021-01-11 11:20:52 +08001139 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001140
1141 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1142 running_partition_id =
1143 tfm_spm_partition_get_partition_id(running_partition_idx);
1144 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1145
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001146 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1147
1148 if (irq_line < 0) {
1149 /* FixMe: error severity TBD */
1150 tfm_secure_api_error_handler();
1151 }
1152
1153 tfm_spm_hal_clear_pending_irq(irq_line);
1154 tfm_spm_hal_enable_irq(irq_line);
1155
1156 signal_mask = curr_part_data->signal_mask & ~irq_signal;
1157 tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
1158}
Mingyang Sunda01a972019-07-12 17:32:59 +08001159
1160/*
1161 * This function is called when a secure partition causes an error.
1162 * In case of an error in the error handling, a non-zero value have to be
1163 * returned.
1164 */
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001165static void tfm_spm_partition_err_handler(const uint32_t idx, int32_t errcode)
Mingyang Sunda01a972019-07-12 17:32:59 +08001166{
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001167 (void)errcode;
Ken Liuf250b8b2019-12-27 16:31:24 +08001168
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001169 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_CLOSED);
Mingyang Sunda01a972019-07-12 17:32:59 +08001170}
1171
David Hu9804b6a2021-02-15 21:23:06 +08001172fih_int tfm_spm_partition_init(void)
Mingyang Sunda01a972019-07-12 17:32:59 +08001173{
1174 struct spm_partition_desc_t *part;
1175 struct tfm_sfn_req_s desc;
1176 int32_t args[4] = {0};
David Hu9804b6a2021-02-15 21:23:06 +08001177 fih_int fail_cnt = FIH_INT_INIT(0);
Mingyang Sunda01a972019-07-12 17:32:59 +08001178 uint32_t idx;
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001179 bool privileged;
Ken Liu172f1e32021-02-05 16:31:03 +08001180 const struct platform_data_t **platform_data_p;
David Hu9804b6a2021-02-15 21:23:06 +08001181#ifdef TFM_FIH_PROFILE_ON
1182 fih_int fih_rc = FIH_FAILURE;
1183#endif
Mingyang Sunda01a972019-07-12 17:32:59 +08001184
1185 /* Call the init function for each partition */
1186 for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
1187 part = &g_spm_partition_db.partitions[idx];
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001188 platform_data_p = part->platform_data_list;
1189 if (platform_data_p != NULL) {
1190 while ((*platform_data_p) != NULL) {
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001191 if (tfm_is_partition_privileged(idx)) {
1192 privileged = true;
1193 } else {
1194 privileged = false;
1195 }
David Hu9804b6a2021-02-15 21:23:06 +08001196#ifdef TFM_FIH_PROFILE_ON
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001197 FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc,
1198 privileged, *platform_data_p);
David Hu9804b6a2021-02-15 21:23:06 +08001199 if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
1200 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
1201 }
1202#else /* TFM_FIH_PROFILE_ON */
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001203 if (tfm_spm_hal_configure_default_isolation(privileged,
Edison Ai6be3df12020-02-14 22:14:33 +08001204 *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
1205 fail_cnt++;
1206 }
David Hu9804b6a2021-02-15 21:23:06 +08001207#endif /* TFM_FIH_PROFILE_ON */
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001208 ++platform_data_p;
1209 }
1210 }
Summer Qin423dbef2019-08-22 15:59:35 +08001211 if (part->static_data->partition_init == NULL) {
Mingyang Sunda01a972019-07-12 17:32:59 +08001212 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1213 tfm_spm_partition_set_caller_partition_idx(idx,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001214 SPM_INVALID_PARTITION_IDX);
Mingyang Sunda01a972019-07-12 17:32:59 +08001215 } else {
1216 int32_t res;
1217
1218 desc.args = args;
Summer Qin43c185d2019-10-10 15:44:42 +08001219 desc.ns_caller = false;
Summer Qin423dbef2019-08-22 15:59:35 +08001220 desc.sfn = (sfn_t)part->static_data->partition_init;
1221 desc.sp_id = part->static_data->partition_id;
Mingyang Sunda01a972019-07-12 17:32:59 +08001222 res = tfm_core_sfn_request(&desc);
1223 if (res == TFM_SUCCESS) {
1224 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1225 } else {
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001226 tfm_spm_partition_err_handler(idx, res);
David Hu9804b6a2021-02-15 21:23:06 +08001227 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
Mingyang Sunda01a972019-07-12 17:32:59 +08001228 }
1229 }
1230 }
1231
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001232 tfm_spm_secure_api_init_done();
Mingyang Sunda01a972019-07-12 17:32:59 +08001233
David Hu9804b6a2021-02-15 21:23:06 +08001234 fih_int_validate(fail_cnt);
1235 if (fih_eq(fail_cnt, fih_int_encode(0))) {
1236 FIH_RET(fih_int_encode(SPM_ERR_OK));
Mingyang Sunda01a972019-07-12 17:32:59 +08001237 }
David Hu9804b6a2021-02-15 21:23:06 +08001238
1239 FIH_RET(fih_int_encode(SPM_ERR_PARTITION_NOT_AVAILABLE));
Mingyang Sunda01a972019-07-12 17:32:59 +08001240}
1241
1242void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
1243{
1244 struct spm_partition_runtime_data_t *runtime_data =
1245 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1246 struct interrupted_ctx_stack_frame_t *stack_frame =
Edison Ai7aff9e82019-07-11 14:56:46 +08001247 (struct interrupted_ctx_stack_frame_t *)runtime_data->ctx_stack_ptr;
Mingyang Sunda01a972019-07-12 17:32:59 +08001248
1249 stack_frame->partition_state = runtime_data->partition_state;
Matt463ed582019-12-20 12:31:25 +08001250
1251 runtime_data->ctx_stack_ptr +=
1252 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
Mingyang Sunda01a972019-07-12 17:32:59 +08001253}
1254
1255void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
1256{
1257 struct spm_partition_runtime_data_t *runtime_data =
1258 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1259 struct interrupted_ctx_stack_frame_t *stack_frame;
1260
Matt463ed582019-12-20 12:31:25 +08001261 runtime_data->ctx_stack_ptr -=
1262 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
1263
Mingyang Sunda01a972019-07-12 17:32:59 +08001264 stack_frame = (struct interrupted_ctx_stack_frame_t *)
1265 runtime_data->ctx_stack_ptr;
1266 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1267 stack_frame->partition_state = 0;
Mingyang Sunda01a972019-07-12 17:32:59 +08001268}
1269
1270void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
1271{
1272 struct spm_partition_runtime_data_t *runtime_data =
1273 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1274 struct handler_ctx_stack_frame_t *stack_frame =
1275 (struct handler_ctx_stack_frame_t *)
1276 runtime_data->ctx_stack_ptr;
1277
1278 stack_frame->partition_state = runtime_data->partition_state;
1279 stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
1280
1281 runtime_data->ctx_stack_ptr +=
1282 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1283}
1284
1285void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
1286{
1287 struct spm_partition_runtime_data_t *runtime_data =
1288 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1289 struct handler_ctx_stack_frame_t *stack_frame;
1290
1291 runtime_data->ctx_stack_ptr -=
1292 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1293
1294 stack_frame = (struct handler_ctx_stack_frame_t *)
1295 runtime_data->ctx_stack_ptr;
1296
1297 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1298 stack_frame->partition_state = 0;
1299 tfm_spm_partition_set_caller_partition_idx(
1300 partition_idx, stack_frame->caller_partition_idx);
1301 stack_frame->caller_partition_idx = 0;
1302}
1303
Mingyang Sunda01a972019-07-12 17:32:59 +08001304void tfm_spm_partition_store_context(uint32_t partition_idx,
1305 uint32_t stack_ptr, uint32_t lr)
1306{
1307 g_spm_partition_db.partitions[partition_idx].
1308 runtime_data.stack_ptr = stack_ptr;
1309 g_spm_partition_db.partitions[partition_idx].
1310 runtime_data.lr = lr;
1311}
1312
1313const struct spm_partition_runtime_data_t *
1314 tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
1315{
1316 return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
1317}
1318
1319void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
1320{
1321 g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
1322 state;
1323 if (state == SPM_PARTITION_STATE_RUNNING ||
1324 state == SPM_PARTITION_STATE_HANDLING_IRQ) {
1325 g_spm_partition_db.running_partition_idx = partition_idx;
1326 }
1327}
1328
1329void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
1330 uint32_t caller_partition_idx)
1331{
1332 g_spm_partition_db.partitions[partition_idx].runtime_data.
1333 caller_partition_idx = caller_partition_idx;
1334}
1335
1336void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
1337 uint32_t signal_mask)
1338{
1339 g_spm_partition_db.partitions[partition_idx].runtime_data.
1340 signal_mask = signal_mask;
1341}
1342
1343void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
1344 int32_t caller_client_id)
1345{
1346 g_spm_partition_db.partitions[partition_idx].runtime_data.
1347 caller_client_id = caller_client_id;
1348}
1349
Mingyang Sunda01a972019-07-12 17:32:59 +08001350uint32_t tfm_spm_partition_get_running_partition_idx(void)
1351{
1352 return g_spm_partition_db.running_partition_idx;
1353}
1354
1355void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
1356{
1357 struct spm_partition_desc_t *partition =
1358 &(g_spm_partition_db.partitions[partition_idx]);
1359 int32_t i;
1360
1361 partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
Mingyang Sunda01a972019-07-12 17:32:59 +08001362 partition->runtime_data.iovec_args.in_len = 0;
1363 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1364 partition->runtime_data.iovec_args.in_vec[i].base = 0;
1365 partition->runtime_data.iovec_args.in_vec[i].len = 0;
1366 }
1367 partition->runtime_data.iovec_args.out_len = 0;
1368 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1369 partition->runtime_data.iovec_args.out_vec[i].base = 0;
1370 partition->runtime_data.iovec_args.out_vec[i].len = 0;
1371 }
1372 partition->runtime_data.orig_outvec = 0;
Summer Qin423dbef2019-08-22 15:59:35 +08001373}
Summer Qin830c5542020-02-14 13:44:20 +08001374
1375void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
1376{
1377 uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
1378 uint32_t running_partition_flags = 0;
1379 uint32_t running_partition_idx;
1380
1381 /* Check permissions on request type basis */
1382
1383 switch (svc_ctx->r0) {
1384 case TFM_SPM_REQUEST_RESET_VOTE:
1385 running_partition_idx =
1386 tfm_spm_partition_get_running_partition_idx();
1387 running_partition_flags = tfm_spm_partition_get_flags(
1388 running_partition_idx);
1389
1390 /* Currently only PSA Root of Trust services are allowed to make Reset
1391 * vote request
1392 */
1393 if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1394 *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1395 }
1396
1397 /* FixMe: this is a placeholder for checks to be performed before
1398 * allowing execution of reset
1399 */
1400 *res_ptr = (uint32_t)TFM_SUCCESS;
1401
1402 break;
1403 default:
1404 *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1405 }
1406}
Mingyang Sunbd7ceb52020-06-11 16:53:03 +08001407
1408enum spm_err_t tfm_spm_db_init(void)
1409{
1410 uint32_t i;
1411
1412 /* This function initialises partition db */
1413
1414 /* For the non secure Execution environment */
1415 tfm_nspm_configure_clients();
1416
1417 for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1418 g_spm_partition_db.partitions[i].runtime_data.partition_state =
1419 SPM_PARTITION_STATE_UNINIT;
1420 g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
1421 SPM_INVALID_PARTITION_IDX;
1422 g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
1423 TFM_INVALID_CLIENT_ID;
1424 g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
1425 ctx_stack_list[i];
1426 g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
1427 g_spm_partition_db.partitions[i].platform_data_list =
1428 platform_data_list_list[i];
1429 }
1430 g_spm_partition_db.is_init = 1;
1431
1432 return SPM_ERR_OK;
1433}