blob: 4c9101838860872e1239041a83f5ef59cf471474 [file] [log] [blame]
Mingyang Sunda01a972019-07-12 17:32:59 +08001/*
Mingyang Sunabb1aab2020-02-18 13:49:08 +08002 * Copyright (c) 2017-2020, 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>
11#include "tfm_nspm.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080012#include "tfm_api.h"
13#include "tfm_arch.h"
14#include "tfm_irq_list.h"
15#include "psa/service.h"
16#include "tfm_core_mem_check.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080017#include "tfm_peripherals_def.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080018#include "tfm_secure_api.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080019#include "tfm_spm_hal.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080020#include "spm_func.h"
Mingyang Sunda01a972019-07-12 17:32:59 +080021#include "region_defs.h"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080022#include "region.h"
Mingyang Sun7397b4f2020-06-17 15:07:45 +080023#include "spm_partition_defs.h"
24#include "psa_manifest/pid.h"
Summer Qin5fdcf632020-06-22 16:49:24 +080025#include "tfm/tfm_spm_services.h"
Mingyang Sunbd7ceb52020-06-11 16:53:03 +080026#include "tfm_spm_db_func.inc"
Mingyang Sunabb1aab2020-02-18 13:49:08 +080027
28#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
29#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
30
31#ifndef TFM_LVL
32#error TFM_LVL is not defined!
33#endif
34
35REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Base, uint32_t);
36REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Limit, struct iovec_args_t)[];
37
38/*
39 * This is the "Big Lock" on the secure side, to guarantee single entry
40 * to SPE
41 */
Summer Qin5fdcf632020-06-22 16:49:24 +080042static int32_t tfm_secure_lock;
Mingyang Sunabb1aab2020-02-18 13:49:08 +080043static int32_t tfm_secure_api_initializing = 1;
Mingyang Sunda01a972019-07-12 17:32:59 +080044
Mingyang Sunabb1aab2020-02-18 13:49:08 +080045static uint32_t *prepare_partition_iovec_ctx(
46 const struct tfm_state_context_t *svc_ctx,
47 const struct tfm_sfn_req_s *desc_ptr,
48 const struct iovec_args_t *iovec_args,
49 uint32_t *dst)
50{
51 /* XPSR = as was when called, but make sure it's thread mode */
52 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00U;
53 /* ReturnAddress = resume veneer in new context */
54 *(--dst) = svc_ctx->ra;
55 /* LR = sfn address */
56 *(--dst) = (uint32_t)desc_ptr->sfn;
57 /* R12 = don't care */
58 *(--dst) = 0U;
59
60 /* R0-R3 = sfn arguments */
61 *(--dst) = iovec_args->out_len;
62 *(--dst) = (uint32_t)iovec_args->out_vec;
63 *(--dst) = iovec_args->in_len;
64 *(--dst) = (uint32_t)iovec_args->in_vec;
65
66 return dst;
67}
68
69/**
70 * \brief Create a stack frame that sets the execution environment to thread
71 * mode on exception return.
72 *
73 * \param[in] svc_ctx The stacked SVC context
74 * \param[in] unpriv_handler The unprivileged IRQ handler to be called
75 * \param[in] dst A pointer where the context is to be created. (the
76 * pointer is considered to be a stack pointer, and
77 * the frame is created below it)
78 *
79 * \return A pointer pointing at the created stack frame.
80 */
81static int32_t *prepare_partition_irq_ctx(
82 const struct tfm_state_context_t *svc_ctx,
83 sfn_t unpriv_handler,
84 int32_t *dst)
85{
86 int i;
87
88 /* XPSR = as was when called, but make sure it's thread mode */
89 *(--dst) = svc_ctx->xpsr & 0xFFFFFE00;
90 /* ReturnAddress = resume to the privileged handler code, but execute it
91 * unprivileged.
92 */
93 *(--dst) = svc_ctx->ra;
94 /* LR = start address */
95 *(--dst) = (int32_t)unpriv_handler;
96
97 /* R12, R0-R3 unused arguments */
98 for (i = 0; i < 5; ++i) {
99 *(--dst) = 0;
100 }
101
102 return dst;
103}
104
105static void restore_caller_ctx(const struct tfm_state_context_t *svc_ctx,
106 struct tfm_state_context_t *target_ctx)
107{
108 /* ReturnAddress = resume veneer after second SVC */
109 target_ctx->ra = svc_ctx->ra;
110
111 /* R0 = function return value */
112 target_ctx->r0 = svc_ctx->r0;
113
114 return;
115}
116
117/**
118 * \brief Check whether the iovec parameters are valid, and the memory ranges
119 * are in the possession of the calling partition.
120 *
121 * \param[in] desc_ptr The secure function request descriptor
122 *
123 * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
124 * otherwise as in /ref tfm_status_e
125 */
126static enum tfm_status_e tfm_core_check_sfn_parameters(
127 const struct tfm_sfn_req_s *desc_ptr)
128{
129 struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
130 size_t in_len;
131 struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
132 size_t out_len;
133 uint32_t i;
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800134 uint32_t privileged_mode = TFM_PARTITION_UNPRIVILEGED_MODE;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800135
136 if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
137 return TFM_ERROR_INVALID_PARAMETER;
138 }
139
140 in_len = (size_t)(desc_ptr->args[1]);
141 out_len = (size_t)(desc_ptr->args[3]);
142
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800143 /*
144 * Get caller's privileged mode:
145 * The privileged mode of NS Secure Service caller will be decided by the
146 * tfm_core_has_xxx_access_to_region functions.
147 * Secure caller can be only privileged mode because the whole SPE is
148 * running under privileged mode
149 */
150 if (!desc_ptr->ns_caller) {
151 privileged_mode = TFM_PARTITION_PRIVILEGED_MODE;
152 }
153
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800154 /* The number of vectors are within range. Extra checks to avoid overflow */
155 if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
156 (in_len + out_len > PSA_MAX_IOVEC)) {
157 return TFM_ERROR_INVALID_PARAMETER;
158 }
159
160 /* Check whether the caller partition has at write access to the iovec
161 * structures themselves. Use the TT instruction for this.
162 */
163 if (in_len > 0) {
164 if ((in_vec == NULL) ||
165 (tfm_core_has_write_access_to_region(in_vec,
166 sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800167 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800168 return TFM_ERROR_INVALID_PARAMETER;
169 }
170 } else {
171 if (in_vec != NULL) {
172 return TFM_ERROR_INVALID_PARAMETER;
173 }
174 }
175 if (out_len > 0) {
176 if ((out_vec == NULL) ||
177 (tfm_core_has_write_access_to_region(out_vec,
178 sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800179 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800180 return TFM_ERROR_INVALID_PARAMETER;
181 }
182 } else {
183 if (out_vec != NULL) {
184 return TFM_ERROR_INVALID_PARAMETER;
185 }
186 }
187
188 /* Check whether the caller partition has access to the data inside the
189 * iovecs
190 */
191 for (i = 0; i < in_len; ++i) {
192 if (in_vec[i].len > 0) {
193 if ((in_vec[i].base == NULL) ||
194 (tfm_core_has_read_access_to_region(in_vec[i].base,
195 in_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800196 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800197 return TFM_ERROR_INVALID_PARAMETER;
198 }
199 }
200 }
201 for (i = 0; i < out_len; ++i) {
202 if (out_vec[i].len > 0) {
203 if ((out_vec[i].base == NULL) ||
204 (tfm_core_has_write_access_to_region(out_vec[i].base,
205 out_vec[i].len, desc_ptr->ns_caller,
Kevin Peng1f6f5af2020-08-27 15:07:58 +0800206 privileged_mode) != TFM_SUCCESS)) {
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800207 return TFM_ERROR_INVALID_PARAMETER;
208 }
209 }
210 }
211
212 return TFM_SUCCESS;
213}
214
215static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
216 const struct iovec_args_t *source)
217{
218 size_t i;
219
220 /* The vectors have been sanity checked already, and since then the
221 * interrupts have been kept disabled. So we can be sure that the
222 * vectors haven't been tampered with since the check. So it is safe to pass
223 * it to the called partition.
224 */
225
226 target->in_len = source->in_len;
227 for (i = 0; i < source->in_len; ++i) {
228 target->in_vec[i].base = source->in_vec[i].base;
229 target->in_vec[i].len = source->in_vec[i].len;
230 }
231 target->out_len = source->out_len;
232 for (i = 0; i < source->out_len; ++i) {
233 target->out_vec[i].base = source->out_vec[i].base;
234 target->out_vec[i].len = source->out_vec[i].len;
235 }
236}
237
238static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
239{
240 int i;
241
242 args->in_len = 0;
243 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
244 args->in_vec[i].base = NULL;
245 args->in_vec[i].len = 0;
246 }
247 args->out_len = 0;
248 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
249 args->out_vec[i].base = NULL;
250 args->out_vec[i].len = 0;
251 }
252}
253
254/**
255 * \brief Check whether the partitions for the secure function call are in a
256 * proper state.
257 *
258 * \param[in] curr_partition_state State of the partition to be called
259 * \param[in] caller_partition_state State of the caller partition
260 *
261 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
262 */
263static enum tfm_status_e check_partition_state(uint32_t curr_partition_state,
264 uint32_t caller_partition_state)
265{
266 if (caller_partition_state != SPM_PARTITION_STATE_RUNNING) {
267 /* Calling partition from non-running state (e.g. during handling IRQ)
268 * is not allowed.
269 */
270 return TFM_ERROR_INVALID_EXC_MODE;
271 }
272
273 if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
274 curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
275 curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
276 curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
277 /* Active partitions cannot be called! */
278 return TFM_ERROR_PARTITION_NON_REENTRANT;
279 } else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
280 /* The partition to be called is not in a proper state */
281 return TFM_SECURE_LOCK_FAILED;
282 }
283 return TFM_SUCCESS;
284}
285
286/**
287 * \brief Check whether the partitions for the secure function call of irq are
288 * in a proper state.
289 *
290 * \param[in] called_partition_state State of the partition to be called
291 *
292 * \return \ref TFM_SUCCESS if the check passes, error otherwise.
293 */
294static enum tfm_status_e check_irq_partition_state(
295 uint32_t called_partition_state)
296{
297 if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
298 called_partition_state == SPM_PARTITION_STATE_RUNNING ||
299 called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
300 called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
301 called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
302 return TFM_SUCCESS;
303 }
304 return TFM_SECURE_LOCK_FAILED;
305}
306
307/**
308 * \brief Calculate the address where the iovec parameters are to be saved for
309 * the called partition.
310 *
311 * \param[in] partition_idx The index of the partition to be called.
312 *
313 * \return The address where the iovec parameters should be saved.
314 */
315static struct iovec_args_t *get_iovec_args_stack_address(uint32_t partition_idx)
316{
317 /* Save the iovecs on the common stack. */
TTornblom99f0be22019-12-17 16:22:38 +0100318 return &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800319}
320
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800321/**
322 * \brief Returns the index of the partition with the given partition ID.
323 *
324 * \param[in] partition_id Partition id
325 *
326 * \return the partition idx if partition_id is valid,
327 * \ref SPM_INVALID_PARTITION_IDX othervise
328 */
329static uint32_t get_partition_idx(uint32_t partition_id)
330{
331 uint32_t i;
332
333 if (partition_id == INVALID_PARTITION_ID) {
334 return SPM_INVALID_PARTITION_IDX;
335 }
336
337 for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
338 if (g_spm_partition_db.partitions[i].static_data->partition_id ==
339 partition_id) {
340 return i;
341 }
342 }
343 return SPM_INVALID_PARTITION_IDX;
344}
345
346/**
347 * \brief Get the flags associated with a partition
348 *
349 * \param[in] partition_idx Partition index
350 *
351 * \return Flags associated with the partition
352 *
353 * \note This function doesn't check if partition_idx is valid.
354 */
355static uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
356{
357 return g_spm_partition_db.partitions[partition_idx].static_data->
358 partition_flags;
359}
360
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800361static enum tfm_status_e tfm_start_partition(
362 const struct tfm_sfn_req_s *desc_ptr,
363 uint32_t excReturn)
364{
365 enum tfm_status_e res;
366 uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
367 const struct spm_partition_runtime_data_t *curr_part_data;
368 const struct spm_partition_runtime_data_t *caller_part_data;
369 uint32_t caller_flags;
370 register uint32_t partition_idx;
371 uint32_t psp;
372 uint32_t partition_psp, partition_psplim;
373 uint32_t partition_state;
374 uint32_t caller_partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800375 struct tfm_state_context_t *svc_ctx;
376 uint32_t caller_partition_id;
377 int32_t client_id;
378 struct iovec_args_t *iovec_args;
379
380 psp = __get_PSP();
381 svc_ctx = (struct tfm_state_context_t *)psp;
382 caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
383
384 /* Check partition state consistency */
385 if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
386 != (!desc_ptr->ns_caller)) {
387 /* Partition state inconsistency detected */
388 return TFM_SECURE_LOCK_FAILED;
389 }
390
391 partition_idx = get_partition_idx(desc_ptr->sp_id);
392
393 curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
394 caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
395 partition_state = curr_part_data->partition_state;
396 caller_partition_state = caller_part_data->partition_state;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800397 caller_partition_id = tfm_spm_partition_get_partition_id(
398 caller_partition_idx);
399
400 if (!tfm_secure_api_initializing) {
401 res = check_partition_state(partition_state, caller_partition_state);
402 if (res != TFM_SUCCESS) {
403 return res;
404 }
405 }
406
407 /* Prepare switch to shared secure partition stack */
408 /* In case the call is coming from the non-secure world, we save the iovecs
409 * on the stop of the stack. So the memory area, that can actually be used
410 * as stack by the partitions starts at a lower address
411 */
412 partition_psp =
TTornblom99f0be22019-12-17 16:22:38 +0100413 (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800414 partition_psplim =
415 (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
416
417 /* Store the context for the partition call */
418 tfm_spm_partition_set_caller_partition_idx(partition_idx,
419 caller_partition_idx);
420 tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
421
422 if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
423 tfm_spm_partition_set_caller_client_id(partition_idx,
424 caller_partition_id);
425 } else {
426 client_id = tfm_nspm_get_current_client_id();
427 if (client_id >= 0) {
428 return TFM_SECURE_LOCK_FAILED;
429 }
430 tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
431 }
432
433 /* In level one, only switch context and return from exception if in
434 * handler mode
435 */
436 if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
437 if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
438 SPM_ERR_OK) {
439 return TFM_ERROR_GENERIC;
440 }
441 iovec_args = get_iovec_args_stack_address(partition_idx);
442 tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
443
444 /* Prepare the partition context, update stack ptr */
445 psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
446 iovec_args,
447 (uint32_t *)partition_psp);
448 __set_PSP(psp);
449 tfm_arch_set_psplim(partition_psplim);
450 }
451
452 tfm_spm_partition_set_state(caller_partition_idx,
453 SPM_PARTITION_STATE_BLOCKED);
454 tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
455 tfm_secure_lock++;
456
457 return TFM_SUCCESS;
458}
459
460static enum tfm_status_e tfm_start_partition_for_irq_handling(
461 uint32_t excReturn,
462 struct tfm_state_context_t *svc_ctx)
463{
464 uint32_t handler_partition_id = svc_ctx->r0;
465 sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
466 uint32_t irq_signal = svc_ctx->r2;
TTornblomfaf74f52020-03-04 17:56:27 +0100467 IRQn_Type irq_line = (IRQn_Type) svc_ctx->r3;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800468 enum tfm_status_e res;
469 uint32_t psp = __get_PSP();
470 uint32_t handler_partition_psp;
471 uint32_t handler_partition_state;
472 uint32_t interrupted_partition_idx =
473 tfm_spm_partition_get_running_partition_idx();
474 const struct spm_partition_runtime_data_t *handler_part_data;
475 uint32_t handler_partition_idx;
476
477 handler_partition_idx = get_partition_idx(handler_partition_id);
478 handler_part_data = tfm_spm_partition_get_runtime_data(
479 handler_partition_idx);
480 handler_partition_state = handler_part_data->partition_state;
481
482 res = check_irq_partition_state(handler_partition_state);
483 if (res != TFM_SUCCESS) {
484 return res;
485 }
486
487 /* set mask for the partition */
488 tfm_spm_partition_set_signal_mask(
489 handler_partition_idx,
490 handler_part_data->signal_mask | irq_signal);
491
492 tfm_spm_hal_disable_irq(irq_line);
493
494 /* save the current context of the interrupted partition */
495 tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
496
497 handler_partition_psp = psp;
498
499 /* save the current context of the handler partition */
500 tfm_spm_partition_push_handler_ctx(handler_partition_idx);
501
502 /* Store caller for the partition */
503 tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
504 interrupted_partition_idx);
505
506 psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
507 (int32_t *)handler_partition_psp);
508 __set_PSP(psp);
509
510 tfm_spm_partition_set_state(interrupted_partition_idx,
511 SPM_PARTITION_STATE_SUSPENDED);
512 tfm_spm_partition_set_state(handler_partition_idx,
513 SPM_PARTITION_STATE_HANDLING_IRQ);
514
515 return TFM_SUCCESS;
516}
517
518static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
519{
520 uint32_t current_partition_idx =
521 tfm_spm_partition_get_running_partition_idx();
522 const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800523 uint32_t return_partition_idx;
524 uint32_t return_partition_flags;
525 uint32_t psp = __get_PSP();
526 size_t i;
527 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
528 struct iovec_args_t *iovec_args;
529
530 if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
531 return TFM_SECURE_UNLOCK_FAILED;
532 }
533
534 curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
535 return_partition_idx = curr_part_data->caller_partition_idx;
536
537 if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
538 return TFM_SECURE_UNLOCK_FAILED;
539 }
540
541 ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
542
543 return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800544
545 tfm_secure_lock--;
546
547 if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
548 (tfm_secure_api_initializing)) {
549 /* In TFM level 1 context restore is only done when
550 * returning to NS or after initialization
551 */
552 /* Restore caller context */
553 restore_caller_ctx(svc_ctx,
554 (struct tfm_state_context_t *)ret_part_data->stack_ptr);
555 *excReturn = ret_part_data->lr;
556 __set_PSP(ret_part_data->stack_ptr);
TTornblom99f0be22019-12-17 16:22:38 +0100557 REGION_DECLARE_T(Image$$, ARM_LIB_STACK, $$ZI$$Base, uint32_t)[];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800558 uint32_t psp_stack_bottom =
559 (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
560 tfm_arch_set_psplim(psp_stack_bottom);
561
TTornblom99f0be22019-12-17 16:22:38 +0100562 iovec_args = &REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)[-1];
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800563
564 for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
565 curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
566 }
567 tfm_clear_iovec_parameters(iovec_args);
568 }
569
570 tfm_spm_partition_cleanup_context(current_partition_idx);
571
572 tfm_spm_partition_set_state(current_partition_idx,
573 SPM_PARTITION_STATE_IDLE);
574 tfm_spm_partition_set_state(return_partition_idx,
575 SPM_PARTITION_STATE_RUNNING);
576
577 return TFM_SUCCESS;
578}
579
580static enum tfm_status_e tfm_return_from_partition_irq_handling(
581 uint32_t *excReturn)
582{
583 uint32_t handler_partition_idx =
584 tfm_spm_partition_get_running_partition_idx();
585 const struct spm_partition_runtime_data_t *handler_part_data;
586 uint32_t interrupted_partition_idx;
587 uint32_t psp = __get_PSP();
588 struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
589
590 if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
591 return TFM_SECURE_UNLOCK_FAILED;
592 }
593
594 handler_part_data = tfm_spm_partition_get_runtime_data(
595 handler_partition_idx);
596 interrupted_partition_idx = handler_part_data->caller_partition_idx;
597
598 if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
599 return TFM_SECURE_UNLOCK_FAILED;
600 }
601
602 /* For level 1, modify PSP, so that the SVC stack frame disappears,
603 * and return to the privileged handler using the stack frame still on the
604 * MSP stack.
605 */
606 *excReturn = svc_ctx->ra;
607 psp += sizeof(struct tfm_state_context_t);
608
609 tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
610 tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
611
612 __set_PSP(psp);
613
614 return TFM_SUCCESS;
615}
616
617static enum tfm_status_e tfm_check_sfn_req_integrity(
618 const struct tfm_sfn_req_s *desc_ptr)
619{
620 if ((desc_ptr == NULL) ||
621 (desc_ptr->sp_id == 0) ||
622 (desc_ptr->sfn == NULL)) {
623 /* invalid parameter */
624 return TFM_ERROR_INVALID_PARAMETER;
625 }
626 return TFM_SUCCESS;
627}
628
629static enum tfm_status_e tfm_core_check_sfn_req_rules(
630 const struct tfm_sfn_req_s *desc_ptr)
631{
632 /* Check partition idx validity */
633 if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
634 return TFM_ERROR_NO_ACTIVE_PARTITION;
635 }
636
637 if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
638 /* Secure domain is already locked!
639 * This should only happen if caller is secure partition!
640 */
641 /* This scenario is a potential security breach.
642 * Error is handled in caller.
643 */
644 return TFM_ERROR_SECURE_DOMAIN_LOCKED;
645 }
646
647 if (tfm_secure_api_initializing) {
648 int32_t id =
649 tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
650
651 if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
652 /* Invalid request during system initialization */
653 ERROR_MSG("Invalid service request during initialization!");
654 return TFM_ERROR_NOT_INITIALIZED;
655 }
656 }
657
658 return TFM_SUCCESS;
659}
660
Mingyang Sunda30f1e2020-07-13 17:20:32 +0800661uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
662{
663 return g_spm_partition_db.partitions[partition_idx].static_data->
664 partition_id;
665}
666
667uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
668{
669 if (partition_flags & SPM_PART_FLAG_PSA_ROT) {
670 return TFM_PARTITION_PRIVILEGED_MODE;
671 } else {
672 return TFM_PARTITION_UNPRIVILEGED_MODE;
673 }
674}
675
676bool tfm_is_partition_privileged(uint32_t partition_idx)
677{
678 uint32_t flags = tfm_spm_partition_get_flags(partition_idx);
679
680 return tfm_spm_partition_get_privileged_mode(flags) ==
681 TFM_PARTITION_PRIVILEGED_MODE;
682}
683
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800684void tfm_spm_secure_api_init_done(void)
685{
686 tfm_secure_api_initializing = 0;
687}
688
689enum tfm_status_e tfm_spm_sfn_request_handler(
690 struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
691{
692 enum tfm_status_e res;
693
694 res = tfm_check_sfn_req_integrity(desc_ptr);
695 if (res != TFM_SUCCESS) {
696 ERROR_MSG("Invalid service request!");
697 tfm_secure_api_error_handler();
698 }
699
700 __disable_irq();
701
702 desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
703
704 res = tfm_core_check_sfn_parameters(desc_ptr);
705 if (res != TFM_SUCCESS) {
706 /* The sanity check of iovecs failed. */
707 __enable_irq();
708 tfm_secure_api_error_handler();
709 }
710
711 res = tfm_core_check_sfn_req_rules(desc_ptr);
712 if (res != TFM_SUCCESS) {
713 /* FixMe: error compartmentalization TBD */
714 tfm_spm_partition_set_state(
715 desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
716 __enable_irq();
717 ERROR_MSG("Unauthorized service request!");
718 tfm_secure_api_error_handler();
719 }
720
721 res = tfm_start_partition(desc_ptr, excReturn);
722 if (res != TFM_SUCCESS) {
723 /* FixMe: consider possible fault scenarios */
724 __enable_irq();
725 ERROR_MSG("Failed to process service request!");
726 tfm_secure_api_error_handler();
727 }
728
729 __enable_irq();
730
731 return res;
732}
733
734int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
735{
736 enum tfm_status_e res;
737 int32_t *args;
738 int32_t retVal;
739
740 res = tfm_core_check_sfn_parameters(desc_ptr);
741 if (res != TFM_SUCCESS) {
742 /* The sanity check of iovecs failed. */
743 return (int32_t)res;
744 }
745
746 /* No excReturn value is needed as no exception handling is used */
747 res = tfm_spm_sfn_request_handler(desc_ptr, 0);
748
749 if (res != TFM_SUCCESS) {
750 tfm_secure_api_error_handler();
751 }
752
753 /* Secure partition to secure partition call in TFM level 1 */
754 args = desc_ptr->args;
755 retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
756
757 /* return handler should restore original exc_return value... */
758 res = tfm_return_from_partition(NULL);
759 if (res == TFM_SUCCESS) {
760 /* If unlock successful, pass SS return value to caller */
761 return retVal;
762 } else {
763 /* Unlock errors indicate ctx database corruption or unknown
764 * anomalies. Halt execution
765 */
766 ERROR_MSG("Secure API error during unlock!");
767 tfm_secure_api_error_handler();
768 }
769 return (int32_t)res;
770}
771
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800772int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
773 void *start_addr,
774 size_t len,
775 uint32_t alignment)
776{
777 uintptr_t start_addr_value = (uintptr_t)start_addr;
778 uintptr_t end_addr_value = (uintptr_t)start_addr + len;
779 uintptr_t alignment_mask;
780
781 alignment_mask = (((uintptr_t)1) << alignment) - 1;
782
783 /* Check that the pointer is aligned properly */
784 if (start_addr_value & alignment_mask) {
785 /* not aligned, return error */
786 return 0;
787 }
788
789 /* Protect against overflow (and zero len) */
790 if (end_addr_value <= start_addr_value) {
791 return 0;
792 }
793
794 /* For privileged partition execution, all secure data memory and stack
795 * is accessible
796 */
797 if (start_addr_value >= S_DATA_START &&
798 end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
799 return 1;
800 }
801
802 return 0;
803}
804
805void tfm_spm_get_caller_client_id_handler(uint32_t *svc_args)
806{
807 uintptr_t result_ptr_value = svc_args[0];
808 uint32_t running_partition_idx =
809 tfm_spm_partition_get_running_partition_idx();
810 const uint32_t running_partition_flags =
811 tfm_spm_partition_get_flags(running_partition_idx);
812 const struct spm_partition_runtime_data_t *curr_part_data =
813 tfm_spm_partition_get_runtime_data(running_partition_idx);
814 int res = 0;
815
816 if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
817 curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
818 curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
819 /* This handler shouldn't be called from outside partition context.
820 * Also if the current partition is handling IRQ, the caller partition
821 * index might not be valid;
822 * Partitions are only allowed to run while S domain is locked.
823 */
824 svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
825 return;
826 }
827
828 /* Make sure that the output pointer points to a memory area that is owned
829 * by the partition
830 */
831 res = tfm_spm_check_buffer_access(running_partition_idx,
832 (void *)result_ptr_value,
833 sizeof(curr_part_data->caller_client_id),
834 2);
835 if (!res) {
836 /* Not in accessible range, return error */
837 svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
838 return;
839 }
840
841 *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
842
843 /* Store return value in r0 */
844 svc_args[0] = (uint32_t)TFM_SUCCESS;
845}
846
847/* This SVC handler is called if veneer is running in thread mode */
848uint32_t tfm_spm_partition_request_svc_handler(
849 const uint32_t *svc_ctx, uint32_t excReturn)
850{
851 struct tfm_sfn_req_s *desc_ptr;
852
853 if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
854 /* Service request SVC called with MSP active.
855 * Either invalid configuration for Thread mode or SVC called
856 * from Handler mode, which is not supported.
857 * FixMe: error severity TBD
858 */
859 ERROR_MSG("Service request SVC called with MSP active!");
860 tfm_secure_api_error_handler();
861 }
862
863 desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
864
865 if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
866 tfm_secure_api_error_handler();
867 }
868
869 return EXC_RETURN_SECURE_FUNCTION;
870}
871
872/* This SVC handler is called, if a thread mode execution environment is to
873 * be set up, to run an unprivileged IRQ handler
874 */
875uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
876{
877 struct tfm_state_context_t *svc_ctx =
878 (struct tfm_state_context_t *)svc_args;
879
880 enum tfm_status_e res;
881
882 if (excReturn & EXC_RETURN_STACK_PROCESS) {
883 /* FixMe: error severity TBD */
884 ERROR_MSG("Partition request SVC called with PSP active!");
885 tfm_secure_api_error_handler();
886 }
887
888 res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
889 if (res != TFM_SUCCESS) {
890 /* The partition is in an invalid state (UNINIT or CLOSED), so none of
891 * its code can be run
892 */
893 /* FixMe: For now this case is handled with TF-M panic, however it would
894 * be possible to skip the execution of the interrupt handler, and
895 * resume the execution of the interrupted code.
896 */
897 tfm_secure_api_error_handler();
898 }
899 return EXC_RETURN_SECURE_FUNCTION;
900}
901
902/* This SVC handler is called when sfn returns */
903uint32_t tfm_spm_partition_return_handler(uint32_t lr)
904{
905 enum tfm_status_e res;
906
907 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
908 /* Partition return SVC called with MSP active.
909 * This should not happen!
910 */
911 ERROR_MSG("Partition return SVC called with MSP active!");
912 tfm_secure_api_error_handler();
913 }
914
915 res = tfm_return_from_partition(&lr);
916 if (res != TFM_SUCCESS) {
917 /* Unlock errors indicate ctx database corruption or unknown anomalies
918 * Halt execution
919 */
920 ERROR_MSG("Secure API error during unlock!");
921 tfm_secure_api_error_handler();
922 }
923
924 return lr;
925}
926
927/* This SVC handler is called if a deprivileged IRQ handler was executed, and
928 * the execution environment is to be set back for the privileged handler mode
929 */
930uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
931{
932 enum tfm_status_e res;
933 struct tfm_state_context_t *irq_svc_ctx =
934 (struct tfm_state_context_t *)irq_svc_args;
935
936 if (!(lr & EXC_RETURN_STACK_PROCESS)) {
937 /* Partition request SVC called with MSP active.
938 * FixMe: error severity TBD
939 */
940 ERROR_MSG("Partition request SVC called with MSP active!");
941 tfm_secure_api_error_handler();
942 }
943
944 res = tfm_return_from_partition_irq_handling(&lr);
945 if (res != TFM_SUCCESS) {
946 /* Unlock errors indicate ctx database corruption or unknown anomalies
947 * Halt execution
948 */
949 ERROR_MSG("Secure API error during unlock!");
950 tfm_secure_api_error_handler();
951 }
952
953 irq_svc_ctx->ra = lr;
954
955 return EXC_RETURN_SECURE_HANDLER;
956}
957
958/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
959/**
960 * \brief Return the IRQ line number associated with a signal
961 *
962 * \param[in] partition_id The ID of the partition in which we look for the
963 * signal
964 * \param[in] signal The signal we do the query for
965 *
966 * \retval >=0 The IRQ line number associated with a signal in the partition
967 * \retval <0 error
968 */
TTornblomfaf74f52020-03-04 17:56:27 +0100969static IRQn_Type get_irq_line_for_signal(int32_t partition_id,
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800970 psa_signal_t signal)
971{
972 size_t i;
973
974 for (i = 0; i < tfm_core_irq_signals_count; ++i) {
975 if (tfm_core_irq_signals[i].partition_id == partition_id &&
976 tfm_core_irq_signals[i].signal_value == signal) {
977 return tfm_core_irq_signals[i].irq_line;
978 }
979 }
TTornblomfaf74f52020-03-04 17:56:27 +0100980 return (IRQn_Type) -1;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800981}
982
983void tfm_spm_enable_irq_handler(uint32_t *svc_args)
984{
985 struct tfm_state_context_t *svc_ctx =
986 (struct tfm_state_context_t *)svc_args;
987 psa_signal_t irq_signal = svc_ctx->r0;
988 uint32_t running_partition_idx =
989 tfm_spm_partition_get_running_partition_idx();
990 uint32_t running_partition_id =
991 tfm_spm_partition_get_partition_id(running_partition_idx);
TTornblomfaf74f52020-03-04 17:56:27 +0100992 IRQn_Type irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +0800993
994 /* Only a single signal is allowed */
995 if (!tfm_is_one_bit_set(irq_signal)) {
996 /* FixMe: error severity TBD */
997 tfm_secure_api_error_handler();
998 }
999
1000 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1001
1002 if (irq_line < 0) {
1003 /* FixMe: error severity TBD */
1004 tfm_secure_api_error_handler();
1005 }
1006
1007 tfm_spm_hal_enable_irq(irq_line);
1008}
1009
1010void tfm_spm_disable_irq_handler(uint32_t *svc_args)
1011{
1012 struct tfm_state_context_t *svc_ctx =
1013 (struct tfm_state_context_t *)svc_args;
1014 psa_signal_t irq_signal = svc_ctx->r0;
1015 uint32_t running_partition_idx =
1016 tfm_spm_partition_get_running_partition_idx();
1017 uint32_t running_partition_id =
1018 tfm_spm_partition_get_partition_id(running_partition_idx);
TTornblomfaf74f52020-03-04 17:56:27 +01001019 IRQn_Type irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001020
1021 /* Only a single signal is allowed */
1022 if (!tfm_is_one_bit_set(irq_signal)) {
1023 /* FixMe: error severity TBD */
1024 tfm_secure_api_error_handler();
1025 }
1026
1027 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1028
1029 if (irq_line < 0) {
1030 /* FixMe: error severity TBD */
1031 tfm_secure_api_error_handler();
1032 }
1033
1034 tfm_spm_hal_disable_irq(irq_line);
1035}
1036
1037void tfm_spm_psa_wait(uint32_t *svc_args)
1038{
1039 /* Look for partition that is ready for run */
1040 struct tfm_state_context_t *svc_ctx =
1041 (struct tfm_state_context_t *)svc_args;
1042 uint32_t running_partition_idx;
1043 const struct spm_partition_runtime_data_t *curr_part_data;
1044
1045 psa_signal_t signal_mask = svc_ctx->r0;
1046 uint32_t timeout = svc_ctx->r1;
1047
1048 /*
1049 * Timeout[30:0] are reserved for future use.
1050 * SPM must ignore the value of RES.
1051 */
1052 timeout &= PSA_TIMEOUT_MASK;
1053
1054 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1055 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1056
1057 if (timeout == PSA_BLOCK) {
1058 /* FIXME: Scheduling is not available in library model, and busy wait is
1059 * also not possible as this code is running in SVC context, and it
1060 * cannot be pre-empted by interrupts. So do nothing here for now
1061 */
1062 (void) signal_mask;
1063 }
1064
1065 svc_ctx->r0 = curr_part_data->signal_mask;
1066}
1067
1068void tfm_spm_psa_eoi(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 signal_mask;
1074 uint32_t running_partition_idx;
1075 uint32_t running_partition_id;
1076 const struct spm_partition_runtime_data_t *curr_part_data;
TTornblomfaf74f52020-03-04 17:56:27 +01001077 IRQn_Type irq_line;
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001078
1079 running_partition_idx = tfm_spm_partition_get_running_partition_idx();
1080 running_partition_id =
1081 tfm_spm_partition_get_partition_id(running_partition_idx);
1082 curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
1083
1084 /* Only a single signal is allowed */
1085 if (!tfm_is_one_bit_set(irq_signal)) {
1086 tfm_secure_api_error_handler();
1087 }
1088
1089 irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
1090
1091 if (irq_line < 0) {
1092 /* FixMe: error severity TBD */
1093 tfm_secure_api_error_handler();
1094 }
1095
1096 tfm_spm_hal_clear_pending_irq(irq_line);
1097 tfm_spm_hal_enable_irq(irq_line);
1098
1099 signal_mask = curr_part_data->signal_mask & ~irq_signal;
1100 tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
1101}
Mingyang Sunda01a972019-07-12 17:32:59 +08001102
1103/*
1104 * This function is called when a secure partition causes an error.
1105 * In case of an error in the error handling, a non-zero value have to be
1106 * returned.
1107 */
1108static void tfm_spm_partition_err_handler(
1109 const struct spm_partition_desc_t *partition,
Mingyang Sunda01a972019-07-12 17:32:59 +08001110 int32_t err_code)
1111{
Mingyang Sunda01a972019-07-12 17:32:59 +08001112 (void)err_code;
Ken Liuf250b8b2019-12-27 16:31:24 +08001113
Summer Qin423dbef2019-08-22 15:59:35 +08001114 tfm_spm_partition_set_state(partition->static_data->partition_id,
Mingyang Sunda01a972019-07-12 17:32:59 +08001115 SPM_PARTITION_STATE_CLOSED);
1116}
1117
1118enum spm_err_t tfm_spm_partition_init(void)
1119{
1120 struct spm_partition_desc_t *part;
1121 struct tfm_sfn_req_s desc;
1122 int32_t args[4] = {0};
1123 int32_t fail_cnt = 0;
1124 uint32_t idx;
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001125 const struct tfm_spm_partition_platform_data_t **platform_data_p;
Mingyang Sunda01a972019-07-12 17:32:59 +08001126
1127 /* Call the init function for each partition */
1128 for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
1129 part = &g_spm_partition_db.partitions[idx];
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001130 platform_data_p = part->platform_data_list;
1131 if (platform_data_p != NULL) {
1132 while ((*platform_data_p) != NULL) {
Edison Ai6be3df12020-02-14 22:14:33 +08001133 if (tfm_spm_hal_configure_default_isolation(idx,
1134 *platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
1135 fail_cnt++;
1136 }
Mate Toth-Pal8ac98a72019-11-21 17:30:10 +01001137 ++platform_data_p;
1138 }
1139 }
Summer Qin423dbef2019-08-22 15:59:35 +08001140 if (part->static_data->partition_init == NULL) {
Mingyang Sunda01a972019-07-12 17:32:59 +08001141 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1142 tfm_spm_partition_set_caller_partition_idx(idx,
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001143 SPM_INVALID_PARTITION_IDX);
Mingyang Sunda01a972019-07-12 17:32:59 +08001144 } else {
1145 int32_t res;
1146
1147 desc.args = args;
Summer Qin43c185d2019-10-10 15:44:42 +08001148 desc.ns_caller = false;
Summer Qin423dbef2019-08-22 15:59:35 +08001149 desc.sfn = (sfn_t)part->static_data->partition_init;
1150 desc.sp_id = part->static_data->partition_id;
Mingyang Sunda01a972019-07-12 17:32:59 +08001151 res = tfm_core_sfn_request(&desc);
1152 if (res == TFM_SUCCESS) {
1153 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
1154 } else {
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001155 tfm_spm_partition_err_handler(part, res);
Mingyang Sunda01a972019-07-12 17:32:59 +08001156 fail_cnt++;
1157 }
1158 }
1159 }
1160
Mingyang Sunabb1aab2020-02-18 13:49:08 +08001161 tfm_spm_secure_api_init_done();
Mingyang Sunda01a972019-07-12 17:32:59 +08001162
1163 if (fail_cnt == 0) {
1164 return SPM_ERR_OK;
1165 } else {
1166 return SPM_ERR_PARTITION_NOT_AVAILABLE;
1167 }
1168}
1169
1170void tfm_spm_partition_push_interrupted_ctx(uint32_t partition_idx)
1171{
1172 struct spm_partition_runtime_data_t *runtime_data =
1173 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1174 struct interrupted_ctx_stack_frame_t *stack_frame =
Edison Ai7aff9e82019-07-11 14:56:46 +08001175 (struct interrupted_ctx_stack_frame_t *)runtime_data->ctx_stack_ptr;
Mingyang Sunda01a972019-07-12 17:32:59 +08001176
1177 stack_frame->partition_state = runtime_data->partition_state;
Matt463ed582019-12-20 12:31:25 +08001178
1179 runtime_data->ctx_stack_ptr +=
1180 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
Mingyang Sunda01a972019-07-12 17:32:59 +08001181}
1182
1183void tfm_spm_partition_pop_interrupted_ctx(uint32_t partition_idx)
1184{
1185 struct spm_partition_runtime_data_t *runtime_data =
1186 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1187 struct interrupted_ctx_stack_frame_t *stack_frame;
1188
Matt463ed582019-12-20 12:31:25 +08001189 runtime_data->ctx_stack_ptr -=
1190 sizeof(struct interrupted_ctx_stack_frame_t) / sizeof(uint32_t);
1191
Mingyang Sunda01a972019-07-12 17:32:59 +08001192 stack_frame = (struct interrupted_ctx_stack_frame_t *)
1193 runtime_data->ctx_stack_ptr;
1194 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1195 stack_frame->partition_state = 0;
Mingyang Sunda01a972019-07-12 17:32:59 +08001196}
1197
1198void tfm_spm_partition_push_handler_ctx(uint32_t partition_idx)
1199{
1200 struct spm_partition_runtime_data_t *runtime_data =
1201 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1202 struct handler_ctx_stack_frame_t *stack_frame =
1203 (struct handler_ctx_stack_frame_t *)
1204 runtime_data->ctx_stack_ptr;
1205
1206 stack_frame->partition_state = runtime_data->partition_state;
1207 stack_frame->caller_partition_idx = runtime_data->caller_partition_idx;
1208
1209 runtime_data->ctx_stack_ptr +=
1210 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1211}
1212
1213void tfm_spm_partition_pop_handler_ctx(uint32_t partition_idx)
1214{
1215 struct spm_partition_runtime_data_t *runtime_data =
1216 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1217 struct handler_ctx_stack_frame_t *stack_frame;
1218
1219 runtime_data->ctx_stack_ptr -=
1220 sizeof(struct handler_ctx_stack_frame_t) / sizeof(uint32_t);
1221
1222 stack_frame = (struct handler_ctx_stack_frame_t *)
1223 runtime_data->ctx_stack_ptr;
1224
1225 tfm_spm_partition_set_state(partition_idx, stack_frame->partition_state);
1226 stack_frame->partition_state = 0;
1227 tfm_spm_partition_set_caller_partition_idx(
1228 partition_idx, stack_frame->caller_partition_idx);
1229 stack_frame->caller_partition_idx = 0;
1230}
1231
Mingyang Sunda01a972019-07-12 17:32:59 +08001232void tfm_spm_partition_store_context(uint32_t partition_idx,
1233 uint32_t stack_ptr, uint32_t lr)
1234{
1235 g_spm_partition_db.partitions[partition_idx].
1236 runtime_data.stack_ptr = stack_ptr;
1237 g_spm_partition_db.partitions[partition_idx].
1238 runtime_data.lr = lr;
1239}
1240
1241const struct spm_partition_runtime_data_t *
1242 tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
1243{
1244 return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
1245}
1246
1247void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
1248{
1249 g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
1250 state;
1251 if (state == SPM_PARTITION_STATE_RUNNING ||
1252 state == SPM_PARTITION_STATE_HANDLING_IRQ) {
1253 g_spm_partition_db.running_partition_idx = partition_idx;
1254 }
1255}
1256
1257void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
1258 uint32_t caller_partition_idx)
1259{
1260 g_spm_partition_db.partitions[partition_idx].runtime_data.
1261 caller_partition_idx = caller_partition_idx;
1262}
1263
1264void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
1265 uint32_t signal_mask)
1266{
1267 g_spm_partition_db.partitions[partition_idx].runtime_data.
1268 signal_mask = signal_mask;
1269}
1270
1271void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
1272 int32_t caller_client_id)
1273{
1274 g_spm_partition_db.partitions[partition_idx].runtime_data.
1275 caller_client_id = caller_client_id;
1276}
1277
Mingyang Sunda01a972019-07-12 17:32:59 +08001278enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
1279 const int32_t *args)
1280{
1281 struct spm_partition_runtime_data_t *runtime_data =
1282 &g_spm_partition_db.partitions[partition_idx].runtime_data;
1283 size_t i;
1284
1285 if ((args[1] < 0) || (args[3] < 0)) {
1286 return SPM_ERR_INVALID_PARAMETER;
1287 }
1288
1289 runtime_data->iovec_args.in_len = (size_t)args[1];
1290 for (i = 0U; i < runtime_data->iovec_args.in_len; ++i) {
1291 runtime_data->iovec_args.in_vec[i].base =
1292 ((psa_invec *)args[0])[i].base;
1293 runtime_data->iovec_args.in_vec[i].len = ((psa_invec *)args[0])[i].len;
1294 }
1295 runtime_data->iovec_args.out_len = (size_t)args[3];
1296 for (i = 0U; i < runtime_data->iovec_args.out_len; ++i) {
1297 runtime_data->iovec_args.out_vec[i].base =
1298 ((psa_outvec *)args[2])[i].base;
1299 runtime_data->iovec_args.out_vec[i].len =
1300 ((psa_outvec *)args[2])[i].len;
1301 }
1302 runtime_data->orig_outvec = (psa_outvec *)args[2];
Mingyang Sunda01a972019-07-12 17:32:59 +08001303
1304 return SPM_ERR_OK;
1305}
1306
1307uint32_t tfm_spm_partition_get_running_partition_idx(void)
1308{
1309 return g_spm_partition_db.running_partition_idx;
1310}
1311
1312void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
1313{
1314 struct spm_partition_desc_t *partition =
1315 &(g_spm_partition_db.partitions[partition_idx]);
1316 int32_t i;
1317
1318 partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
Mingyang Sunda01a972019-07-12 17:32:59 +08001319 partition->runtime_data.iovec_args.in_len = 0;
1320 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1321 partition->runtime_data.iovec_args.in_vec[i].base = 0;
1322 partition->runtime_data.iovec_args.in_vec[i].len = 0;
1323 }
1324 partition->runtime_data.iovec_args.out_len = 0;
1325 for (i = 0; i < PSA_MAX_IOVEC; ++i) {
1326 partition->runtime_data.iovec_args.out_vec[i].base = 0;
1327 partition->runtime_data.iovec_args.out_vec[i].len = 0;
1328 }
1329 partition->runtime_data.orig_outvec = 0;
Summer Qin423dbef2019-08-22 15:59:35 +08001330}
Summer Qin830c5542020-02-14 13:44:20 +08001331
1332void tfm_spm_request_handler(const struct tfm_state_context_t *svc_ctx)
1333{
1334 uint32_t *res_ptr = (uint32_t *)&svc_ctx->r0;
1335 uint32_t running_partition_flags = 0;
1336 uint32_t running_partition_idx;
1337
1338 /* Check permissions on request type basis */
1339
1340 switch (svc_ctx->r0) {
1341 case TFM_SPM_REQUEST_RESET_VOTE:
1342 running_partition_idx =
1343 tfm_spm_partition_get_running_partition_idx();
1344 running_partition_flags = tfm_spm_partition_get_flags(
1345 running_partition_idx);
1346
1347 /* Currently only PSA Root of Trust services are allowed to make Reset
1348 * vote request
1349 */
1350 if ((running_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
1351 *res_ptr = (uint32_t)TFM_ERROR_GENERIC;
1352 }
1353
1354 /* FixMe: this is a placeholder for checks to be performed before
1355 * allowing execution of reset
1356 */
1357 *res_ptr = (uint32_t)TFM_SUCCESS;
1358
1359 break;
1360 default:
1361 *res_ptr = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
1362 }
1363}
Mingyang Sunbd7ceb52020-06-11 16:53:03 +08001364
1365enum spm_err_t tfm_spm_db_init(void)
1366{
1367 uint32_t i;
1368
1369 /* This function initialises partition db */
1370
1371 /* For the non secure Execution environment */
1372 tfm_nspm_configure_clients();
1373
1374 for (i = 0; i < g_spm_partition_db.partition_count; i++) {
1375 g_spm_partition_db.partitions[i].runtime_data.partition_state =
1376 SPM_PARTITION_STATE_UNINIT;
1377 g_spm_partition_db.partitions[i].runtime_data.caller_partition_idx =
1378 SPM_INVALID_PARTITION_IDX;
1379 g_spm_partition_db.partitions[i].runtime_data.caller_client_id =
1380 TFM_INVALID_CLIENT_ID;
1381 g_spm_partition_db.partitions[i].runtime_data.ctx_stack_ptr =
1382 ctx_stack_list[i];
1383 g_spm_partition_db.partitions[i].static_data = &static_data_list[i];
1384 g_spm_partition_db.partitions[i].platform_data_list =
1385 platform_data_list_list[i];
1386 }
1387 g_spm_partition_db.is_init = 1;
1388
1389 return SPM_ERR_OK;
1390}