blob: 443ea024d4c9f4064a3bb113bdbd3ff2260d038d [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
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800457static enum tfm_status_e tfm_start_partition(
David Hu5da82de2020-12-02 16:41:30 +0800458 const struct tfm_sfn_req_s *desc_ptr,
459 const struct iovec_params_t *iovec_ptr,
460 uint32_t excReturn)
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800461{
Xinyu Zhang3a453242021-04-16 17:57:09 +0800462 register uint32_t partition_idx;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800463 enum tfm_status_e res;
464 uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
465 const struct spm_partition_runtime_data_t *curr_part_data;
466 const struct spm_partition_runtime_data_t *caller_part_data;
467 uint32_t caller_flags;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800468 uint32_t psp;
469 uint32_t partition_psp, partition_psplim;
470 uint32_t partition_state;
471 uint32_t caller_partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800472 struct tfm_state_context_t *svc_ctx;
473 uint32_t caller_partition_id;
474 int32_t client_id;
475 struct iovec_args_t *iovec_args;
476
477 psp = __get_PSP();
478 svc_ctx = (struct tfm_state_context_t *)psp;
479 caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
480
481 /* Check partition state consistency */
482 if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
483 != (!desc_ptr->ns_caller)) {
484 /* Partition state inconsistency detected */
485 return TFM_SECURE_LOCK_FAILED;
486 }
487
488 partition_idx = get_partition_idx(desc_ptr->sp_id);
489
490 curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
491 caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
492 partition_state = curr_part_data->partition_state;
493 caller_partition_state = caller_part_data->partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800494 caller_partition_id = tfm_spm_partition_get_partition_id(
495 caller_partition_idx);
496
497 if (!tfm_secure_api_initializing) {
498 res = check_partition_state(partition_state, caller_partition_state);
499 if (res != TFM_SUCCESS) {
500 return res;
501 }
502 }
503
504 /* Prepare switch to shared secure partition stack */
505 /* In case the call is coming from the non-secure world, we save the iovecs
Soby Mathew960521a2020-09-29 12:48:50 +0100506 * on the stop of the stack. Also the stack seal is present below this region.
507 * So the memory area, that can actually be used as stack by the partitions
508 * starts at a lower address.
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800509 */
Soby Mathew960521a2020-09-29 12:48:50 +0100510 partition_psp = (uint32_t) tfm_secure_stack_seal;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800511 partition_psplim =
512 (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
513
514 /* Store the context for the partition call */
515 tfm_spm_partition_set_caller_partition_idx(partition_idx,
516 caller_partition_idx);
517 tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
518
519 if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
520 tfm_spm_partition_set_caller_client_id(partition_idx,
521 caller_partition_id);
522 } else {
523 client_id = tfm_nspm_get_current_client_id();
524 if (client_id >= 0) {
525 return TFM_SECURE_LOCK_FAILED;
526 }
527 tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
528 }
529
530 /* In level one, only switch context and return from exception if in
531 * handler mode
532 */
533 if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
David Hu5da82de2020-12-02 16:41:30 +0800534 if (tfm_spm_partition_set_iovec(partition_idx, iovec_ptr) !=
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800535 SPM_ERR_OK) {
536 return TFM_ERROR_GENERIC;
537 }
538 iovec_args = get_iovec_args_stack_address(partition_idx);
539 tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
540
541 /* Prepare the partition context, update stack ptr */
542 psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
543 iovec_args,
544 (uint32_t *)partition_psp);
545 __set_PSP(psp);
546 tfm_arch_set_psplim(partition_psplim);
547 }
548
549 tfm_spm_partition_set_state(caller_partition_idx,
550 SPM_PARTITION_STATE_BLOCKED);
551 tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
552 tfm_secure_lock++;
553
554 return TFM_SUCCESS;
555}
556
557static enum tfm_status_e tfm_start_partition_for_irq_handling(
558 uint32_t excReturn,
559 struct tfm_state_context_t *svc_ctx)
560{
561 uint32_t handler_partition_id = svc_ctx->r0;
562 sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
563 uint32_t irq_signal = svc_ctx->r2;
Kevin Penga20b5af2021-01-11 11:20:52 +0800564 uint32_t irq_line = svc_ctx->r3;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800565 enum tfm_status_e res;
566 uint32_t psp = __get_PSP();
567 uint32_t handler_partition_psp;
568 uint32_t handler_partition_state;
569 uint32_t interrupted_partition_idx =
570 tfm_spm_partition_get_running_partition_idx();
571 const struct spm_partition_runtime_data_t *handler_part_data;
572 uint32_t handler_partition_idx;
573
574 handler_partition_idx = get_partition_idx(handler_partition_id);
575 handler_part_data = tfm_spm_partition_get_runtime_data(
576 handler_partition_idx);
577 handler_partition_state = handler_part_data->partition_state;
578
579 res = check_irq_partition_state(handler_partition_state);
580 if (res != TFM_SUCCESS) {
581 return res;
582 }
583
584 /* set mask for the partition */
585 tfm_spm_partition_set_signal_mask(
586 handler_partition_idx,
587 handler_part_data->signal_mask | irq_signal);
588
589 tfm_spm_hal_disable_irq(irq_line);
590
591 /* save the current context of the interrupted partition */
592 tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
593
594 handler_partition_psp = psp;
595
596 /* save the current context of the handler partition */
597 tfm_spm_partition_push_handler_ctx(handler_partition_idx);
598
599 /* Store caller for the partition */
600 tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
601 interrupted_partition_idx);
602
603 psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
604 (int32_t *)handler_partition_psp);
605 __set_PSP(psp);
606
607 tfm_spm_partition_set_state(interrupted_partition_idx,
608 SPM_PARTITION_STATE_SUSPENDED);
609 tfm_spm_partition_set_state(handler_partition_idx,
610 SPM_PARTITION_STATE_HANDLING_IRQ);
611
612 return TFM_SUCCESS;
613}
614
615static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
616{
617 uint32_t current_partition_idx =
618 tfm_spm_partition_get_running_partition_idx();
619 const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800620 uint32_t return_partition_idx;
621 uint32_t return_partition_flags;
622 uint32_t psp = __get_PSP();
623 size_t i;
624 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
625 struct iovec_args_t *iovec_args;
626
627 if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
628 return TFM_SECURE_UNLOCK_FAILED;
629 }
630
631 curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
632 return_partition_idx = curr_part_data->caller_partition_idx;
633
634 if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
635 return TFM_SECURE_UNLOCK_FAILED;
636 }
637
638 ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
639
640 return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800641
642 tfm_secure_lock--;
643
644 if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
645 (tfm_secure_api_initializing)) {
646 /* In TFM level 1 context restore is only done when
647 * returning to NS or after initialization
648 */
649 /* Restore caller context */
650 restore_caller_ctx(svc_ctx,
651 (struct tfm_state_context_t *)ret_part_data->stack_ptr);
652 *excReturn = ret_part_data->lr;
653 __set_PSP(ret_part_data->stack_ptr);
TTornblom99f0be22019-12-17 16:22:38 +0100654 REGION_DECLARE_T(Image$$, ARM_LIB_STACK, $$ZI$$Base, uint32_t)[];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800655 uint32_t psp_stack_bottom =
656 (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
657 tfm_arch_set_psplim(psp_stack_bottom);
658
TTornblom99f0be22019-12-17 16:22:38 +0100659 iovec_args = &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800660
661 for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
662 curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
663 }
664 tfm_clear_iovec_parameters(iovec_args);
665 }
666
667 tfm_spm_partition_cleanup_context(current_partition_idx);
668
669 tfm_spm_partition_set_state(current_partition_idx,
670 SPM_PARTITION_STATE_IDLE);
671 tfm_spm_partition_set_state(return_partition_idx,
672 SPM_PARTITION_STATE_RUNNING);
673
674 return TFM_SUCCESS;
675}
676
677static enum tfm_status_e tfm_return_from_partition_irq_handling(
678 uint32_t *excReturn)
679{
680 uint32_t handler_partition_idx =
681 tfm_spm_partition_get_running_partition_idx();
682 const struct spm_partition_runtime_data_t *handler_part_data;
683 uint32_t interrupted_partition_idx;
684 uint32_t psp = __get_PSP();
685 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
686
687 if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
688 return TFM_SECURE_UNLOCK_FAILED;
689 }
690
691 handler_part_data = tfm_spm_partition_get_runtime_data(
692 handler_partition_idx);
693 interrupted_partition_idx = handler_part_data->caller_partition_idx;
694
695 if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
696 return TFM_SECURE_UNLOCK_FAILED;
697 }
698
699 /* For level 1, modify PSP, so that the SVC stack frame disappears,
700 * and return to the privileged handler using the stack frame still on the
701 * MSP stack.
702 */
703 *excReturn = svc_ctx->ra;
704 psp += sizeof(struct tfm_state_context_t);
705
706 tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
707 tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
708
709 __set_PSP(psp);
710
711 return TFM_SUCCESS;
712}
713
714static enum tfm_status_e tfm_check_sfn_req_integrity(
715 const struct tfm_sfn_req_s *desc_ptr)
716{
717 if ((desc_ptr == NULL) ||
718 (desc_ptr->sp_id == 0) ||
719 (desc_ptr->sfn == NULL)) {
720 /* invalid parameter */
721 return TFM_ERROR_INVALID_PARAMETER;
722 }
723 return TFM_SUCCESS;
724}
725
726static enum tfm_status_e tfm_core_check_sfn_req_rules(
727 const struct tfm_sfn_req_s *desc_ptr)
728{
729 /* Check partition idx validity */
730 if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
731 return TFM_ERROR_NO_ACTIVE_PARTITION;
732 }
733
734 if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
735 /* Secure domain is already locked!
736 * This should only happen if caller is secure partition!
737 */
738 /* This scenario is a potential security breach.
739 * Error is handled in caller.
740 */
741 return TFM_ERROR_SECURE_DOMAIN_LOCKED;
742 }
743
744 if (tfm_secure_api_initializing) {
745 int32_t id =
746 tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
747
748 if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
749 /* Invalid request during system initialization */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100750 SPMLOG_ERRMSG("Invalid service request during initialization!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800751 return TFM_ERROR_NOT_INITIALIZED;
752 }
753 }
754
755 return TFM_SUCCESS;
756}
757
Antonio de Angelis5b64bb72021-04-27 08:37:14 +0100758uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
759{
760 return g_spm_partition_db.partitions[partition_idx].static_data->
761 partition_flags;
762}
763
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800764uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
765{
766 return g_spm_partition_db.partitions[partition_idx].static_data->
767 partition_id;
768}
769
770uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
771{
772 if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
773 return TFM_PARTITION_PRIVILEGED_MODE;
774 } else {
775 return TFM_PARTITION_UNPRIVILEGED_MODE;
776 }
777}
778
779bool tfm_is_partition_privileged(uint32_t partition_idx)
780{
781 uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
782
783 return tfm_spm_partition_get_privileged_mode(flags) ==
784 TFM_PARTITION_PRIVILEGED_MODE;
785}
786
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800787void tfm_spm_secure_api_init_done(void)
788{
789 tfm_secure_api_initializing = 0;
790}
791
792enum tfm_status_e tfm_spm_sfn_request_handler(
793 struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
794{
795 enum tfm_status_e res;
shejia0101a497c2021-04-21 10:04:07 +0800796 struct iovec_params_t iovecs = {0};
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800797
798 res = tfm_check_sfn_req_integrity(desc_ptr);
799 if (res != TFM_SUCCESS) {
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100800 SPMLOG_ERRMSG("Invalid service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800801 tfm_secure_api_error_handler();
802 }
803
804 __disable_irq();
805
806 desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
807
David Hu5da82de2020-12-02 16:41:30 +0800808 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800809 if (res != TFM_SUCCESS) {
810 /* The sanity check of iovecs failed. */
811 __enable_irq();
812 tfm_secure_api_error_handler();
813 }
814
815 res = tfm_core_check_sfn_req_rules(desc_ptr);
816 if (res != TFM_SUCCESS) {
817 /* FixMe: error compartmentalization TBD */
818 tfm_spm_partition_set_state(
819 desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
820 __enable_irq();
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100821 SPMLOG_ERRMSG("Unauthorized service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800822 tfm_secure_api_error_handler();
823 }
824
David Hu5da82de2020-12-02 16:41:30 +0800825 res = tfm_start_partition(desc_ptr, &iovecs, excReturn);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800826 if (res != TFM_SUCCESS) {
827 /* FixMe: consider possible fault scenarios */
828 __enable_irq();
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100829 SPMLOG_ERRMSG("Failed to process service request!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800830 tfm_secure_api_error_handler();
831 }
832
833 __enable_irq();
834
835 return res;
836}
837
838int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
839{
840 enum tfm_status_e res;
841 int32_t *args;
842 int32_t retVal;
David Hu5da82de2020-12-02 16:41:30 +0800843 struct iovec_params_t iovecs;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800844
David Hu5da82de2020-12-02 16:41:30 +0800845 res = tfm_core_check_sfn_parameters(desc_ptr, &iovecs);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800846 if (res != TFM_SUCCESS) {
847 /* The sanity check of iovecs failed. */
848 return (int32_t)res;
849 }
850
851 /* No excReturn value is needed as no exception handling is used */
852 res = tfm_spm_sfn_request_handler(desc_ptr, 0);
853
854 if (res != TFM_SUCCESS) {
855 tfm_secure_api_error_handler();
856 }
857
858 /* Secure partition to secure partition call in TFM level 1 */
859 args = desc_ptr->args;
860 retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
861
862 /* return handler should restore original exc_return value... */
863 res = tfm_return_from_partition(NULL);
864 if (res == TFM_SUCCESS) {
865 /* If unlock successful, pass SS return value to caller */
866 return retVal;
867 } else {
868 /* Unlock errors indicate ctx database corruption or unknown
869 * anomalies. Halt execution
870 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100871 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800872 tfm_secure_api_error_handler();
873 }
874 return (int32_t)res;
875}
876
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800877int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
878 void *start_addr,
879 size_t len,
880 uint32_t alignment)
881{
882 uintptr_t start_addr_value = (uintptr_t)start_addr;
883 uintptr_t end_addr_value = (uintptr_t)start_addr + len;
884 uintptr_t alignment_mask;
885
886 alignment_mask = (((uintptr_t)1) << alignment) - 1;
887
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100888 /* Check pointer alignment and protect against overflow and zero len */
889 if (!(start_addr_value & alignment_mask) &&
890 (end_addr_value > start_addr_value)) {
891 /* Check that the range is in S_DATA */
892 if ((start_addr_value >= S_DATA_START) &&
893 (end_addr_value <= (S_DATA_START + S_DATA_SIZE))) {
894 return TFM_SUCCESS;
895 } else {
896 return TFM_ERROR_NOT_IN_RANGE;
897 }
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800898 }
899
Antonio de Angelisf8564cb2021-04-28 13:52:13 +0100900 return TFM_ERROR_INVALID_PARAMETER;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800901}
902
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800903/* This SVC handler is called if veneer is running in thread mode */
904uint32_t tfm_spm_partition_request_svc_handler(
905 const uint32_t *svc_ctx, uint32_t excReturn)
906{
907 struct tfm_sfn_req_s *desc_ptr;
908
909 if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
910 /* Service request SVC called with MSP active.
911 * Either invalid configuration for Thread mode or SVC called
912 * from Handler mode, which is not supported.
913 * FixMe: error severity TBD
914 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100915 SPMLOG_ERRMSG("Service request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800916 tfm_secure_api_error_handler();
917 }
918
919 desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
920
921 if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
922 tfm_secure_api_error_handler();
923 }
924
925 return EXC_RETURN_SECURE_FUNCTION;
926}
927
928/* This SVC handler is called, if a thread mode execution environment is to
929 * be set up, to run an unprivileged IRQ handler
930 */
931uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
932{
933 struct tfm_state_context_t *svc_ctx =
934 (struct tfm_state_context_t *)svc_args;
935
936 enum tfm_status_e res;
937
938 if (excReturn & EXC_RETURN_STACK_PROCESS) {
939 /* FixMe: error severity TBD */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +0100940 SPMLOG_ERRMSG("Partition request SVC called with PSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800941 tfm_secure_api_error_handler();
942 }
943
944 res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
945 if (res != TFM_SUCCESS) {
946 /* The partition is in an invalid state (UNINIT or CLOSED), so none of
947 * its code can be run
948 */
949 /* FixMe: For now this case is handled with TF-M panic, however it would
950 * be possible to skip the execution of the interrupt handler, and
951 * resume the execution of the interrupted code.
952 */
953 tfm_secure_api_error_handler();
954 }
955 return EXC_RETURN_SECURE_FUNCTION;
956}
957
958/* This SVC handler is called when sfn returns */
959uint32_t tfm_spm_partition_return_handler(uint32_t lr)
960{
961 enum tfm_status_e res;
962
963 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
964 /* Partition return SVC called with MSP active.
965 * This should not happen!
966 */
967 ERROR_MSG("Partition return SVC called with MSP active!");
968 tfm_secure_api_error_handler();
969 }
970
971 res = tfm_return_from_partition(&lr);
972 if (res != TFM_SUCCESS) {
973 /* Unlock errors indicate ctx database corruption or unknown anomalies
974 * Halt execution
975 */
976 ERROR_MSG("Secure API error during unlock!");
977 tfm_secure_api_error_handler();
978 }
979
980 return lr;
981}
982
983/* This SVC handler is called if a deprivileged IRQ handler was executed, and
984 * the execution environment is to be set back for the privileged handler mode
985 */
986uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
987{
988 enum tfm_status_e res;
Ken Liue0af44c2020-07-25 22:51:30 +0800989 struct tfm_state_context_t *irq_svc_ctx;
990
991 /* Take into account the sealed stack*/
992 irq_svc_args += 2;
993
994 irq_svc_ctx = (struct tfm_state_context_t *)irq_svc_args;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800995
996 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
997 /* Partition request SVC called with MSP active.
998 * FixMe: error severity TBD
999 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001000 SPMLOG_ERRMSG("Partition request SVC called with MSP active!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001001 tfm_secure_api_error_handler();
1002 }
1003
1004 res = tfm_return_from_partition_irq_handling(&lr);
1005 if (res != TFM_SUCCESS) {
1006 /* Unlock errors indicate ctx database corruption or unknown anomalies
1007 * Halt execution
1008 */
Antonio de Angelisfa5d4602021-06-09 16:11:11 +01001009 SPMLOG_ERRMSG("Secure API error during unlock!\r\n");
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001010 tfm_secure_api_error_handler();
1011 }
1012
1013 irq_svc_ctx->ra = lr;
1014
1015 return EXC_RETURN_SECURE_HANDLER;
1016}
1017
1018/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
1019/**
1020 * \brief Return the IRQ line number associated with a signal
1021 *
1022 * \param[in] partition_id The ID of the partition in which we look for the
1023 * signal
1024 * \param[in] signal The signal we do the query for
1025 *
1026 * \retval >=0 The IRQ line number associated with a signal in the partition
1027 * \retval <0 error
1028 */
Kevin Penga20b5af2021-01-11 11:20:52 +08001029static int32_t get_irq_line_for_signal(int32_t partition_id,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001030 psa_signal_t signal)
1031{
1032 size_t i;
1033
Ken Liu24dffb22021-02-10 11:03:58 +08001034 if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
Kevin Peng410bee52021-01-13 16:27:17 +08001035 return -1;
1036 }
1037
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001038 for (i = 0; i < tfm_core_irq_signals_count; ++i) {
1039 if (tfm_core_irq_signals[i].partition_id == partition_id &&
1040 tfm_core_irq_signals[i].signal_value == signal) {
1041 return tfm_core_irq_signals[i].irq_line;
1042 }
1043 }
Kevin Penga20b5af2021-01-11 11:20:52 +08001044 return -1;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001045}
1046
1047void tfm_spm_enable_irq_handler(uint32_t *svc_args)
1048{
1049 struct tfm_state_context_t *svc_ctx =
1050 (struct tfm_state_context_t *)svc_args;
1051 psa_signal_t irq_signal = svc_ctx->r0;
1052 uint32_t running_partition_idx =
1053 tfm_spm_partition_get_running_partition_idx();
1054 uint32_t running_partition_id =
1055 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001056 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001057
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001058 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1059
1060 if (irq_line < 0) {
1061 /* FixMe: error severity TBD */
1062 tfm_secure_api_error_handler();
1063 }
1064
1065 tfm_spm_hal_enable_irq(irq_line);
1066}
1067
1068void tfm_spm_disable_irq_handler(uint32_t *svc_args)
1069{
1070 struct tfm_state_context_t *svc_ctx =
1071 (struct tfm_state_context_t *)svc_args;
1072 psa_signal_t irq_signal = svc_ctx->r0;
1073 uint32_t running_partition_idx =
1074 tfm_spm_partition_get_running_partition_idx();
1075 uint32_t running_partition_id =
1076 tfm_spm_partition_get_partition_id(running_partition_idx);
Kevin Penga20b5af2021-01-11 11:20:52 +08001077 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001078
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001079 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1080
1081 if (irq_line < 0) {
1082 /* FixMe: error severity TBD */
1083 tfm_secure_api_error_handler();
1084 }
1085
1086 tfm_spm_hal_disable_irq(irq_line);
1087}
1088
1089void tfm_spm_psa_wait(uint32_t *svc_args)
1090{
1091 /* Look for partition that is ready for run */
1092 struct tfm_state_context_t *svc_ctx =
1093 (struct tfm_state_context_t *)svc_args;
1094 uint32_t running_partition_idx;
1095 const struct spm_partition_runtime_data_t *curr_part_data;
1096
1097 psa_signal_t signal_mask = svc_ctx->r0;
1098 uint32_t timeout = svc_ctx->r1;
1099
1100 /*
1101 * Timeout[30:0] are reserved for future use.
1102 * SPM must ignore the value of RES.
1103 */
1104 timeout &= PSA_TIMEOUT_MASK;
1105
1106 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1107 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1108
1109 if (timeout == PSA_BLOCK) {
1110 /* FIXME: Scheduling is not available in library model, and busy wait is
1111 * also not possible as this code is running in SVC context, and it
1112 * cannot be pre-empted by interrupts. So do nothing here for now
1113 */
1114 (void) signal_mask;
1115 }
1116
1117 svc_ctx->r0 = curr_part_data->signal_mask;
1118}
1119
1120void tfm_spm_psa_eoi(uint32_t *svc_args)
1121{
1122 struct tfm_state_context_t *svc_ctx =
1123 (struct tfm_state_context_t *)svc_args;
1124 psa_signal_t irq_signal = svc_ctx->r0;
1125 uint32_t signal_mask;
1126 uint32_t running_partition_idx;
1127 uint32_t running_partition_id;
1128 const struct spm_partition_runtime_data_t *curr_part_data;
Kevin Penga20b5af2021-01-11 11:20:52 +08001129 int32_t irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001130
1131 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1132 running_partition_id =
1133 tfm_spm_partition_get_partition_id(running_partition_idx);
1134 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1135
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001136 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1137
1138 if (irq_line < 0) {
1139 /* FixMe: error severity TBD */
1140 tfm_secure_api_error_handler();
1141 }
1142
1143 tfm_spm_hal_clear_pending_irq(irq_line);
1144 tfm_spm_hal_enable_irq(irq_line);
1145
1146 signal_mask = curr_part_data->signal_mask & ~irq_signal;
1147 tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
1148}
Mingyang Sunda01a972019-07-12 17:32:59 +08001149
1150/*
1151 * This function is called when a secure partition causes an error.
1152 * In case of an error in the error handling, a non-zero value have to be
1153 * returned.
1154 */
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001155static void tfm_spm_partition_err_handler(const uint32_t idx, int32_t errcode)
Mingyang Sunda01a972019-07-12 17:32:59 +08001156{
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001157 (void)errcode;
Ken Liuf250b8b2019-12-27 16:31:24 +08001158
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001159 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_CLOSED);
Mingyang Sunda01a972019-07-12 17:32:59 +08001160}
1161
David Hu9804b6a2021-02-15 21:23:06 +08001162fih_int tfm_spm_partition_init(void)
Mingyang Sunda01a972019-07-12 17:32:59 +08001163{
1164 struct spm_partition_desc_t *part;
1165 struct tfm_sfn_req_s desc;
1166 int32_t args[4] = {0};
David Hu9804b6a2021-02-15 21:23:06 +08001167 fih_int fail_cnt = FIH_INT_INIT(0);
Mingyang Sunda01a972019-07-12 17:32:59 +08001168 uint32_t idx;
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001169 bool privileged;
Ken Liu172f1e32021-02-05 16:31:03 +08001170 const struct platform_data_t **platform_data_p;
David Hu9804b6a2021-02-15 21:23:06 +08001171#ifdef TFM_FIH_PROFILE_ON
1172 fih_int fih_rc = FIH_FAILURE;
1173#endif
Mingyang Sunda01a972019-07-12 17:32:59 +08001174
1175 /* Call the init function for each partition */
1176 for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
1177 part = &g_spm_partition_db.partitions[idx];
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001178 platform_data_p = part->platform_data_list;
1179 if (platform_data_p != NULL) {
1180 while ((*platform_data_p) != NULL) {
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001181 if (tfm_is_partition_privileged(idx)) {
1182 privileged = true;
1183 } else {
1184 privileged = false;
1185 }
David Hu9804b6a2021-02-15 21:23:06 +08001186#ifdef TFM_FIH_PROFILE_ON
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001187 FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc,
1188 privileged, *platform_data_p);
David Hu9804b6a2021-02-15 21:23:06 +08001189 if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
1190 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
1191 }
1192#else /* TFM_FIH_PROFILE_ON */
Mingyang Sun61f8fbc2021-06-04 17:49:56 +08001193 if (tfm_spm_hal_configure_default_isolation(privileged,
Edison Ai6be3df12020-02-14 22:14:33 +08001194 *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
1195 fail_cnt++;
1196 }
David Hu9804b6a2021-02-15 21:23:06 +08001197#endif /* TFM_FIH_PROFILE_ON */
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001198 ++platform_data_p;
1199 }
1200 }
Summer Qin423dbef2019-08-22 15:59:35 +08001201 if (part->static_data->partition_init == NULL) {
Mingyang Sunda01a972019-07-12 17:32:59 +08001202 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1203 tfm_spm_partition_set_caller_partition_idx(idx,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001204 SPM_INVALID_PARTITION_IDX);
Mingyang Sunda01a972019-07-12 17:32:59 +08001205 } else {
1206 int32_t res;
1207
1208 desc.args = args;
Summer Qin43c185d2019-10-10 15:44:42 +08001209 desc.ns_caller = false;
Summer Qin423dbef2019-08-22 15:59:35 +08001210 desc.sfn = (sfn_t)part->static_data->partition_init;
1211 desc.sp_id = part->static_data->partition_id;
Mingyang Sunda01a972019-07-12 17:32:59 +08001212 res = tfm_core_sfn_request(&desc);
1213 if (res == TFM_SUCCESS) {
1214 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1215 } else {
Xinyu Zhanga8820de2021-01-25 16:41:50 +08001216 tfm_spm_partition_err_handler(idx, res);
David Hu9804b6a2021-02-15 21:23:06 +08001217 fail_cnt = fih_int_encode(fih_int_decode(fail_cnt) + 1);
Mingyang Sunda01a972019-07-12 17:32:59 +08001218 }
1219 }
1220 }
1221
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001222 tfm_spm_secure_api_init_done();
Mingyang Sunda01a972019-07-12 17:32:59 +08001223
David Hu9804b6a2021-02-15 21:23:06 +08001224 fih_int_validate(fail_cnt);
1225 if (fih_eq(fail_cnt, fih_int_encode(0))) {
1226 FIH_RET(fih_int_encode(SPM_ERR_OK));
Mingyang Sunda01a972019-07-12 17:32:59 +08001227 }
David Hu9804b6a2021-02-15 21:23:06 +08001228
1229 FIH_RET(fih_int_encode(SPM_ERR_PARTITION_NOT_AVAILABLE));
Mingyang Sunda01a972019-07-12 17:32:59 +08001230}
1231
1232void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
1233{
1234 struct spm_partition_runtime_data_t *runtime_data =
1235 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1236 struct interrupted_ctx_stack_frame_t *stack_frame =
Edison Ai7aff9e82019-07-11 14:56:46 +08001237 (struct interrupted_ctx_stack_frame_t *)runtime_data->ctx_stack_ptr;
Mingyang Sunda01a972019-07-12 17:32:59 +08001238
1239 stack_frame->partition_state = runtime_data->partition_state;
Matt463ed582019-12-20 12:31:25 +08001240
1241 runtime_data->ctx_stack_ptr +=
1242 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
Mingyang Sunda01a972019-07-12 17:32:59 +08001243}
1244
1245void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
1246{
1247 struct spm_partition_runtime_data_t *runtime_data =
1248 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1249 struct interrupted_ctx_stack_frame_t *stack_frame;
1250
Matt463ed582019-12-20 12:31:25 +08001251 runtime_data->ctx_stack_ptr -=
1252 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
1253
Mingyang Sunda01a972019-07-12 17:32:59 +08001254 stack_frame = (struct interrupted_ctx_stack_frame_t *)
1255 runtime_data->ctx_stack_ptr;
1256 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1257 stack_frame->partition_state = 0;
Mingyang Sunda01a972019-07-12 17:32:59 +08001258}
1259
1260void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
1261{
1262 struct spm_partition_runtime_data_t *runtime_data =
1263 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1264 struct handler_ctx_stack_frame_t *stack_frame =
1265 (struct handler_ctx_stack_frame_t *)
1266 runtime_data->ctx_stack_ptr;
1267
1268 stack_frame->partition_state = runtime_data->partition_state;
1269 stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
1270
1271 runtime_data->ctx_stack_ptr +=
1272 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1273}
1274
1275void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
1276{
1277 struct spm_partition_runtime_data_t *runtime_data =
1278 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1279 struct handler_ctx_stack_frame_t *stack_frame;
1280
1281 runtime_data->ctx_stack_ptr -=
1282 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1283
1284 stack_frame = (struct handler_ctx_stack_frame_t *)
1285 runtime_data->ctx_stack_ptr;
1286
1287 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1288 stack_frame->partition_state = 0;
1289 tfm_spm_partition_set_caller_partition_idx(
1290 partition_idx, stack_frame->caller_partition_idx);
1291 stack_frame->caller_partition_idx = 0;
1292}
1293
Mingyang Sunda01a972019-07-12 17:32:59 +08001294void tfm_spm_partition_store_context(uint32_t partition_idx,
1295 uint32_t stack_ptr, uint32_t lr)
1296{
1297 g_spm_partition_db.partitions[partition_idx].
1298 runtime_data.stack_ptr = stack_ptr;
1299 g_spm_partition_db.partitions[partition_idx].
1300 runtime_data.lr = lr;
1301}
1302
1303const struct spm_partition_runtime_data_t *
1304 tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
1305{
1306 return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
1307}
1308
1309void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
1310{
1311 g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
1312 state;
1313 if (state == SPM_PARTITION_STATE_RUNNING ||
1314 state == SPM_PARTITION_STATE_HANDLING_IRQ) {
1315 g_spm_partition_db.running_partition_idx = partition_idx;
1316 }
1317}
1318
1319void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
1320 uint32_t caller_partition_idx)
1321{
1322 g_spm_partition_db.partitions[partition_idx].runtime_data.
1323 caller_partition_idx = caller_partition_idx;
1324}
1325
1326void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
1327 uint32_t signal_mask)
1328{
1329 g_spm_partition_db.partitions[partition_idx].runtime_data.
1330 signal_mask = signal_mask;
1331}
1332
1333void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
1334 int32_t caller_client_id)
1335{
1336 g_spm_partition_db.partitions[partition_idx].runtime_data.
1337 caller_client_id = caller_client_id;
1338}
1339
Mingyang Sunda01a972019-07-12 17:32:59 +08001340uint32_t tfm_spm_partition_get_running_partition_idx(void)
1341{
1342 return g_spm_partition_db.running_partition_idx;
1343}
1344
1345void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
1346{
1347 struct spm_partition_desc_t *partition =
1348 &(g_spm_partition_db.partitions[partition_idx]);
1349 int32_t i;
1350
1351 partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
Mingyang Sunda01a972019-07-12 17:32:59 +08001352 partition->runtime_data.iovec_args.in_len = 0;
1353 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1354 partition->runtime_data.iovec_args.in_vec[i].base = 0;
1355 partition->runtime_data.iovec_args.in_vec[i].len = 0;
1356 }
1357 partition->runtime_data.iovec_args.out_len = 0;
1358 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1359 partition->runtime_data.iovec_args.out_vec[i].base = 0;
1360 partition->runtime_data.iovec_args.out_vec[i].len = 0;
1361 }
1362 partition->runtime_data.orig_outvec = 0;
Summer Qin423dbef2019-08-22 15:59:35 +08001363}
Summer Qin830c5542020-02-14 13:44:20 +08001364
1365void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
1366{
1367 uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
1368 uint32_t running_partition_flags = 0;
1369 uint32_t running_partition_idx;
1370
1371 /* Check permissions on request type basis */
1372
1373 switch (svc_ctx->r0) {
1374 case TFM_SPM_REQUEST_RESET_VOTE:
1375 running_partition_idx =
1376 tfm_spm_partition_get_running_partition_idx();
1377 running_partition_flags = tfm_spm_partition_get_flags(
1378 running_partition_idx);
1379
1380 /* Currently only PSA Root of Trust services are allowed to make Reset
1381 * vote request
1382 */
1383 if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1384 *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1385 }
1386
1387 /* FixMe: this is a placeholder for checks to be performed before
1388 * allowing execution of reset
1389 */
1390 *res_ptr = (uint32_t)TFM_SUCCESS;
1391
1392 break;
1393 default:
1394 *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1395 }
1396}
Mingyang Sunbd7ceb52020-06-11 16:53:03 +08001397
1398enum spm_err_t tfm_spm_db_init(void)
1399{
1400 uint32_t i;
1401
1402 /* This function initialises partition db */
1403
1404 /* For the non secure Execution environment */
1405 tfm_nspm_configure_clients();
1406
1407 for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1408 g_spm_partition_db.partitions[i].runtime_data.partition_state =
1409 SPM_PARTITION_STATE_UNINIT;
1410 g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
1411 SPM_INVALID_PARTITION_IDX;
1412 g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
1413 TFM_INVALID_CLIENT_ID;
1414 g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
1415 ctx_stack_list[i];
1416 g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
1417 g_spm_partition_db.partitions[i].platform_data_list =
1418 platform_data_list_list[i];
1419 }
1420 g_spm_partition_db.is_init = 1;
1421
1422 return SPM_ERR_OK;
1423}