blob: 1c8edbc2f74ce4a3e81de4a809ee5970bf0138ca [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>
Ken Liu24dffb22021-02-10 11:03:58 +080011#include "bitops.h"
David Hu9804b6a2021-02-15 21:23:06 +080012#include "fih.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080013#include "tfm_nspm.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080014#include "tfm_api.h"
15#include "tfm_arch.h"
16#include "tfm_irq_list.h"
17#include "psa/service.h"
18#include "tfm_core_mem_check.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080019#include "tfm_peripherals_def.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080020#include "tfm_secure_api.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080021#include "tfm_spm_hal.h"
Soby Mathew960521a2020-09-29 12:48:50 +010022#include "tfm_core_trustzone.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080023#include "spm_func.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080024#include "region_defs.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080025#include "region.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080026#include "spm_partition_defs.h"
27#include "psa_manifest/pid.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080028#include "tfm/tfm_spm_services.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080029#include "tfm_spm_db_func.inc"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080030
David Hu5da82de2020-12-02 16:41:30 +080031/* Structure to temporarily save iovec parameters from PSA client */
32struct iovec_params_t {
33 psa_invec in_vec[PSA_MAX_IOVEC];
34 size_t in_len;
35 psa_outvec out_vec[PSA_MAX_IOVEC];
36 size_t out_len;
37
38 psa_outvec *orig_outvec;
39};
40
Mingyang Sunabb1aab2020-02-18 13:49:08 +080041#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
42#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
43
44#ifndef TFM_LVL
45#error TFM_LVL is not defined!
46#endif
47
Soby Mathew960521a2020-09-29 12:48:50 +010048#ifdef TFM_MULTI_CORE_TOPOLOGY
49#error Multi core is not supported by Function mode
50#endif
51
Mingyang Sunabb1aab2020-02-18 13:49:08 +080052REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Base, uint32_t);
53REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Limit, struct iovec_args_t)[];
54
Soby Mathew960521a2020-09-29 12:48:50 +010055static uint32_t *tfm_secure_stack_seal =
56 ((uint32_t *)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1]) - 2;
57
shejia0101a497c2021-04-21 10:04:07 +080058REGION_DECLARE_T(Image$$, ARM_LIB_STACK_SEAL, $$ZI$$Base, uint32_t)[];
Soby Mathew960521a2020-09-29 12:48:50 +010059
60/*
61 * Function to seal the psp stacks for Function model of TF-M.
62 */
63void tfm_spm_seal_psp_stacks(void)
64{
65 /*
66 * The top of TFM_SECURE_STACK is used for iovec parameters, we need to
67 * place the seal between iovec parameters and partition stack.
68 *
69 * Image$$TFM_SECURE_STACK$$ZI$$Limit-> +-------------------------+
70 * | |
71 * | iovec parameters for |
72 * | partition |
73 * (Image$$TFM_SECURE_STACK$$ZI$$Limit -| |
74 * sizeof(iovec_args_t)) -> +-------------------------+
75 * | Stack Seal |
76 * +-------------------------+
77 * | |
78 * | Partition stack |
79 * | |
80 * Image$$TFM_SECURE_STACK$$ZI$$Base-> +-------------------------+
81 */
82 *(tfm_secure_stack_seal) = TFM_STACK_SEAL_VALUE;
83 *(tfm_secure_stack_seal + 1) = TFM_STACK_SEAL_VALUE;
84
85 /*
86 * Seal the ARM_LIB_STACK by writing the seal value to the reserved
87 * region.
88 */
shejia0101a497c2021-04-21 10:04:07 +080089 uint32_t *arm_lib_stck_seal_base =
90 ((uint32_t *)&REGION_NAME(Image$$, ARM_LIB_STACK_SEAL, $$ZI$$Base)[-1]) - 2;
Soby Mathew960521a2020-09-29 12:48:50 +010091
92 *(arm_lib_stck_seal_base) = TFM_STACK_SEAL_VALUE;
93 *(arm_lib_stck_seal_base + 1) = TFM_STACK_SEAL_VALUE;
94}
95
Mingyang Sunabb1aab2020-02-18 13:49:08 +080096/*
97 * This is the "Big Lock" on the secure side, to guarantee single entry
98 * to SPE
99 */
Summer Qin5fdcf632020-06-22 16:49:24 +0800100static int32_t tfm_secure_lock;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800101static int32_t tfm_secure_api_initializing = 1;
Mingyang Sunda01a972019-07-12 17:32:59 +0800102
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800103static uint32_t *prepare_partition_iovec_ctx(
104 const struct tfm_state_context_t *svc_ctx,
105 const struct tfm_sfn_req_s *desc_ptr,
106 const struct iovec_args_t *iovec_args,
107 uint32_t *dst)
108{
109 /* XPSR = as was when called, but make sure it's thread mode */
110 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00U;
111 /* ReturnAddress = resume veneer in new context */
112 *(--dst) = svc_ctx->ra;
113 /* LR = sfn address */
114 *(--dst) = (uint32_t)desc_ptr->sfn;
115 /* R12 = don't care */
116 *(--dst) = 0U;
117
118 /* R0-R3 = sfn arguments */
119 *(--dst) = iovec_args->out_len;
120 *(--dst) = (uint32_t)iovec_args->out_vec;
121 *(--dst) = iovec_args->in_len;
122 *(--dst) = (uint32_t)iovec_args->in_vec;
123
124 return dst;
125}
126
127/**
128 * \brief Create a stack frame that sets the execution environment to thread
129 * mode on exception return.
130 *
131 * \param[in] svc_ctx The stacked SVC context
132 * \param[in] unpriv_handler The unprivileged IRQ handler to be called
133 * \param[in] dst A pointer where the context is to be created. (the
134 * pointer is considered to be a stack pointer, and
135 * the frame is created below it)
136 *
137 * \return A pointer pointing at the created stack frame.
138 */
139static int32_t *prepare_partition_irq_ctx(
140 const struct tfm_state_context_t *svc_ctx,
141 sfn_t unpriv_handler,
142 int32_t *dst)
143{
144 int i;
145
146 /* XPSR = as was when called, but make sure it's thread mode */
147 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00;
148 /* ReturnAddress = resume to the privileged handler code, but execute it
149 * unprivileged.
150 */
151 *(--dst) = svc_ctx->ra;
152 /* LR = start address */
153 *(--dst) = (int32_t)unpriv_handler;
154
155 /* R12, R0-R3 unused arguments */
156 for (i = 0; i < 5; ++i) {
157 *(--dst) = 0;
158 }
159
160 return dst;
161}
162
163static void restore_caller_ctx(const struct tfm_state_context_t *svc_ctx,
164 struct tfm_state_context_t *target_ctx)
165{
166 /* ReturnAddress = resume veneer after second SVC */
167 target_ctx->ra = svc_ctx->ra;
168
169 /* R0 = function return value */
170 target_ctx->r0 = svc_ctx->r0;
171
172 return;
173}
174
175/**
176 * \brief Check whether the iovec parameters are valid, and the memory ranges
177 * are in the possession of the calling partition.
178 *
David Hu5da82de2020-12-02 16:41:30 +0800179 * \param[in] desc_ptr The secure function request descriptor
180 * \param[out] iovec_ptr The local buffer to store iovec arguments
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800181 *
182 * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
183 * otherwise as in /ref tfm_status_e
184 */
185static enum tfm_status_e tfm_core_check_sfn_parameters(
David Hu5da82de2020-12-02 16:41:30 +0800186 const struct tfm_sfn_req_s *desc_ptr,
187 struct iovec_params_t *iovec_ptr)
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800188{
189 struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
190 size_t in_len;
191 struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
192 size_t out_len;
193 uint32_t i;
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800194 uint32_t privileged_mode = TFM_PARTITION_UNPRIVILEGED_MODE;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800195
196 if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
197 return TFM_ERROR_INVALID_PARAMETER;
198 }
199
200 in_len = (size_t)(desc_ptr->args[1]);
201 out_len = (size_t)(desc_ptr->args[3]);
202
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800203 /*
204 * Get caller's privileged mode:
205 * The privileged mode of NS Secure Service caller will be decided by the
206 * tfm_core_has_xxx_access_to_region functions.
207 * Secure caller can be only privileged mode because the whole SPE is
208 * running under privileged mode
209 */
210 if (!desc_ptr->ns_caller) {
211 privileged_mode = TFM_PARTITION_PRIVILEGED_MODE;
212 }
213
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800214 /* The number of vectors are within range. Extra checks to avoid overflow */
215 if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
216 (in_len + out_len > PSA_MAX_IOVEC)) {
217 return TFM_ERROR_INVALID_PARAMETER;
218 }
219
220 /* Check whether the caller partition has at write access to the iovec
221 * structures themselves. Use the TT instruction for this.
222 */
223 if (in_len > 0) {
224 if ((in_vec == NULL) ||
225 (tfm_core_has_write_access_to_region(in_vec,
226 sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800227 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800228 return TFM_ERROR_INVALID_PARAMETER;
229 }
230 } else {
231 if (in_vec != NULL) {
232 return TFM_ERROR_INVALID_PARAMETER;
233 }
234 }
235 if (out_len > 0) {
236 if ((out_vec == NULL) ||
237 (tfm_core_has_write_access_to_region(out_vec,
238 sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800239 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800240 return TFM_ERROR_INVALID_PARAMETER;
241 }
242 } else {
243 if (out_vec != NULL) {
244 return TFM_ERROR_INVALID_PARAMETER;
245 }
246 }
247
David Hu5da82de2020-12-02 16:41:30 +0800248 /* Copy iovec parameters into a local buffer before validating them */
249 iovec_ptr->in_len = in_len;
250 for (i = 0; i < in_len; ++i) {
251 iovec_ptr->in_vec[i].base = in_vec[i].base;
252 iovec_ptr->in_vec[i].len = in_vec[i].len;
253 }
254 iovec_ptr->out_len = out_len;
255 for (i = 0; i < out_len; ++i) {
256 iovec_ptr->out_vec[i].base = out_vec[i].base;
257 iovec_ptr->out_vec[i].len = out_vec[i].len;
258 }
259 iovec_ptr->orig_outvec = out_vec;
260
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800261 /* Check whether the caller partition has access to the data inside the
262 * iovecs
263 */
264 for (i = 0; i < in_len; ++i) {
David Hu5da82de2020-12-02 16:41:30 +0800265 if (iovec_ptr->in_vec[i].len > 0) {
266 if ((iovec_ptr->in_vec[i].base == NULL) ||
267 (tfm_core_has_read_access_to_region(iovec_ptr->in_vec[i].base,
268 iovec_ptr->in_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800269 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800270 return TFM_ERROR_INVALID_PARAMETER;
271 }
272 }
273 }
274 for (i = 0; i < out_len; ++i) {
David Hu5da82de2020-12-02 16:41:30 +0800275 if (iovec_ptr->out_vec[i].len > 0) {
276 if ((iovec_ptr->out_vec[i].base == NULL) ||
277 (tfm_core_has_write_access_to_region(iovec_ptr->out_vec[i].base,
278 iovec_ptr->out_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800279 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800280 return TFM_ERROR_INVALID_PARAMETER;
281 }
282 }
283 }
284
285 return TFM_SUCCESS;
286}
287
288static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
289 const struct iovec_args_t *source)
290{
291 size_t i;
292
293 /* The vectors have been sanity checked already, and since then the
294 * interrupts have been kept disabled. So we can be sure that the
295 * vectors haven't been tampered with since the check. So it is safe to pass
296 * it to the called partition.
297 */
298
299 target->in_len = source->in_len;
300 for (i = 0; i < source->in_len; ++i) {
301 target->in_vec[i].base = source->in_vec[i].base;
302 target->in_vec[i].len = source->in_vec[i].len;
303 }
304 target->out_len = source->out_len;
305 for (i = 0; i < source->out_len; ++i) {
306 target->out_vec[i].base = source->out_vec[i].base;
307 target->out_vec[i].len = source->out_vec[i].len;
308 }
309}
310
311static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
312{
313 int i;
314
315 args->in_len = 0;
316 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
317 args->in_vec[i].base = NULL;
318 args->in_vec[i].len = 0;
319 }
320 args->out_len = 0;
321 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
322 args->out_vec[i].base = NULL;
323 args->out_vec[i].len = 0;
324 }
325}
326
327/**
328 * \brief Check whether the partitions for the secure function call are in a
329 * proper state.
330 *
331 * \param[in] curr_partition_state State of the partition to be called
332 * \param[in] caller_partition_state State of the caller partition
333 *
334 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
335 */
336static enum tfm_status_e check_partition_state(uint32_t curr_partition_state,
337 uint32_t caller_partition_state)
338{
339 if (caller_partition_state != SPM_PARTITION_STATE_RUNNING) {
340 /* Calling partition from non-running state (e.g. during handling IRQ)
341 * is not allowed.
342 */
343 return TFM_ERROR_INVALID_EXC_MODE;
344 }
345
346 if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
347 curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
348 curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
349 curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
350 /* Active partitions cannot be called! */
351 return TFM_ERROR_PARTITION_NON_REENTRANT;
352 } else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
353 /* The partition to be called is not in a proper state */
354 return TFM_SECURE_LOCK_FAILED;
355 }
356 return TFM_SUCCESS;
357}
358
359/**
360 * \brief Check whether the partitions for the secure function call of irq are
361 * in a proper state.
362 *
363 * \param[in] called_partition_state State of the partition to be called
364 *
365 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
366 */
367static enum tfm_status_e check_irq_partition_state(
368 uint32_t called_partition_state)
369{
370 if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
371 called_partition_state == SPM_PARTITION_STATE_RUNNING ||
372 called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
373 called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
374 called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
375 return TFM_SUCCESS;
376 }
377 return TFM_SECURE_LOCK_FAILED;
378}
379
380/**
381 * \brief Calculate the address where the iovec parameters are to be saved for
382 * the called partition.
383 *
384 * \param[in] partition_idx The index of the partition to be called.
385 *
386 * \return The address where the iovec parameters should be saved.
387 */
388static struct iovec_args_t *get_iovec_args_stack_address(uint32_t partition_idx)
389{
390 /* Save the iovecs on the common stack. */
TTornblom99f0be22019-12-17 16:22:38 +0100391 return &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800392}
393
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800394/**
395 * \brief Returns the index of the partition with the given partition ID.
396 *
397 * \param[in] partition_id Partition id
398 *
399 * \return the partition idx if partition_id is valid,
400 * \ref SPM_INVALID_PARTITION_IDX othervise
401 */
402static uint32_t get_partition_idx(uint32_t partition_id)
403{
404 uint32_t i;
405
406 if (partition_id == INVALID_PARTITION_ID) {
407 return SPM_INVALID_PARTITION_IDX;
408 }
409
410 for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
411 if (g_spm_partition_db.partitions[i].static_data->partition_id ==
412 partition_id) {
413 return i;
414 }
415 }
416 return SPM_INVALID_PARTITION_IDX;
417}
418
419/**
David Hu5da82de2020-12-02 16:41:30 +0800420 * \brief Set the iovec parameters for the partition
421 *
422 * \param[in] partition_idx Partition index
423 * \param[in] iovec_ptr The arguments of the secure function
424 *
425 * \return Error code \ref spm_err_t
426 *
427 * \note This function doesn't check if partition_idx is valid.
428 * \note This function assumes that the iovecs that are passed in iovec_ptr are
429 * valid, and does no sanity check on them at all.
430 */
431static enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
432 const struct iovec_params_t *iovec_ptr)
433{
434 struct spm_partition_runtime_data_t *runtime_data =
435 &g_spm_partition_db.partitions[partition_idx].runtime_data;
436 size_t i;
437
438 if ((iovec_ptr->in_len < 0) || (iovec_ptr->out_len < 0)) {
439 return SPM_ERR_INVALID_PARAMETER;
440 }
441
442 runtime_data->iovec_args.in_len = iovec_ptr->in_len;
443 for (i = 0U; i < runtime_data->iovec_args.in_len; ++i) {
444 runtime_data->iovec_args.in_vec[i].base = iovec_ptr->in_vec[i].base;
445 runtime_data->iovec_args.in_vec[i].len = iovec_ptr->in_vec[i].len;
446 }
447 runtime_data->iovec_args.out_len = iovec_ptr->out_len;
448 for (i = 0U; i < runtime_data->iovec_args.out_len; ++i) {
449 runtime_data->iovec_args.out_vec[i].base = iovec_ptr->out_vec[i].base;
450 runtime_data->iovec_args.out_vec[i].len = iovec_ptr->out_vec[i].len;
451 }
452 runtime_data->orig_outvec = iovec_ptr->orig_outvec;
453
454 return SPM_ERR_OK;
455}
456
457/**
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800458 * \brief Get the flags associated with a partition
459 *
460 * \param[in] partition_idx Partition index
461 *
462 * \return Flags associated with the partition
463 *
464 * \note This function doesn't check if partition_idx is valid.
465 */
466static uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
467{
468 return g_spm_partition_db.partitions[partition_idx].static_data->
469 partition_flags;
470}
471
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800472static enum tfm_status_e tfm_start_partition(
David Hu5da82de2020-12-02 16:41:30 +0800473 const struct tfm_sfn_req_s *desc_ptr,
474 const struct iovec_params_t *iovec_ptr,
475 uint32_t excReturn)
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800476{
Xinyu Zhang3a453242021-04-16 17:57:09 +0800477 register uint32_t partition_idx;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800478 enum tfm_status_e res;
479 uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
480 const struct spm_partition_runtime_data_t *curr_part_data;
481 const struct spm_partition_runtime_data_t *caller_part_data;
482 uint32_t caller_flags;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800483 uint32_t psp;
484 uint32_t partition_psp, partition_psplim;
485 uint32_t partition_state;
486 uint32_t caller_partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800487 struct tfm_state_context_t *svc_ctx;
488 uint32_t caller_partition_id;
489 int32_t client_id;
490 struct iovec_args_t *iovec_args;
491
492 psp = __get_PSP();
493 svc_ctx = (struct tfm_state_context_t *)psp;
494 caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
495
496 /* Check partition state consistency */
497 if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
498 != (!desc_ptr->ns_caller)) {
499 /* Partition state inconsistency detected */
500 return TFM_SECURE_LOCK_FAILED;
501 }
502
503 partition_idx = get_partition_idx(desc_ptr->sp_id);
504
505 curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
506 caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
507 partition_state = curr_part_data->partition_state;
508 caller_partition_state = caller_part_data->partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800509 caller_partition_id = tfm_spm_partition_get_partition_id(
510 caller_partition_idx);
511
512 if (!tfm_secure_api_initializing) {
513 res = check_partition_state(partition_state, caller_partition_state);
514 if (res != TFM_SUCCESS) {
515 return res;
516 }
517 }
518
519 /* Prepare switch to shared secure partition stack */
520 /* In case the call is coming from the non-secure world, we save the iovecs
Soby Mathew960521a2020-09-29 12:48:50 +0100521 * on the stop of the stack. Also the stack seal is present below this region.
522 * So the memory area, that can actually be used as stack by the partitions
523 * starts at a lower address.
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800524 */
Soby Mathew960521a2020-09-29 12:48:50 +0100525 partition_psp = (uint32_t) tfm_secure_stack_seal;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800526 partition_psplim =
527 (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
528
529 /* Store the context for the partition call */
530 tfm_spm_partition_set_caller_partition_idx(partition_idx,
531 caller_partition_idx);
532 tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
533
534 if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
535 tfm_spm_partition_set_caller_client_id(partition_idx,
536 caller_partition_id);
537 } else {
538 client_id = tfm_nspm_get_current_client_id();
539 if (client_id >= 0) {
540 return TFM_SECURE_LOCK_FAILED;
541 }
542 tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
543 }
544
545 /* In level one, only switch context and return from exception if in
546 * handler mode
547 */
548 if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
David Hu5da82de2020-12-02 16:41:30 +0800549 if (tfm_spm_partition_set_iovec(partition_idx, iovec_ptr) !=
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800550 SPM_ERR_OK) {
551 return TFM_ERROR_GENERIC;
552 }
553 iovec_args = get_iovec_args_stack_address(partition_idx);
554 tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
555
556 /* Prepare the partition context, update stack ptr */
557 psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
558 iovec_args,
559 (uint32_t *)partition_psp);
560 __set_PSP(psp);
561 tfm_arch_set_psplim(partition_psplim);
562 }
563
564 tfm_spm_partition_set_state(caller_partition_idx,
565 SPM_PARTITION_STATE_BLOCKED);
566 tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
567 tfm_secure_lock++;
568
569 return TFM_SUCCESS;
570}
571
572static enum tfm_status_e tfm_start_partition_for_irq_handling(
573 uint32_t excReturn,
574 struct tfm_state_context_t *svc_ctx)
575{
576 uint32_t handler_partition_id = svc_ctx->r0;
577 sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
578 uint32_t irq_signal = svc_ctx->r2;
Kevin Penga20b5af2021-01-11 11:20:52 +0800579 uint32_t irq_line = svc_ctx->r3;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800580 enum tfm_status_e res;
581 uint32_t psp = __get_PSP();
582 uint32_t handler_partition_psp;
583 uint32_t handler_partition_state;
584 uint32_t interrupted_partition_idx =
585 tfm_spm_partition_get_running_partition_idx();
586 const struct spm_partition_runtime_data_t *handler_part_data;
587 uint32_t handler_partition_idx;
588
589 handler_partition_idx = get_partition_idx(handler_partition_id);
590 handler_part_data = tfm_spm_partition_get_runtime_data(
591 handler_partition_idx);
592 handler_partition_state = handler_part_data->partition_state;
593
594 res = check_irq_partition_state(handler_partition_state);
595 if (res != TFM_SUCCESS) {
596 return res;
597 }
598
599 /* set mask for the partition */
600 tfm_spm_partition_set_signal_mask(
601 handler_partition_idx,
602 handler_part_data->signal_mask | irq_signal);
603
604 tfm_spm_hal_disable_irq(irq_line);
605
606 /* save the current context of the interrupted partition */
607 tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
608
609 handler_partition_psp = psp;
610
611 /* save the current context of the handler partition */
612 tfm_spm_partition_push_handler_ctx(handler_partition_idx);
613
614 /* Store caller for the partition */
615 tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
616 interrupted_partition_idx);
617
618 psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
619 (int32_t *)handler_partition_psp);
620 __set_PSP(psp);
621
622 tfm_spm_partition_set_state(interrupted_partition_idx,
623 SPM_PARTITION_STATE_SUSPENDED);
624 tfm_spm_partition_set_state(handler_partition_idx,
625 SPM_PARTITION_STATE_HANDLING_IRQ);
626
627 return TFM_SUCCESS;
628}
629
630static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
631{
632 uint32_t current_partition_idx =
633 tfm_spm_partition_get_running_partition_idx();
634 const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800635 uint32_t return_partition_idx;
636 uint32_t return_partition_flags;
637 uint32_t psp = __get_PSP();
638 size_t i;
639 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
640 struct iovec_args_t *iovec_args;
641
642 if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
643 return TFM_SECURE_UNLOCK_FAILED;
644 }
645
646 curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
647 return_partition_idx = curr_part_data->caller_partition_idx;
648
649 if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
650 return TFM_SECURE_UNLOCK_FAILED;
651 }
652
653 ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
654
655 return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800656
657 tfm_secure_lock--;
658
659 if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
660 (tfm_secure_api_initializing)) {
661 /* In TFM level 1 context restore is only done when
662 * returning to NS or after initialization
663 */
664 /* Restore caller context */
665 restore_caller_ctx(svc_ctx,
666 (struct tfm_state_context_t *)ret_part_data->stack_ptr);
667 *excReturn = ret_part_data->lr;
668 __set_PSP(ret_part_data->stack_ptr);
TTornblom99f0be22019-12-17 16:22:38 +0100669 REGION_DECLARE_T(Image$$, ARM_LIB_STACK, $$ZI$$Base, uint32_t)[];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800670 uint32_t psp_stack_bottom =
671 (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
672 tfm_arch_set_psplim(psp_stack_bottom);
673
TTornblom99f0be22019-12-17 16:22:38 +0100674 iovec_args = &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800675
676 for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
677 curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
678 }
679 tfm_clear_iovec_parameters(iovec_args);
680 }
681
682 tfm_spm_partition_cleanup_context(current_partition_idx);
683
684 tfm_spm_partition_set_state(current_partition_idx,
685 SPM_PARTITION_STATE_IDLE);
686 tfm_spm_partition_set_state(return_partition_idx,
687 SPM_PARTITION_STATE_RUNNING);
688
689 return TFM_SUCCESS;
690}
691
692static enum tfm_status_e tfm_return_from_partition_irq_handling(
693 uint32_t *excReturn)
694{
695 uint32_t handler_partition_idx =
696 tfm_spm_partition_get_running_partition_idx();
697 const struct spm_partition_runtime_data_t *handler_part_data;
698 uint32_t interrupted_partition_idx;
699 uint32_t psp = __get_PSP();
700 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
701
702 if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
703 return TFM_SECURE_UNLOCK_FAILED;
704 }
705
706 handler_part_data = tfm_spm_partition_get_runtime_data(
707 handler_partition_idx);
708 interrupted_partition_idx = handler_part_data->caller_partition_idx;
709
710 if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
711 return TFM_SECURE_UNLOCK_FAILED;
712 }
713
714 /* For level 1, modify PSP, so that the SVC stack frame disappears,
715 * and return to the privileged handler using the stack frame still on the
716 * MSP stack.
717 */
718 *excReturn = svc_ctx->ra;
719 psp += sizeof(struct tfm_state_context_t);
720
721 tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
722 tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
723
724 __set_PSP(psp);
725
726 return TFM_SUCCESS;
727}
728
729static enum tfm_status_e tfm_check_sfn_req_integrity(
730 const struct tfm_sfn_req_s *desc_ptr)
731{
732 if ((desc_ptr == NULL) ||
733 (desc_ptr->sp_id == 0) ||
734 (desc_ptr->sfn == NULL)) {
735 /* invalid parameter */
736 return TFM_ERROR_INVALID_PARAMETER;
737 }
738 return TFM_SUCCESS;
739}
740
741static enum tfm_status_e tfm_core_check_sfn_req_rules(
742 const struct tfm_sfn_req_s *desc_ptr)
743{
744 /* Check partition idx validity */
745 if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
746 return TFM_ERROR_NO_ACTIVE_PARTITION;
747 }
748
749 if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
750 /* Secure domain is already locked!
751 * This should only happen if caller is secure partition!
752 */
753 /* This scenario is a potential security breach.
754 * Error is handled in caller.
755 */
756 return TFM_ERROR_SECURE_DOMAIN_LOCKED;
757 }
758
759 if (tfm_secure_api_initializing) {
760 int32_t id =
761 tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
762
763 if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
764 /* Invalid request during system initialization */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100765 SPMLOG_ERRMSG("Invalid service request during initialization!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800766 return TFM_ERROR_NOT_INITIALIZED;
767 }
768 }
769
770 return TFM_SUCCESS;
771}
772
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800773uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
774{
775 return g_spm_partition_db.partitions[partition_idx].static_data->
776 partition_id;
777}
778
779uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
780{
781 if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
782 return TFM_PARTITION_PRIVILEGED_MODE;
783 } else {
784 return TFM_PARTITION_UNPRIVILEGED_MODE;
785 }
786}
787
788bool tfm_is_partition_privileged(uint32_t partition_idx)
789{
790 uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
791
792 return tfm_spm_partition_get_privileged_mode(flags) ==
793 TFM_PARTITION_PRIVILEGED_MODE;
794}
795
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800796void tfm_spm_secure_api_init_done(void)
797{
798 tfm_secure_api_initializing = 0;
799}
800
801enum tfm_status_e tfm_spm_sfn_request_handler(
802 struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
803{
804 enum tfm_status_e res;
shejia0101a497c2021-04-21 10:04:07 +0800805 struct iovec_params_t iovecs = {0};
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800806
807 res = tfm_check_sfn_req_integrity(desc_ptr);
808 if (res != TFM_SUCCESS) {
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100809 SPMLOG_ERRMSG("Invalid service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800810 tfm_secure_api_error_handler();
811 }
812
813 __disable_irq();
814
815 desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
816
David Hu5da82de2020-12-02 16:41:30 +0800817 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800818 if (res != TFM_SUCCESS) {
819 /* The sanity check of iovecs failed. */
820 __enable_irq();
821 tfm_secure_api_error_handler();
822 }
823
824 res = tfm_core_check_sfn_req_rules(desc_ptr);
825 if (res != TFM_SUCCESS) {
826 /* FixMe: error compartmentalization TBD */
827 tfm_spm_partition_set_state(
828 desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
829 __enable_irq();
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100830 SPMLOG_ERRMSG("Unauthorized service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800831 tfm_secure_api_error_handler();
832 }
833
David Hu5da82de2020-12-02 16:41:30 +0800834 res = tfm_start_partition(desc_ptr, &iovecs, excReturn);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800835 if (res != TFM_SUCCESS) {
836 /* FixMe: consider possible fault scenarios */
837 __enable_irq();
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100838 SPMLOG_ERRMSG("Failed to process service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800839 tfm_secure_api_error_handler();
840 }
841
842 __enable_irq();
843
844 return res;
845}
846
847int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
848{
849 enum tfm_status_e res;
850 int32_t *args;
851 int32_t retVal;
David Hu5da82de2020-12-02 16:41:30 +0800852 struct iovec_params_t iovecs;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800853
David Hu5da82de2020-12-02 16:41:30 +0800854 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800855 if (res != TFM_SUCCESS) {
856 /* The sanity check of iovecs failed. */
857 return (int32_t)res;
858 }
859
860 /* No excReturn value is needed as no exception handling is used */
861 res = tfm_spm_sfn_request_handler(desc_ptr, 0);
862
863 if (res != TFM_SUCCESS) {
864 tfm_secure_api_error_handler();
865 }
866
867 /* Secure partition to secure partition call in TFM level 1 */
868 args = desc_ptr->args;
869 retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
870
871 /* return handler should restore original exc_return value... */
872 res = tfm_return_from_partition(NULL);
873 if (res == TFM_SUCCESS) {
874 /* If unlock successful, pass SS return value to caller */
875 return retVal;
876 } else {
877 /* Unlock errors indicate ctx database corruption or unknown
878 * anomalies. Halt execution
879 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100880 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800881 tfm_secure_api_error_handler();
882 }
883 return (int32_t)res;
884}
885
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800886int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
887 void *start_addr,
888 size_t len,
889 uint32_t alignment)
890{
891 uintptr_t start_addr_value = (uintptr_t)start_addr;
892 uintptr_t end_addr_value = (uintptr_t)start_addr + len;
893 uintptr_t alignment_mask;
894
895 alignment_mask = (((uintptr_t)1) << alignment) - 1;
896
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100897 /* Check pointer alignment and protect against overflow and zero len */
898 if (!(start_addr_value & alignment_mask) &&
899 (end_addr_value > start_addr_value)) {
900 /* Check that the range is in S_DATA */
901 if ((start_addr_value >= S_DATA_START) &&
902 (end_addr_value <= (S_DATA_START + S_DATA_SIZE))) {
903 return TFM_SUCCESS;
904 } else {
905 return TFM_ERROR_NOT_IN_RANGE;
906 }
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800907 }
908
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100909 return TFM_ERROR_INVALID_PARAMETER;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800910}
911
912void tfm_spm_get_caller_client_id_handler(uint32_t *svc_args)
913{
914 uintptr_t result_ptr_value = svc_args[0];
915 uint32_t running_partition_idx =
916 tfm_spm_partition_get_running_partition_idx();
917 const uint32_t running_partition_flags =
918 tfm_spm_partition_get_flags(running_partition_idx);
919 const struct spm_partition_runtime_data_t *curr_part_data =
920 tfm_spm_partition_get_runtime_data(running_partition_idx);
921 int res = 0;
922
923 if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
924 curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
925 curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
926 /* This handler shouldn't be called from outside partition context.
927 * Also if the current partition is handling IRQ, the caller partition
928 * index might not be valid;
929 * Partitions are only allowed to run while S domain is locked.
930 */
931 svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
932 return;
933 }
934
935 /* Make sure that the output pointer points to a memory area that is owned
936 * by the partition
937 */
938 res = tfm_spm_check_buffer_access(running_partition_idx,
939 (void *)result_ptr_value,
940 sizeof(curr_part_data->caller_client_id),
941 2);
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100942 if (res != TFM_SUCCESS) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800943 /* Not in accessible range, return error */
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100944 svc_args[0] = (uint32_t)res;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800945 return;
946 }
947
948 *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
949
950 /* Store return value in r0 */
951 svc_args[0] = (uint32_t)TFM_SUCCESS;
952}
953
954/* This SVC handler is called if veneer is running in thread mode */
955uint32_t tfm_spm_partition_request_svc_handler(
956 const uint32_t *svc_ctx, uint32_t excReturn)
957{
958 struct tfm_sfn_req_s *desc_ptr;
959
960 if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
961 /* Service request SVC called with MSP active.
962 * Either invalid configuration for Thread mode or SVC called
963 * from Handler mode, which is not supported.
964 * FixMe: error severity TBD
965 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100966 SPMLOG_ERRMSG("Service request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800967 tfm_secure_api_error_handler();
968 }
969
970 desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
971
972 if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
973 tfm_secure_api_error_handler();
974 }
975
976 return EXC_RETURN_SECURE_FUNCTION;
977}
978
979/* This SVC handler is called, if a thread mode execution environment is to
980 * be set up, to run an unprivileged IRQ handler
981 */
982uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
983{
984 struct tfm_state_context_t *svc_ctx =
985 (struct tfm_state_context_t *)svc_args;
986
987 enum tfm_status_e res;
988
989 if (excReturn & EXC_RETURN_STACK_PROCESS) {
990 /* FixMe: error severity TBD */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100991 SPMLOG_ERRMSG("Partition request SVC called with PSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800992 tfm_secure_api_error_handler();
993 }
994
995 res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
996 if (res != TFM_SUCCESS) {
997 /* The partition is in an invalid state (UNINIT or CLOSED), so none of
998 * its code can be run
999 */
1000 /* FixMe: For now this case is handled with TF-M panic, however it would
1001 * be possible to skip the execution of the interrupt handler, and
1002 * resume the execution of the interrupted code.
1003 */
1004 tfm_secure_api_error_handler();
1005 }
1006 return EXC_RETURN_SECURE_FUNCTION;
1007}
1008
1009/* This SVC handler is called when sfn returns */
1010uint32_t tfm_spm_partition_return_handler(uint32_t lr)
1011{
1012 enum tfm_status_e res;
1013
1014 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
1015 /* Partition return SVC called with MSP active.
1016 * This should not happen!
1017 */
1018 ERROR_MSG("Partition return SVC called with MSP active!");
1019 tfm_secure_api_error_handler();
1020 }
1021
1022 res = tfm_return_from_partition(&lr);
1023 if (res != TFM_SUCCESS) {
1024 /* Unlock errors indicate ctx database corruption or unknown anomalies
1025 * Halt execution
1026 */
1027 ERROR_MSG("Secure API error during unlock!");
1028 tfm_secure_api_error_handler();
1029 }
1030
1031 return lr;
1032}
1033
1034/* This SVC handler is called if a deprivileged IRQ handler was executed, and
1035 * the execution environment is to be set back for the privileged handler mode
1036 */
1037uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
1038{
1039 enum tfm_status_e res;
Ken Liue0af44c2020-07-25 22:51:30 +08001040 struct tfm_state_context_t *irq_svc_ctx;
1041
1042 /* Take into account the sealed stack*/
1043 irq_svc_args += 2;
1044
1045 irq_svc_ctx = (struct tfm_state_context_t *)irq_svc_args;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001046
1047 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
1048 /* Partition request SVC called with MSP active.
1049 * FixMe: error severity TBD
1050 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001051 SPMLOG_ERRMSG("Partition request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001052 tfm_secure_api_error_handler();
1053 }
1054
1055 res = tfm_return_from_partition_irq_handling(&lr);
1056 if (res != TFM_SUCCESS) {
1057 /* Unlock errors indicate ctx database corruption or unknown anomalies
1058 * Halt execution
1059 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001060 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001061 tfm_secure_api_error_handler();
1062 }
1063
1064 irq_svc_ctx->ra = lr;
1065
1066 return EXC_RETURN_SECURE_HANDLER;
1067}
1068
1069/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
1070/**
1071 * \brief Return the IRQ line number associated with a signal
1072 *
1073 * \param[in] partition_id The ID of the partition in which we look for the
1074 * signal
1075 * \param[in] signal The signal we do the query for
1076 *
1077 * \retval >=0 The IRQ line number associated with a signal in the partition
1078 * \retval <0 error
1079 */
Kevin Penga20b5af2021-01-11 11:20:52 +08001080static int32_t get_irq_line_for_signal(int32_t partition_id,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001081 psa_signal_t signal)
1082{
1083 size_t i;
1084
Ken Liu24dffb22021-02-10 11:03:58 +08001085 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
Kevin Peng410bee52021-01-13 16:27:17 +08001086 return -1;
1087 }
1088
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001089 for (i = 0; i < tfm_core_irq_signals_count; ++i) {
1090 if (tfm_core_irq_signals[i].partition_id == partition_id &&
1091 tfm_core_irq_signals[i].signal_value == signal) {
1092 return tfm_core_irq_signals[i].irq_line;
1093 }
1094 }
Kevin Penga20b5af2021-01-11 11:20:52 +08001095 return -1;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001096}
1097
1098void tfm_spm_enable_irq_handler(uint32_t *svc_args)
1099{
1100 struct tfm_state_context_t *svc_ctx =
1101 (struct tfm_state_context_t *)svc_args;
1102 psa_signal_t irq_signal = svc_ctx->r0;
1103 uint32_t running_partition_idx =
1104 tfm_spm_partition_get_running_partition_idx();
1105 uint32_t running_partition_id =
1106 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001107 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001108
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001109 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1110
1111 if (irq_line < 0) {
1112 /* FixMe: error severity TBD */
1113 tfm_secure_api_error_handler();
1114 }
1115
1116 tfm_spm_hal_enable_irq(irq_line);
1117}
1118
1119void tfm_spm_disable_irq_handler(uint32_t *svc_args)
1120{
1121 struct tfm_state_context_t *svc_ctx =
1122 (struct tfm_state_context_t *)svc_args;
1123 psa_signal_t irq_signal = svc_ctx->r0;
1124 uint32_t running_partition_idx =
1125 tfm_spm_partition_get_running_partition_idx();
1126 uint32_t running_partition_id =
1127 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001128 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001129
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001130 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1131
1132 if (irq_line < 0) {
1133 /* FixMe: error severity TBD */
1134 tfm_secure_api_error_handler();
1135 }
1136
1137 tfm_spm_hal_disable_irq(irq_line);
1138}
1139
1140void tfm_spm_psa_wait(uint32_t *svc_args)
1141{
1142 /* Look for partition that is ready for run */
1143 struct tfm_state_context_t *svc_ctx =
1144 (struct tfm_state_context_t *)svc_args;
1145 uint32_t running_partition_idx;
1146 const struct spm_partition_runtime_data_t *curr_part_data;
1147
1148 psa_signal_t signal_mask = svc_ctx->r0;
1149 uint32_t timeout = svc_ctx->r1;
1150
1151 /*
1152 * Timeout[30:0] are reserved for future use.
1153 * SPM must ignore the value of RES.
1154 */
1155 timeout &= PSA_TIMEOUT_MASK;
1156
1157 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1158 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1159
1160 if (timeout == PSA_BLOCK) {
1161 /* FIXME: Scheduling is not available in library model, and busy wait is
1162 * also not possible as this code is running in SVC context, and it
1163 * cannot be pre-empted by interrupts. So do nothing here for now
1164 */
1165 (void) signal_mask;
1166 }
1167
1168 svc_ctx->r0 = curr_part_data->signal_mask;
1169}
1170
1171void tfm_spm_psa_eoi(uint32_t *svc_args)
1172{
1173 struct tfm_state_context_t *svc_ctx =
1174 (struct tfm_state_context_t *)svc_args;
1175 psa_signal_t irq_signal = svc_ctx->r0;
1176 uint32_t signal_mask;
1177 uint32_t running_partition_idx;
1178 uint32_t running_partition_id;
1179 const struct spm_partition_runtime_data_t *curr_part_data;
Kevin Penga20b5af2021-01-11 11:20:52 +08001180 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001181
1182 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1183 running_partition_id =
1184 tfm_spm_partition_get_partition_id(running_partition_idx);
1185 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1186
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001187 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1188
1189 if (irq_line < 0) {
1190 /* FixMe: error severity TBD */
1191 tfm_secure_api_error_handler();
1192 }
1193
1194 tfm_spm_hal_clear_pending_irq(irq_line);
1195 tfm_spm_hal_enable_irq(irq_line);
1196
1197 signal_mask = curr_part_data->signal_mask & ~irq_signal;
1198 tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
1199}
Mingyang Sunda01a972019-07-12 17:32:59 +08001200
1201/*
1202 * This function is called when a secure partition causes an error.
1203 * In case of an error in the error handling, a non-zero value have to be
1204 * returned.
1205 */
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001206static void tfm_spm_partition_err_handler(const uint32_t idx, int32_t errcode)
Mingyang Sunda01a972019-07-12 17:32:59 +08001207{
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001208 (void)errcode;
Ken Liuf250b8b2019-12-27 16:31:24 +08001209
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001210 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_CLOSED);
Mingyang Sunda01a972019-07-12 17:32:59 +08001211}
1212
David Hu9804b6a2021-02-15 21:23:06 +08001213fih_int tfm_spm_partition_init(void)
Mingyang Sunda01a972019-07-12 17:32:59 +08001214{
1215 struct spm_partition_desc_t *part;
1216 struct tfm_sfn_req_s desc;
1217 int32_t args[4] = {0};
David Hu9804b6a2021-02-15 21:23:06 +08001218 fih_int fail_cnt = FIH_INT_INIT(0);
Mingyang Sunda01a972019-07-12 17:32:59 +08001219 uint32_t idx;
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001220 bool privileged;
Ken Liu172f1e32021-02-05 16:31:03 +08001221 const struct platform_data_t **platform_data_p;
David Hu9804b6a2021-02-15 21:23:06 +08001222#ifdef TFM_FIH_PROFILE_ON
1223 fih_int fih_rc = FIH_FAILURE;
1224#endif
Mingyang Sunda01a972019-07-12 17:32:59 +08001225
1226 /* Call the init function for each partition */
1227 for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
1228 part = &g_spm_partition_db.partitions[idx];
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001229 platform_data_p = part->platform_data_list;
1230 if (platform_data_p != NULL) {
1231 while ((*platform_data_p) != NULL) {
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001232 if (tfm_is_partition_privileged(idx)) {
1233 privileged = true;
1234 } else {
1235 privileged = false;
1236 }
David Hu9804b6a2021-02-15 21:23:06 +08001237#ifdef TFM_FIH_PROFILE_ON
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001238 FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc,
1239 privileged, *platform_data_p);
David Hu9804b6a2021-02-15 21:23:06 +08001240 if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
1241 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
1242 }
1243#else /* TFM_FIH_PROFILE_ON */
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001244 if (tfm_spm_hal_configure_default_isolation(privileged,
Edison Ai6be3df12020-02-14 22:14:33 +08001245 *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
1246 fail_cnt++;
1247 }
David Hu9804b6a2021-02-15 21:23:06 +08001248#endif /* TFM_FIH_PROFILE_ON */
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001249 ++platform_data_p;
1250 }
1251 }
Summer Qin423dbef2019-08-22 15:59:35 +08001252 if (part->static_data->partition_init == NULL) {
Mingyang Sunda01a972019-07-12 17:32:59 +08001253 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1254 tfm_spm_partition_set_caller_partition_idx(idx,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001255 SPM_INVALID_PARTITION_IDX);
Mingyang Sunda01a972019-07-12 17:32:59 +08001256 } else {
1257 int32_t res;
1258
1259 desc.args = args;
Summer Qin43c185d2019-10-10 15:44:42 +08001260 desc.ns_caller = false;
Summer Qin423dbef2019-08-22 15:59:35 +08001261 desc.sfn = (sfn_t)part->static_data->partition_init;
1262 desc.sp_id = part->static_data->partition_id;
Mingyang Sunda01a972019-07-12 17:32:59 +08001263 res = tfm_core_sfn_request(&desc);
1264 if (res == TFM_SUCCESS) {
1265 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1266 } else {
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001267 tfm_spm_partition_err_handler(idx, res);
David Hu9804b6a2021-02-15 21:23:06 +08001268 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
Mingyang Sunda01a972019-07-12 17:32:59 +08001269 }
1270 }
1271 }
1272
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001273 tfm_spm_secure_api_init_done();
Mingyang Sunda01a972019-07-12 17:32:59 +08001274
David Hu9804b6a2021-02-15 21:23:06 +08001275 fih_int_validate(fail_cnt);
1276 if (fih_eq(fail_cnt, fih_int_encode(0))) {
1277 FIH_RET(fih_int_encode(SPM_ERR_OK));
Mingyang Sunda01a972019-07-12 17:32:59 +08001278 }
David Hu9804b6a2021-02-15 21:23:06 +08001279
1280 FIH_RET(fih_int_encode(SPM_ERR_PARTITION_NOT_AVAILABLE));
Mingyang Sunda01a972019-07-12 17:32:59 +08001281}
1282
1283void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
1284{
1285 struct spm_partition_runtime_data_t *runtime_data =
1286 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1287 struct interrupted_ctx_stack_frame_t *stack_frame =
Edison Ai7aff9e82019-07-11 14:56:46 +08001288 (struct interrupted_ctx_stack_frame_t *)runtime_data->ctx_stack_ptr;
Mingyang Sunda01a972019-07-12 17:32:59 +08001289
1290 stack_frame->partition_state = runtime_data->partition_state;
Matt463ed582019-12-20 12:31:25 +08001291
1292 runtime_data->ctx_stack_ptr +=
1293 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
Mingyang Sunda01a972019-07-12 17:32:59 +08001294}
1295
1296void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
1297{
1298 struct spm_partition_runtime_data_t *runtime_data =
1299 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1300 struct interrupted_ctx_stack_frame_t *stack_frame;
1301
Matt463ed582019-12-20 12:31:25 +08001302 runtime_data->ctx_stack_ptr -=
1303 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
1304
Mingyang Sunda01a972019-07-12 17:32:59 +08001305 stack_frame = (struct interrupted_ctx_stack_frame_t *)
1306 runtime_data->ctx_stack_ptr;
1307 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1308 stack_frame->partition_state = 0;
Mingyang Sunda01a972019-07-12 17:32:59 +08001309}
1310
1311void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
1312{
1313 struct spm_partition_runtime_data_t *runtime_data =
1314 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1315 struct handler_ctx_stack_frame_t *stack_frame =
1316 (struct handler_ctx_stack_frame_t *)
1317 runtime_data->ctx_stack_ptr;
1318
1319 stack_frame->partition_state = runtime_data->partition_state;
1320 stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
1321
1322 runtime_data->ctx_stack_ptr +=
1323 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1324}
1325
1326void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
1327{
1328 struct spm_partition_runtime_data_t *runtime_data =
1329 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1330 struct handler_ctx_stack_frame_t *stack_frame;
1331
1332 runtime_data->ctx_stack_ptr -=
1333 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1334
1335 stack_frame = (struct handler_ctx_stack_frame_t *)
1336 runtime_data->ctx_stack_ptr;
1337
1338 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1339 stack_frame->partition_state = 0;
1340 tfm_spm_partition_set_caller_partition_idx(
1341 partition_idx, stack_frame->caller_partition_idx);
1342 stack_frame->caller_partition_idx = 0;
1343}
1344
Mingyang Sunda01a972019-07-12 17:32:59 +08001345void tfm_spm_partition_store_context(uint32_t partition_idx,
1346 uint32_t stack_ptr, uint32_t lr)
1347{
1348 g_spm_partition_db.partitions[partition_idx].
1349 runtime_data.stack_ptr = stack_ptr;
1350 g_spm_partition_db.partitions[partition_idx].
1351 runtime_data.lr = lr;
1352}
1353
1354const struct spm_partition_runtime_data_t *
1355 tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
1356{
1357 return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
1358}
1359
1360void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
1361{
1362 g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
1363 state;
1364 if (state == SPM_PARTITION_STATE_RUNNING ||
1365 state == SPM_PARTITION_STATE_HANDLING_IRQ) {
1366 g_spm_partition_db.running_partition_idx = partition_idx;
1367 }
1368}
1369
1370void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
1371 uint32_t caller_partition_idx)
1372{
1373 g_spm_partition_db.partitions[partition_idx].runtime_data.
1374 caller_partition_idx = caller_partition_idx;
1375}
1376
1377void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
1378 uint32_t signal_mask)
1379{
1380 g_spm_partition_db.partitions[partition_idx].runtime_data.
1381 signal_mask = signal_mask;
1382}
1383
1384void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
1385 int32_t caller_client_id)
1386{
1387 g_spm_partition_db.partitions[partition_idx].runtime_data.
1388 caller_client_id = caller_client_id;
1389}
1390
Mingyang Sunda01a972019-07-12 17:32:59 +08001391uint32_t tfm_spm_partition_get_running_partition_idx(void)
1392{
1393 return g_spm_partition_db.running_partition_idx;
1394}
1395
1396void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
1397{
1398 struct spm_partition_desc_t *partition =
1399 &(g_spm_partition_db.partitions[partition_idx]);
1400 int32_t i;
1401
1402 partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
Mingyang Sunda01a972019-07-12 17:32:59 +08001403 partition->runtime_data.iovec_args.in_len = 0;
1404 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1405 partition->runtime_data.iovec_args.in_vec[i].base = 0;
1406 partition->runtime_data.iovec_args.in_vec[i].len = 0;
1407 }
1408 partition->runtime_data.iovec_args.out_len = 0;
1409 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1410 partition->runtime_data.iovec_args.out_vec[i].base = 0;
1411 partition->runtime_data.iovec_args.out_vec[i].len = 0;
1412 }
1413 partition->runtime_data.orig_outvec = 0;
Summer Qin423dbef2019-08-22 15:59:35 +08001414}
Summer Qin830c5542020-02-14 13:44:20 +08001415
1416void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
1417{
1418 uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
1419 uint32_t running_partition_flags = 0;
1420 uint32_t running_partition_idx;
1421
1422 /* Check permissions on request type basis */
1423
1424 switch (svc_ctx->r0) {
1425 case TFM_SPM_REQUEST_RESET_VOTE:
1426 running_partition_idx =
1427 tfm_spm_partition_get_running_partition_idx();
1428 running_partition_flags = tfm_spm_partition_get_flags(
1429 running_partition_idx);
1430
1431 /* Currently only PSA Root of Trust services are allowed to make Reset
1432 * vote request
1433 */
1434 if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1435 *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1436 }
1437
1438 /* FixMe: this is a placeholder for checks to be performed before
1439 * allowing execution of reset
1440 */
1441 *res_ptr = (uint32_t)TFM_SUCCESS;
1442
1443 break;
1444 default:
1445 *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1446 }
1447}
Mingyang Sunbd7ceb52020-06-11 16:53:03 +08001448
1449enum spm_err_t tfm_spm_db_init(void)
1450{
1451 uint32_t i;
1452
1453 /* This function initialises partition db */
1454
1455 /* For the non secure Execution environment */
1456 tfm_nspm_configure_clients();
1457
1458 for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1459 g_spm_partition_db.partitions[i].runtime_data.partition_state =
1460 SPM_PARTITION_STATE_UNINIT;
1461 g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
1462 SPM_INVALID_PARTITION_IDX;
1463 g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
1464 TFM_INVALID_CLIENT_ID;
1465 g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
1466 ctx_stack_list[i];
1467 g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
1468 g_spm_partition_db.partitions[i].platform_data_list =
1469 platform_data_list_list[i];
1470 }
1471 g_spm_partition_db.is_init = 1;
1472
1473 return SPM_ERR_OK;
1474}