blob: 1144b441c94873f036d61f3a9ec5f43c84b02252 [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 */
765 ERROR_MSG("Invalid service request during initialization!");
766 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) {
809 ERROR_MSG("Invalid service request!");
810 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();
830 ERROR_MSG("Unauthorized service request!");
831 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();
838 ERROR_MSG("Failed to process service request!");
839 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 */
880 ERROR_MSG("Secure API error during unlock!");
881 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
897 /* Check that the pointer is aligned properly */
898 if (start_addr_value & alignment_mask) {
899 /* not aligned, return error */
900 return 0;
901 }
902
903 /* Protect against overflow (and zero len) */
904 if (end_addr_value <= start_addr_value) {
905 return 0;
906 }
907
908 /* For privileged partition execution, all secure data memory and stack
909 * is accessible
910 */
911 if (start_addr_value >= S_DATA_START &&
912 end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
913 return 1;
914 }
915
916 return 0;
917}
918
919void tfm_spm_get_caller_client_id_handler(uint32_t *svc_args)
920{
921 uintptr_t result_ptr_value = svc_args[0];
922 uint32_t running_partition_idx =
923 tfm_spm_partition_get_running_partition_idx();
924 const uint32_t running_partition_flags =
925 tfm_spm_partition_get_flags(running_partition_idx);
926 const struct spm_partition_runtime_data_t *curr_part_data =
927 tfm_spm_partition_get_runtime_data(running_partition_idx);
928 int res = 0;
929
930 if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
931 curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
932 curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
933 /* This handler shouldn't be called from outside partition context.
934 * Also if the current partition is handling IRQ, the caller partition
935 * index might not be valid;
936 * Partitions are only allowed to run while S domain is locked.
937 */
938 svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
939 return;
940 }
941
942 /* Make sure that the output pointer points to a memory area that is owned
943 * by the partition
944 */
945 res = tfm_spm_check_buffer_access(running_partition_idx,
946 (void *)result_ptr_value,
947 sizeof(curr_part_data->caller_client_id),
948 2);
949 if (!res) {
950 /* Not in accessible range, return error */
951 svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
952 return;
953 }
954
955 *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
956
957 /* Store return value in r0 */
958 svc_args[0] = (uint32_t)TFM_SUCCESS;
959}
960
961/* This SVC handler is called if veneer is running in thread mode */
962uint32_t tfm_spm_partition_request_svc_handler(
963 const uint32_t *svc_ctx, uint32_t excReturn)
964{
965 struct tfm_sfn_req_s *desc_ptr;
966
967 if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
968 /* Service request SVC called with MSP active.
969 * Either invalid configuration for Thread mode or SVC called
970 * from Handler mode, which is not supported.
971 * FixMe: error severity TBD
972 */
973 ERROR_MSG("Service request SVC called with MSP active!");
974 tfm_secure_api_error_handler();
975 }
976
977 desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
978
979 if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
980 tfm_secure_api_error_handler();
981 }
982
983 return EXC_RETURN_SECURE_FUNCTION;
984}
985
986/* This SVC handler is called, if a thread mode execution environment is to
987 * be set up, to run an unprivileged IRQ handler
988 */
989uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
990{
991 struct tfm_state_context_t *svc_ctx =
992 (struct tfm_state_context_t *)svc_args;
993
994 enum tfm_status_e res;
995
996 if (excReturn & EXC_RETURN_STACK_PROCESS) {
997 /* FixMe: error severity TBD */
998 ERROR_MSG("Partition request SVC called with PSP active!");
999 tfm_secure_api_error_handler();
1000 }
1001
1002 res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
1003 if (res != TFM_SUCCESS) {
1004 /* The partition is in an invalid state (UNINIT or CLOSED), so none of
1005 * its code can be run
1006 */
1007 /* FixMe: For now this case is handled with TF-M panic, however it would
1008 * be possible to skip the execution of the interrupt handler, and
1009 * resume the execution of the interrupted code.
1010 */
1011 tfm_secure_api_error_handler();
1012 }
1013 return EXC_RETURN_SECURE_FUNCTION;
1014}
1015
1016/* This SVC handler is called when sfn returns */
1017uint32_t tfm_spm_partition_return_handler(uint32_t lr)
1018{
1019 enum tfm_status_e res;
1020
1021 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
1022 /* Partition return SVC called with MSP active.
1023 * This should not happen!
1024 */
1025 ERROR_MSG("Partition return SVC called with MSP active!");
1026 tfm_secure_api_error_handler();
1027 }
1028
1029 res = tfm_return_from_partition(&lr);
1030 if (res != TFM_SUCCESS) {
1031 /* Unlock errors indicate ctx database corruption or unknown anomalies
1032 * Halt execution
1033 */
1034 ERROR_MSG("Secure API error during unlock!");
1035 tfm_secure_api_error_handler();
1036 }
1037
1038 return lr;
1039}
1040
1041/* This SVC handler is called if a deprivileged IRQ handler was executed, and
1042 * the execution environment is to be set back for the privileged handler mode
1043 */
1044uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
1045{
1046 enum tfm_status_e res;
Ken Liue0af44c2020-07-25 22:51:30 +08001047 struct tfm_state_context_t *irq_svc_ctx;
1048
1049 /* Take into account the sealed stack*/
1050 irq_svc_args += 2;
1051
1052 irq_svc_ctx = (struct tfm_state_context_t *)irq_svc_args;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001053
1054 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
1055 /* Partition request SVC called with MSP active.
1056 * FixMe: error severity TBD
1057 */
1058 ERROR_MSG("Partition request SVC called with MSP active!");
1059 tfm_secure_api_error_handler();
1060 }
1061
1062 res = tfm_return_from_partition_irq_handling(&lr);
1063 if (res != TFM_SUCCESS) {
1064 /* Unlock errors indicate ctx database corruption or unknown anomalies
1065 * Halt execution
1066 */
1067 ERROR_MSG("Secure API error during unlock!");
1068 tfm_secure_api_error_handler();
1069 }
1070
1071 irq_svc_ctx->ra = lr;
1072
1073 return EXC_RETURN_SECURE_HANDLER;
1074}
1075
1076/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
1077/**
1078 * \brief Return the IRQ line number associated with a signal
1079 *
1080 * \param[in] partition_id The ID of the partition in which we look for the
1081 * signal
1082 * \param[in] signal The signal we do the query for
1083 *
1084 * \retval >=0 The IRQ line number associated with a signal in the partition
1085 * \retval <0 error
1086 */
Kevin Penga20b5af2021-01-11 11:20:52 +08001087static int32_t get_irq_line_for_signal(int32_t partition_id,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001088 psa_signal_t signal)
1089{
1090 size_t i;
1091
Ken Liu24dffb22021-02-10 11:03:58 +08001092 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
Kevin Peng410bee52021-01-13 16:27:17 +08001093 return -1;
1094 }
1095
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001096 for (i = 0; i < tfm_core_irq_signals_count; ++i) {
1097 if (tfm_core_irq_signals[i].partition_id == partition_id &&
1098 tfm_core_irq_signals[i].signal_value == signal) {
1099 return tfm_core_irq_signals[i].irq_line;
1100 }
1101 }
Kevin Penga20b5af2021-01-11 11:20:52 +08001102 return -1;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001103}
1104
1105void tfm_spm_enable_irq_handler(uint32_t *svc_args)
1106{
1107 struct tfm_state_context_t *svc_ctx =
1108 (struct tfm_state_context_t *)svc_args;
1109 psa_signal_t irq_signal = svc_ctx->r0;
1110 uint32_t running_partition_idx =
1111 tfm_spm_partition_get_running_partition_idx();
1112 uint32_t running_partition_id =
1113 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001114 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001115
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001116 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1117
1118 if (irq_line < 0) {
1119 /* FixMe: error severity TBD */
1120 tfm_secure_api_error_handler();
1121 }
1122
1123 tfm_spm_hal_enable_irq(irq_line);
1124}
1125
1126void tfm_spm_disable_irq_handler(uint32_t *svc_args)
1127{
1128 struct tfm_state_context_t *svc_ctx =
1129 (struct tfm_state_context_t *)svc_args;
1130 psa_signal_t irq_signal = svc_ctx->r0;
1131 uint32_t running_partition_idx =
1132 tfm_spm_partition_get_running_partition_idx();
1133 uint32_t running_partition_id =
1134 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001135 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001136
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001137 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1138
1139 if (irq_line < 0) {
1140 /* FixMe: error severity TBD */
1141 tfm_secure_api_error_handler();
1142 }
1143
1144 tfm_spm_hal_disable_irq(irq_line);
1145}
1146
1147void tfm_spm_psa_wait(uint32_t *svc_args)
1148{
1149 /* Look for partition that is ready for run */
1150 struct tfm_state_context_t *svc_ctx =
1151 (struct tfm_state_context_t *)svc_args;
1152 uint32_t running_partition_idx;
1153 const struct spm_partition_runtime_data_t *curr_part_data;
1154
1155 psa_signal_t signal_mask = svc_ctx->r0;
1156 uint32_t timeout = svc_ctx->r1;
1157
1158 /*
1159 * Timeout[30:0] are reserved for future use.
1160 * SPM must ignore the value of RES.
1161 */
1162 timeout &= PSA_TIMEOUT_MASK;
1163
1164 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1165 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1166
1167 if (timeout == PSA_BLOCK) {
1168 /* FIXME: Scheduling is not available in library model, and busy wait is
1169 * also not possible as this code is running in SVC context, and it
1170 * cannot be pre-empted by interrupts. So do nothing here for now
1171 */
1172 (void) signal_mask;
1173 }
1174
1175 svc_ctx->r0 = curr_part_data->signal_mask;
1176}
1177
1178void tfm_spm_psa_eoi(uint32_t *svc_args)
1179{
1180 struct tfm_state_context_t *svc_ctx =
1181 (struct tfm_state_context_t *)svc_args;
1182 psa_signal_t irq_signal = svc_ctx->r0;
1183 uint32_t signal_mask;
1184 uint32_t running_partition_idx;
1185 uint32_t running_partition_id;
1186 const struct spm_partition_runtime_data_t *curr_part_data;
Kevin Penga20b5af2021-01-11 11:20:52 +08001187 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001188
1189 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1190 running_partition_id =
1191 tfm_spm_partition_get_partition_id(running_partition_idx);
1192 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1193
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001194 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1195
1196 if (irq_line < 0) {
1197 /* FixMe: error severity TBD */
1198 tfm_secure_api_error_handler();
1199 }
1200
1201 tfm_spm_hal_clear_pending_irq(irq_line);
1202 tfm_spm_hal_enable_irq(irq_line);
1203
1204 signal_mask = curr_part_data->signal_mask & ~irq_signal;
1205 tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
1206}
Mingyang Sunda01a972019-07-12 17:32:59 +08001207
1208/*
1209 * This function is called when a secure partition causes an error.
1210 * In case of an error in the error handling, a non-zero value have to be
1211 * returned.
1212 */
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001213static void tfm_spm_partition_err_handler(const uint32_t idx, int32_t errcode)
Mingyang Sunda01a972019-07-12 17:32:59 +08001214{
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001215 (void)errcode;
Ken Liuf250b8b2019-12-27 16:31:24 +08001216
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001217 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_CLOSED);
Mingyang Sunda01a972019-07-12 17:32:59 +08001218}
1219
David Hu9804b6a2021-02-15 21:23:06 +08001220fih_int tfm_spm_partition_init(void)
Mingyang Sunda01a972019-07-12 17:32:59 +08001221{
1222 struct spm_partition_desc_t *part;
1223 struct tfm_sfn_req_s desc;
1224 int32_t args[4] = {0};
David Hu9804b6a2021-02-15 21:23:06 +08001225 fih_int fail_cnt = FIH_INT_INIT(0);
Mingyang Sunda01a972019-07-12 17:32:59 +08001226 uint32_t idx;
Ken Liu172f1e32021-02-05 16:31:03 +08001227 const struct platform_data_t **platform_data_p;
David Hu9804b6a2021-02-15 21:23:06 +08001228#ifdef TFM_FIH_PROFILE_ON
1229 fih_int fih_rc = FIH_FAILURE;
1230#endif
Mingyang Sunda01a972019-07-12 17:32:59 +08001231
1232 /* Call the init function for each partition */
1233 for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
1234 part = &g_spm_partition_db.partitions[idx];
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001235 platform_data_p = part->platform_data_list;
1236 if (platform_data_p != NULL) {
1237 while ((*platform_data_p) != NULL) {
David Hu9804b6a2021-02-15 21:23:06 +08001238#ifdef TFM_FIH_PROFILE_ON
1239 FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc, idx,
1240 *platform_data_p);
1241 if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
1242 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
1243 }
1244#else /* TFM_FIH_PROFILE_ON */
Edison Ai6be3df12020-02-14 22:14:33 +08001245 if (tfm_spm_hal_configure_default_isolation(idx,
1246 *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
1247 fail_cnt++;
1248 }
David Hu9804b6a2021-02-15 21:23:06 +08001249#endif /* TFM_FIH_PROFILE_ON */
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001250 ++platform_data_p;
1251 }
1252 }
Summer Qin423dbef2019-08-22 15:59:35 +08001253 if (part->static_data->partition_init == NULL) {
Mingyang Sunda01a972019-07-12 17:32:59 +08001254 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1255 tfm_spm_partition_set_caller_partition_idx(idx,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001256 SPM_INVALID_PARTITION_IDX);
Mingyang Sunda01a972019-07-12 17:32:59 +08001257 } else {
1258 int32_t res;
1259
1260 desc.args = args;
Summer Qin43c185d2019-10-10 15:44:42 +08001261 desc.ns_caller = false;
Summer Qin423dbef2019-08-22 15:59:35 +08001262 desc.sfn = (sfn_t)part->static_data->partition_init;
1263 desc.sp_id = part->static_data->partition_id;
Mingyang Sunda01a972019-07-12 17:32:59 +08001264 res = tfm_core_sfn_request(&desc);
1265 if (res == TFM_SUCCESS) {
1266 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1267 } else {
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001268 tfm_spm_partition_err_handler(idx, res);
David Hu9804b6a2021-02-15 21:23:06 +08001269 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
Mingyang Sunda01a972019-07-12 17:32:59 +08001270 }
1271 }
1272 }
1273
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001274 tfm_spm_secure_api_init_done();
Mingyang Sunda01a972019-07-12 17:32:59 +08001275
David Hu9804b6a2021-02-15 21:23:06 +08001276 fih_int_validate(fail_cnt);
1277 if (fih_eq(fail_cnt, fih_int_encode(0))) {
1278 FIH_RET(fih_int_encode(SPM_ERR_OK));
Mingyang Sunda01a972019-07-12 17:32:59 +08001279 }
David Hu9804b6a2021-02-15 21:23:06 +08001280
1281 FIH_RET(fih_int_encode(SPM_ERR_PARTITION_NOT_AVAILABLE));
Mingyang Sunda01a972019-07-12 17:32:59 +08001282}
1283
1284void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
1285{
1286 struct spm_partition_runtime_data_t *runtime_data =
1287 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1288 struct interrupted_ctx_stack_frame_t *stack_frame =
Edison Ai7aff9e82019-07-11 14:56:46 +08001289 (struct interrupted_ctx_stack_frame_t *)runtime_data->ctx_stack_ptr;
Mingyang Sunda01a972019-07-12 17:32:59 +08001290
1291 stack_frame->partition_state = runtime_data->partition_state;
Matt463ed582019-12-20 12:31:25 +08001292
1293 runtime_data->ctx_stack_ptr +=
1294 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
Mingyang Sunda01a972019-07-12 17:32:59 +08001295}
1296
1297void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
1298{
1299 struct spm_partition_runtime_data_t *runtime_data =
1300 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1301 struct interrupted_ctx_stack_frame_t *stack_frame;
1302
Matt463ed582019-12-20 12:31:25 +08001303 runtime_data->ctx_stack_ptr -=
1304 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
1305
Mingyang Sunda01a972019-07-12 17:32:59 +08001306 stack_frame = (struct interrupted_ctx_stack_frame_t *)
1307 runtime_data->ctx_stack_ptr;
1308 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1309 stack_frame->partition_state = 0;
Mingyang Sunda01a972019-07-12 17:32:59 +08001310}
1311
1312void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
1313{
1314 struct spm_partition_runtime_data_t *runtime_data =
1315 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1316 struct handler_ctx_stack_frame_t *stack_frame =
1317 (struct handler_ctx_stack_frame_t *)
1318 runtime_data->ctx_stack_ptr;
1319
1320 stack_frame->partition_state = runtime_data->partition_state;
1321 stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
1322
1323 runtime_data->ctx_stack_ptr +=
1324 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1325}
1326
1327void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
1328{
1329 struct spm_partition_runtime_data_t *runtime_data =
1330 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1331 struct handler_ctx_stack_frame_t *stack_frame;
1332
1333 runtime_data->ctx_stack_ptr -=
1334 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1335
1336 stack_frame = (struct handler_ctx_stack_frame_t *)
1337 runtime_data->ctx_stack_ptr;
1338
1339 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1340 stack_frame->partition_state = 0;
1341 tfm_spm_partition_set_caller_partition_idx(
1342 partition_idx, stack_frame->caller_partition_idx);
1343 stack_frame->caller_partition_idx = 0;
1344}
1345
Mingyang Sunda01a972019-07-12 17:32:59 +08001346void tfm_spm_partition_store_context(uint32_t partition_idx,
1347 uint32_t stack_ptr, uint32_t lr)
1348{
1349 g_spm_partition_db.partitions[partition_idx].
1350 runtime_data.stack_ptr = stack_ptr;
1351 g_spm_partition_db.partitions[partition_idx].
1352 runtime_data.lr = lr;
1353}
1354
1355const struct spm_partition_runtime_data_t *
1356 tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
1357{
1358 return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
1359}
1360
1361void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
1362{
1363 g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
1364 state;
1365 if (state == SPM_PARTITION_STATE_RUNNING ||
1366 state == SPM_PARTITION_STATE_HANDLING_IRQ) {
1367 g_spm_partition_db.running_partition_idx = partition_idx;
1368 }
1369}
1370
1371void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
1372 uint32_t caller_partition_idx)
1373{
1374 g_spm_partition_db.partitions[partition_idx].runtime_data.
1375 caller_partition_idx = caller_partition_idx;
1376}
1377
1378void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
1379 uint32_t signal_mask)
1380{
1381 g_spm_partition_db.partitions[partition_idx].runtime_data.
1382 signal_mask = signal_mask;
1383}
1384
1385void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
1386 int32_t caller_client_id)
1387{
1388 g_spm_partition_db.partitions[partition_idx].runtime_data.
1389 caller_client_id = caller_client_id;
1390}
1391
Mingyang Sunda01a972019-07-12 17:32:59 +08001392uint32_t tfm_spm_partition_get_running_partition_idx(void)
1393{
1394 return g_spm_partition_db.running_partition_idx;
1395}
1396
1397void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
1398{
1399 struct spm_partition_desc_t *partition =
1400 &(g_spm_partition_db.partitions[partition_idx]);
1401 int32_t i;
1402
1403 partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
Mingyang Sunda01a972019-07-12 17:32:59 +08001404 partition->runtime_data.iovec_args.in_len = 0;
1405 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1406 partition->runtime_data.iovec_args.in_vec[i].base = 0;
1407 partition->runtime_data.iovec_args.in_vec[i].len = 0;
1408 }
1409 partition->runtime_data.iovec_args.out_len = 0;
1410 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1411 partition->runtime_data.iovec_args.out_vec[i].base = 0;
1412 partition->runtime_data.iovec_args.out_vec[i].len = 0;
1413 }
1414 partition->runtime_data.orig_outvec = 0;
Summer Qin423dbef2019-08-22 15:59:35 +08001415}
Summer Qin830c5542020-02-14 13:44:20 +08001416
1417void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
1418{
1419 uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
1420 uint32_t running_partition_flags = 0;
1421 uint32_t running_partition_idx;
1422
1423 /* Check permissions on request type basis */
1424
1425 switch (svc_ctx->r0) {
1426 case TFM_SPM_REQUEST_RESET_VOTE:
1427 running_partition_idx =
1428 tfm_spm_partition_get_running_partition_idx();
1429 running_partition_flags = tfm_spm_partition_get_flags(
1430 running_partition_idx);
1431
1432 /* Currently only PSA Root of Trust services are allowed to make Reset
1433 * vote request
1434 */
1435 if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1436 *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1437 }
1438
1439 /* FixMe: this is a placeholder for checks to be performed before
1440 * allowing execution of reset
1441 */
1442 *res_ptr = (uint32_t)TFM_SUCCESS;
1443
1444 break;
1445 default:
1446 *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1447 }
1448}
Mingyang Sunbd7ceb52020-06-11 16:53:03 +08001449
1450enum spm_err_t tfm_spm_db_init(void)
1451{
1452 uint32_t i;
1453
1454 /* This function initialises partition db */
1455
1456 /* For the non secure Execution environment */
1457 tfm_nspm_configure_clients();
1458
1459 for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1460 g_spm_partition_db.partitions[i].runtime_data.partition_state =
1461 SPM_PARTITION_STATE_UNINIT;
1462 g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
1463 SPM_INVALID_PARTITION_IDX;
1464 g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
1465 TFM_INVALID_CLIENT_ID;
1466 g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
1467 ctx_stack_list[i];
1468 g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
1469 g_spm_partition_db.partitions[i].platform_data_list =
1470 platform_data_list_list[i];
1471 }
1472 g_spm_partition_db.is_init = 1;
1473
1474 return SPM_ERR_OK;
1475}