Core: Move library model SPM code to 'spm' folder
- Move the library SPM APIs from 'core' to 'spm' folder, put them
into file 'spm_func.c'. Also move function declaration to the
'spm' header file.
- Change the API names with 'tfm_spm' prefix.
- Remove inclusion of some unused header files.
Change-Id: If7ec1347cbf0d6d19bcb74bbb84f48f15c18cec9
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index f08a1de..1a2ded0 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+# Copyright (c) 2017-2020, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -34,7 +34,6 @@
"${SS_CORE_DIR}/tfm_core.c"
"${SS_CORE_DIR}/tfm_core_svcalls_func.c"
"${SS_CORE_DIR}/tfm_secure_api.c"
- "${SS_CORE_DIR}/tfm_func_api.c"
"${SS_CORE_DIR}/tfm_spm_services.c"
"${SS_CORE_DIR}/tfm_nspm_func.c"
"${SS_CORE_DIR}/tfm_boot_data.c"
diff --git a/secure_fw/core/include/tfm_internal.h b/secure_fw/core/include/tfm_internal.h
index c68eabc..fd8c08d 100644
--- a/secure_fw/core/include/tfm_internal.h
+++ b/secure_fw/core/include/tfm_internal.h
@@ -27,61 +27,14 @@
extern nsfptr_t ns_entry;
/**
- * \brief Signal that secure partition initialisation is finished
- */
-void tfm_secure_api_init_done(void);
-
-/**
* \brief Jumps to non-secure code.
*/
void jump_to_ns_code(void);
/**
- * \brief Called if veneer is running in thread mode
+ * \brief Move to handler mode by a SVC for specific purpose
*/
-uint32_t tfm_core_partition_request_svc_handler(
- const uint32_t *svc_args, uint32_t lr);
-
-/**
- * \brief Called when secure service returns
- */
-uint32_t tfm_core_partition_return_handler(uint32_t lr);
-
-/**
- * \brief Called by secure service to check if client is secure
- */
-void tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
-
-/**
- * \brief Stores caller's client id in state context
- */
-void tfm_core_get_caller_client_id_handler(const uint32_t svc_args[]);
-
-/**
- * \brief Handle an SPM request by a secure service
- */
-void tfm_core_spm_request_handler(const struct tfm_state_context_t *svc_ctx);
-
-/**
- * \brief Check whether a buffer is ok for writing to by the privileged API
- * function.
- *
- * This function checks whether the caller partition owns the buffer, can write
- * to it, and the buffer has proper alignment.
- *
- * \param[in] partition_idx Partition index
- * \param[in] start_addr The start address of the buffer
- * \param[in] len The length of the buffer
- * \param[in] alignment The expected alignment (in bits)
- *
- * \return 1 if the check passes, 0 otherwise.
- *
- * \note For a 0 long buffer the check fails.
- */
-int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
- void *start_addr,
- size_t len,
- uint32_t alignment);
+void tfm_core_handler_mode(void);
/**
* \brief Retrieve secure partition related data from shared memory area, which
@@ -98,39 +51,8 @@
void tfm_core_validate_boot_data(void);
/**
- * \brief Handle deprivileged request
+ * \brief Handle an SPM request by a secure service
*/
-extern uint32_t tfm_core_depriv_req_handler(uint32_t *svc_args,
- uint32_t excReturn);
-
-/**
- * \brief Handle request to return to privileged
- */
-uint32_t tfm_core_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr);
-
-/**
- * \brief Handle IRQ enable request
- */
-void tfm_core_enable_irq_handler(uint32_t *svc_args);
-
-/**
- * \brief Handle IRQ disable request
- */
-void tfm_core_disable_irq_handler(uint32_t *svc_args);
-
-/**
- * \brief Handle signal wait request
- */
-void tfm_core_psa_wait(uint32_t *svc_args);
-
-/**
- * \brief Handle request to record IRQ processed
- */
-void tfm_core_psa_eoi(uint32_t *svc_args);
-
-/**
- * \brief Move to handler mode by a SVC for specific purpose
- */
-void tfm_core_handler_mode(void);
+void tfm_core_spm_request_handler(const struct tfm_state_context_t *svc_ctx);
#endif /* __TFM_INTERNAL_H__ */
diff --git a/secure_fw/core/include/tfm_secure_api.h b/secure_fw/core/include/tfm_secure_api.h
index 9dad148..ae5cd0e 100644
--- a/secure_fw/core/include/tfm_secure_api.h
+++ b/secure_fw/core/include/tfm_secure_api.h
@@ -75,7 +75,7 @@
int32_t tfm_core_sfn_request(const struct tfm_sfn_req_s *desc_ptr);
-int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
+int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
/**
* \brief Check whether a memory range is inside a memory region.
@@ -158,7 +158,7 @@
if (desc.ns_caller) {
return tfm_core_sfn_request(desc_ptr);
} else {
- return tfm_core_sfn_request_thread_mode(desc_ptr);
+ return tfm_spm_sfn_request_thread_mode(desc_ptr);
}
}
return TFM_ERROR_GENERIC;
diff --git a/secure_fw/core/tfm_boot_data.c b/secure_fw/core/tfm_boot_data.c
index 079e020..02bcc1f 100644
--- a/secure_fw/core/tfm_boot_data.c
+++ b/secure_fw/core/tfm_boot_data.c
@@ -154,13 +154,14 @@
#endif
#ifndef TFM_PSA_API
- /* Make sure that the output pointer points to a memory area that is owned
- * by the partition
+ /*
+ * Make sure that the output pointer points to a memory area that is owned
+ * by the partition. And check 4 bytes alignment.
*/
- res = tfm_core_check_buffer_access(running_partition_idx,
- (void *)buf_start,
- buf_size,
- 2); /* Check 4 bytes alignment */
+ res = tfm_spm_check_buffer_access(running_partition_idx,
+ (void *)buf_start,
+ buf_size,
+ 2);
if (!res) {
/* Not in accessible range, return error */
args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
diff --git a/secure_fw/core/tfm_core_svcalls_func.c b/secure_fw/core/tfm_core_svcalls_func.c
index e54153f..8c6d88f 100644
--- a/secure_fw/core/tfm_core_svcalls_func.c
+++ b/secure_fw/core/tfm_core_svcalls_func.c
@@ -11,6 +11,7 @@
#include "core/tfm_core_svc.h"
#include "tfm_secure_api.h"
#include "region_defs.h"
+#include "spm_api.h"
#include "spm_partition_defs.h"
#include "tfm_api.h"
#include "tfm_internal.h"
@@ -51,37 +52,37 @@
}
switch (svc_number) {
case TFM_SVC_SFN_REQUEST:
- lr = tfm_core_partition_request_svc_handler(svc_args, lr);
+ lr = tfm_spm_partition_request_svc_handler(svc_args, lr);
break;
case TFM_SVC_SFN_RETURN:
- lr = tfm_core_partition_return_handler(lr);
+ lr = tfm_spm_partition_return_handler(lr);
break;
case TFM_SVC_VALIDATE_SECURE_CALLER:
- tfm_core_validate_secure_caller_handler(svc_args);
+ tfm_spm_validate_secure_caller_handler(svc_args);
break;
case TFM_SVC_GET_CALLER_CLIENT_ID:
- tfm_core_get_caller_client_id_handler(svc_args);
+ tfm_spm_get_caller_client_id_handler(svc_args);
break;
case TFM_SVC_SPM_REQUEST:
tfm_core_spm_request_handler((struct tfm_state_context_t *)svc_args);
break;
case TFM_SVC_DEPRIV_REQ:
- lr = tfm_core_depriv_req_handler(svc_args, lr);
+ lr = tfm_spm_depriv_req_handler(svc_args, lr);
break;
case TFM_SVC_DEPRIV_RET:
- lr = tfm_core_depriv_return_handler(msp, lr);
+ lr = tfm_spm_depriv_return_handler(msp, lr);
break;
case TFM_SVC_PSA_WAIT:
- tfm_core_psa_wait(svc_args);
+ tfm_spm_psa_wait(svc_args);
break;
case TFM_SVC_PSA_EOI:
- tfm_core_psa_eoi(svc_args);
+ tfm_spm_psa_eoi(svc_args);
break;
case TFM_SVC_ENABLE_IRQ:
- tfm_core_enable_irq_handler(svc_args);
+ tfm_spm_enable_irq_handler(svc_args);
break;
case TFM_SVC_DISABLE_IRQ:
- tfm_core_disable_irq_handler(svc_args);
+ tfm_spm_disable_irq_handler(svc_args);
break;
case TFM_SVC_GET_BOOT_DATA:
tfm_core_get_boot_data_handler(svc_args);
diff --git a/secure_fw/core/tfm_func_api.c b/secure_fw/core/tfm_func_api.c
deleted file mode 100644
index 7bb079a..0000000
--- a/secure_fw/core/tfm_func_api.c
+++ /dev/null
@@ -1,1069 +0,0 @@
-/*
- * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <arm_cmse.h>
-#include "tfm_nspm.h"
-#include "secure_utilities.h"
-#include "uart_stdout.h"
-#include "secure_fw/spm/spm_api.h"
-#include "region_defs.h"
-#include "tfm_api.h"
-#include "tfm_arch.h"
-#include "platform/include/tfm_spm_hal.h"
-#include "tfm_irq_list.h"
-#include "psa/service.h"
-#include "tfm_core_mem_check.h"
-#include "tfm_secure_api.h"
-#include "region.h"
-
-#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
-#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
-
-#ifndef TFM_LVL
-#error TFM_LVL is not defined!
-#endif
-
-REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Base, uint32_t);
-REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Limit, struct iovec_args_t)[];
-
-/* This is the "Big Lock" on the secure side, to guarantee single entry
- * to SPE
- */
-extern int32_t tfm_secure_lock;
-static int32_t tfm_secure_api_initializing = 1;
-
-static uint32_t *prepare_partition_iovec_ctx(
- const struct tfm_state_context_t *svc_ctx,
- const struct tfm_sfn_req_s *desc_ptr,
- const struct iovec_args_t *iovec_args,
- uint32_t *dst)
-{
- /* XPSR = as was when called, but make sure it's thread mode */
- *(--dst) = svc_ctx->xpsr & 0xFFFFFE00U;
- /* ReturnAddress = resume veneer in new context */
- *(--dst) = svc_ctx->ra;
- /* LR = sfn address */
- *(--dst) = (uint32_t)desc_ptr->sfn;
- /* R12 = don't care */
- *(--dst) = 0U;
-
- /* R0-R3 = sfn arguments */
- *(--dst) = iovec_args->out_len;
- *(--dst) = (uint32_t)iovec_args->out_vec;
- *(--dst) = iovec_args->in_len;
- *(--dst) = (uint32_t)iovec_args->in_vec;
-
- return dst;
-}
-
-/**
- * \brief Create a stack frame that sets the execution environment to thread
- * mode on exception return.
- *
- * \param[in] svc_ctx The stacked SVC context
- * \param[in] unpriv_handler The unprivileged IRQ handler to be called
- * \param[in] dst A pointer where the context is to be created. (the
- * pointer is considered to be a stack pointer, and
- * the frame is created below it)
- *
- * \return A pointer pointing at the created stack frame.
- */
-static int32_t *prepare_partition_irq_ctx(
- const struct tfm_state_context_t *svc_ctx,
- sfn_t unpriv_handler,
- int32_t *dst)
-{
- int i;
-
- /* XPSR = as was when called, but make sure it's thread mode */
- *(--dst) = svc_ctx->xpsr & 0xFFFFFE00;
- /* ReturnAddress = resume to the privileged handler code, but execute it
- * unprivileged.
- */
- *(--dst) = svc_ctx->ra;
- /* LR = start address */
- *(--dst) = (int32_t)unpriv_handler;
-
- /* R12, R0-R3 unused arguments */
- for (i = 0; i < 5; ++i) {
- *(--dst) = 0;
- }
-
- return dst;
-}
-
-static void restore_caller_ctx(
- const struct tfm_state_context_t *svc_ctx,
- struct tfm_state_context_t *target_ctx)
-{
- /* ReturnAddress = resume veneer after second SVC */
- target_ctx->ra = svc_ctx->ra;
-
- /* R0 = function return value */
- target_ctx->r0 = svc_ctx->r0;
-
- return;
-}
-
-/** \brief Check whether the iovec parameters are valid, and the memory ranges
- * are in the posession of the calling partition
- *
- * \param[in] desc_ptr The secure function request descriptor
- *
- * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
- * otherwise as in /ref tfm_status_e
- */
-static enum tfm_status_e tfm_core_check_sfn_parameters(
- const struct tfm_sfn_req_s *desc_ptr)
-{
- struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
- size_t in_len;
- struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
- size_t out_len;
-
- uint32_t i;
-
- if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
-
- in_len = (size_t)(desc_ptr->args[1]);
- out_len = (size_t)(desc_ptr->args[3]);
-
- /* The number of vectors are within range. Extra checks to avoid overflow */
- if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
- (in_len + out_len > PSA_MAX_IOVEC)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
-
- /* Check whether the caller partition has at write access to the iovec
- * structures themselves. Use the TT instruction for this.
- */
- if (in_len > 0) {
- if ((in_vec == NULL) ||
- (tfm_core_has_write_access_to_region(in_vec,
- sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
- TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- } else {
- if (in_vec != NULL) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- }
- if (out_len > 0) {
- if ((out_vec == NULL) ||
- (tfm_core_has_write_access_to_region(out_vec,
- sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
- TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- } else {
- if (out_vec != NULL) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- }
-
- /* Check whether the caller partition has access to the data inside the
- * iovecs
- */
- for (i = 0; i < in_len; ++i) {
- if (in_vec[i].len > 0) {
- if ((in_vec[i].base == NULL) ||
- (tfm_core_has_read_access_to_region(in_vec[i].base,
- in_vec[i].len, desc_ptr->ns_caller,
- TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- }
- }
- for (i = 0; i < out_len; ++i) {
- if (out_vec[i].len > 0) {
- if ((out_vec[i].base == NULL) ||
- (tfm_core_has_write_access_to_region(out_vec[i].base,
- out_vec[i].len, desc_ptr->ns_caller,
- TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
- return TFM_ERROR_INVALID_PARAMETER;
- }
- }
- }
-
- return TFM_SUCCESS;
-}
-
-static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
- const struct iovec_args_t *source)
-{
- size_t i;
-
- /* The vectors have been sanity checked already, and since then the
- * interrupts have been kept disabled. So we can be sure that the
- * vectors haven't been tampered with since the check. So it is safe to pass
- * it to the called partition.
- */
-
- target->in_len = source->in_len;
- for (i = 0; i < source->in_len; ++i) {
- target->in_vec[i].base = source->in_vec[i].base;
- target->in_vec[i].len = source->in_vec[i].len;
- }
- target->out_len = source->out_len;
- for (i = 0; i < source->out_len; ++i) {
- target->out_vec[i].base = source->out_vec[i].base;
- target->out_vec[i].len = source->out_vec[i].len;
- }
-}
-
-static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
-{
- int i;
-
- args->in_len = 0;
- for (i = 0; i < PSA_MAX_IOVEC; ++i) {
- args->in_vec[i].base = NULL;
- args->in_vec[i].len = 0;
- }
- args->out_len = 0;
- for (i = 0; i < PSA_MAX_IOVEC; ++i) {
- args->out_vec[i].base = NULL;
- args->out_vec[i].len = 0;
- }
-}
-
-/**
- * \brief Check whether the partitions for the secure function call are in a
- * proper state
- *
- * \param[in] curr_partition_state State of the partition to be called
- * \param[in] caller_partition_state State of the caller partition
- *
- * \return \ref TFM_SUCCESS if the check passes, error otherwise.
- */
-static enum tfm_status_e check_partition_state(uint32_t curr_partition_state,
- uint32_t caller_partition_state)
-{
- if (caller_partition_state != SPM_PARTITION_STATE_RUNNING) {
- /* Calling partition from non-running state (e.g. during handling IRQ)
- * is not allowed.
- */
- return TFM_ERROR_INVALID_EXC_MODE;
- }
-
- if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
- curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
- curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
- curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
- /* Active partitions cannot be called! */
- return TFM_ERROR_PARTITION_NON_REENTRANT;
- } else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
- /* The partition to be called is not in a proper state */
- return TFM_SECURE_LOCK_FAILED;
- }
- return TFM_SUCCESS;
-}
-
-/**
- * \brief Check whether the partitions for the secure function call are in a
- * proper state
- *
- * \param[in] called_partition_state State of the partition to be called
- *
- * \return \ref TFM_SUCCESS if the check passes, error otherwise.
- */
-static enum tfm_status_e check_irq_partition_state(
- uint32_t called_partition_state)
-{
- if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
- called_partition_state == SPM_PARTITION_STATE_RUNNING ||
- called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
- called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
- called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
- return TFM_SUCCESS;
- }
- return TFM_SECURE_LOCK_FAILED;
-}
-
-/**
- * \brief Calculate the address where the iovec parameters are to be saved for
- * the called partition.
- *
- * \param[in] partition_idx The index of the partition to be called.
- *
- * \return The address where the iovec parameters should be saved.
- */
-static struct iovec_args_t *get_iovec_args_stack_address(uint32_t partition_idx)
-{
- /* Save the iovecs on the common stack. */
- return (struct iovec_args_t *)((uint8_t *)®ION_NAME(Image$$,
- TFM_SECURE_STACK, $$ZI$$Limit) -
- sizeof(struct iovec_args_t));
-}
-
-static enum tfm_status_e tfm_start_partition(
- const struct tfm_sfn_req_s *desc_ptr,
- uint32_t excReturn)
-{
- enum tfm_status_e res;
- uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
- const struct spm_partition_runtime_data_t *curr_part_data;
- const struct spm_partition_runtime_data_t *caller_part_data;
- uint32_t caller_flags;
- register uint32_t partition_idx;
- uint32_t psp;
- uint32_t partition_psp, partition_psplim;
- uint32_t partition_state;
- uint32_t caller_partition_state;
- uint32_t partition_flags;
- struct tfm_state_context_t *svc_ctx;
- uint32_t caller_partition_id;
- int32_t client_id;
- struct iovec_args_t *iovec_args;
-
- psp = __get_PSP();
- svc_ctx = (struct tfm_state_context_t *)psp;
- caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
-
- /* Check partition state consistency */
- if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
- != (!desc_ptr->ns_caller)) {
- /* Partition state inconsistency detected */
- return TFM_SECURE_LOCK_FAILED;
- }
-
- partition_idx = get_partition_idx(desc_ptr->sp_id);
-
- curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
- caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
- partition_state = curr_part_data->partition_state;
- caller_partition_state = caller_part_data->partition_state;
- partition_flags = tfm_spm_partition_get_flags(partition_idx);
- caller_partition_id = tfm_spm_partition_get_partition_id(
- caller_partition_idx);
-
- if (!tfm_secure_api_initializing) {
- res = check_partition_state(partition_state, caller_partition_state);
- if (res != TFM_SUCCESS) {
- return res;
- }
- }
-
- /* Prepare switch to shared secure partition stack */
- /* In case the call is coming from the non-secure world, we save the iovecs
- * on the stop of the stack. So the memory area, that can actually be used
- * as stack by the partitions starts at a lower address
- */
- partition_psp =
- (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
- sizeof(struct iovec_args_t);
- partition_psplim =
- (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
-
- /* Store the context for the partition call */
- tfm_spm_partition_set_caller_partition_idx(partition_idx,
- caller_partition_idx);
- tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
-
- if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
- tfm_spm_partition_set_caller_client_id(partition_idx,
- caller_partition_id);
- } else {
- client_id = tfm_nspm_get_current_client_id();
- if (client_id >= 0) {
- return TFM_SECURE_LOCK_FAILED;
- }
- tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
- }
-
- /* In level one, only switch context and return from exception if in
- * handler mode
- */
- if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
- if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
- SPM_ERR_OK) {
- return TFM_ERROR_GENERIC;
- }
- iovec_args = get_iovec_args_stack_address(partition_idx);
- tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
-
- /* Prepare the partition context, update stack ptr */
- psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
- iovec_args,
- (uint32_t *)partition_psp);
- __set_PSP(psp);
- tfm_arch_set_psplim(partition_psplim);
- }
-
- tfm_spm_partition_set_state(caller_partition_idx,
- SPM_PARTITION_STATE_BLOCKED);
- tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
- tfm_secure_lock++;
-
- return TFM_SUCCESS;
-}
-
-static enum tfm_status_e tfm_start_partition_for_irq_handling(
- uint32_t excReturn,
- struct tfm_state_context_t *svc_ctx)
-{
- uint32_t handler_partition_id = svc_ctx->r0;
- sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
- uint32_t irq_signal = svc_ctx->r2;
- uint32_t irq_line = svc_ctx->r3;
- enum tfm_status_e res;
- uint32_t psp = __get_PSP();
- uint32_t handler_partition_psp;
- uint32_t handler_partition_state;
- uint32_t interrupted_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- const struct spm_partition_runtime_data_t *handler_part_data;
- uint32_t handler_partition_idx;
-
- handler_partition_idx = get_partition_idx(handler_partition_id);
- handler_part_data = tfm_spm_partition_get_runtime_data(
- handler_partition_idx);
- handler_partition_state = handler_part_data->partition_state;
-
- res = check_irq_partition_state(handler_partition_state);
- if (res != TFM_SUCCESS) {
- return res;
- }
-
- /* set mask for the partition */
- tfm_spm_partition_set_signal_mask(
- handler_partition_idx,
- handler_part_data->signal_mask | irq_signal);
-
- tfm_spm_hal_disable_irq(irq_line);
-
- /* save the current context of the interrupted partition */
- tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
-
- handler_partition_psp = psp;
-
- /* save the current context of the handler partition */
- tfm_spm_partition_push_handler_ctx(handler_partition_idx);
-
- /* Store caller for the partition */
- tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
- interrupted_partition_idx);
-
- psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
- (int32_t *)handler_partition_psp);
- __set_PSP(psp);
-
- tfm_spm_partition_set_state(interrupted_partition_idx,
- SPM_PARTITION_STATE_SUSPENDED);
- tfm_spm_partition_set_state(handler_partition_idx,
- SPM_PARTITION_STATE_HANDLING_IRQ);
-
- return TFM_SUCCESS;
-}
-
-static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
-{
- uint32_t current_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
- uint32_t current_partition_flags;
- uint32_t return_partition_idx;
- uint32_t return_partition_flags;
- uint32_t psp = __get_PSP();
- size_t i;
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
- struct iovec_args_t *iovec_args;
-
- if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
- return TFM_SECURE_UNLOCK_FAILED;
- }
-
- curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
- return_partition_idx = curr_part_data->caller_partition_idx;
-
- if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
- return TFM_SECURE_UNLOCK_FAILED;
- }
-
- ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
-
- return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
- current_partition_flags = tfm_spm_partition_get_flags(
- current_partition_idx);
-
- tfm_secure_lock--;
-
- if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
- (tfm_secure_api_initializing)) {
- /* In TFM level 1 context restore is only done when
- * returning to NS or after initialization
- */
- /* Restore caller context */
- restore_caller_ctx(svc_ctx,
- (struct tfm_state_context_t *)ret_part_data->stack_ptr);
- *excReturn = ret_part_data->lr;
- __set_PSP(ret_part_data->stack_ptr);
- REGION_DECLARE(Image$$, ARM_LIB_STACK, $$ZI$$Base)[];
- uint32_t psp_stack_bottom =
- (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
- tfm_arch_set_psplim(psp_stack_bottom);
-
- iovec_args = (struct iovec_args_t *)
- ((uint8_t *)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit) -
- sizeof(struct iovec_args_t));
-
- for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
- curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
- }
- tfm_clear_iovec_parameters(iovec_args);
- }
-
- tfm_spm_partition_cleanup_context(current_partition_idx);
-
- tfm_spm_partition_set_state(current_partition_idx,
- SPM_PARTITION_STATE_IDLE);
- tfm_spm_partition_set_state(return_partition_idx,
- SPM_PARTITION_STATE_RUNNING);
-
- return TFM_SUCCESS;
-}
-
-static enum tfm_status_e tfm_return_from_partition_irq_handling(
- uint32_t *excReturn)
-{
- uint32_t handler_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- const struct spm_partition_runtime_data_t *handler_part_data;
- uint32_t interrupted_partition_idx;
- uint32_t psp = __get_PSP();
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
-
- if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
- return TFM_SECURE_UNLOCK_FAILED;
- }
-
- handler_part_data = tfm_spm_partition_get_runtime_data(
- handler_partition_idx);
- interrupted_partition_idx = handler_part_data->caller_partition_idx;
-
- if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
- return TFM_SECURE_UNLOCK_FAILED;
- }
-
- /* For level 1, modify PSP, so that the SVC stack frame disappears,
- * and return to the privileged handler using the stack frame still on the
- * MSP stack.
- */
- *excReturn = svc_ctx->ra;
- psp += sizeof(struct tfm_state_context_t);
-
- tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
- tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
-
- __set_PSP(psp);
-
- return TFM_SUCCESS;
-}
-
-static enum tfm_status_e tfm_check_sfn_req_integrity(
- const struct tfm_sfn_req_s *desc_ptr)
-{
- if ((desc_ptr == NULL) ||
- (desc_ptr->sp_id == 0) ||
- (desc_ptr->sfn == NULL)) {
- /* invalid parameter */
- return TFM_ERROR_INVALID_PARAMETER;
- }
- return TFM_SUCCESS;
-}
-
-static enum tfm_status_e tfm_core_check_sfn_req_rules(
- const struct tfm_sfn_req_s *desc_ptr)
-{
- /* Check partition idx validity */
- if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
- return TFM_ERROR_NO_ACTIVE_PARTITION;
- }
-
- if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
- /* Secure domain is already locked!
- * This should only happen if caller is secure partition!
- */
- /* This scenario is a potential security breach.
- * Error is handled in caller.
- */
- return TFM_ERROR_SECURE_DOMAIN_LOCKED;
- }
-
- if (tfm_secure_api_initializing) {
- int32_t id =
- tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
-
- if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
- /* Invalid request during system initialization */
- ERROR_MSG("Invalid service request during initialization!");
- return TFM_ERROR_NOT_INITIALIZED;
- }
- }
-
- return TFM_SUCCESS;
-}
-
-void tfm_secure_api_init_done(void)
-{
- tfm_secure_api_initializing = 0;
-}
-
-enum tfm_status_e tfm_core_sfn_request_handler(
- struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
-{
- enum tfm_status_e res;
-
- res = tfm_check_sfn_req_integrity(desc_ptr);
- if (res != TFM_SUCCESS) {
- ERROR_MSG("Invalid service request!");
- tfm_secure_api_error_handler();
- }
-
- __disable_irq();
-
- desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
-
- res = tfm_core_check_sfn_parameters(desc_ptr);
- if (res != TFM_SUCCESS) {
- /* The sanity check of iovecs failed. */
- __enable_irq();
- tfm_secure_api_error_handler();
- }
-
- res = tfm_core_check_sfn_req_rules(desc_ptr);
- if (res != TFM_SUCCESS) {
- /* FixMe: error compartmentalization TBD */
- tfm_spm_partition_set_state(
- desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
- __enable_irq();
- ERROR_MSG("Unauthorized service request!");
- tfm_secure_api_error_handler();
- }
-
- res = tfm_start_partition(desc_ptr, excReturn);
- if (res != TFM_SUCCESS) {
- /* FixMe: consider possible fault scenarios */
- __enable_irq();
- ERROR_MSG("Failed to process service request!");
- tfm_secure_api_error_handler();
- }
-
- __enable_irq();
-
- return res;
-}
-
-int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
-{
- enum tfm_status_e res;
- int32_t *args;
- int32_t retVal;
-
- res = tfm_core_check_sfn_parameters(desc_ptr);
- if (res != TFM_SUCCESS) {
- /* The sanity check of iovecs failed. */
- return (int32_t)res;
- }
-
- /* No excReturn value is needed as no exception handling is used */
- res = tfm_core_sfn_request_handler(desc_ptr, 0);
-
- if (res != TFM_SUCCESS) {
- tfm_secure_api_error_handler();
- }
-
- /* Secure partition to secure partition call in TFM level 1 */
- args = desc_ptr->args;
- retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
-
- /* return handler should restore original exc_return value... */
- res = tfm_return_from_partition(NULL);
- if (res == TFM_SUCCESS) {
- /* If unlock successful, pass SS return value to caller */
- return retVal;
- } else {
- /* Unlock errors indicate ctx database corruption or unknown
- * anomalies. Halt execution
- */
- ERROR_MSG("Secure API error during unlock!");
- tfm_secure_api_error_handler();
- }
- return (int32_t)res;
-}
-
-void tfm_core_validate_secure_caller_handler(uint32_t *svc_args)
-{
-
- enum tfm_status_e res = TFM_ERROR_GENERIC;
- uint32_t running_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- const struct spm_partition_runtime_data_t *curr_part_data =
- tfm_spm_partition_get_runtime_data(running_partition_idx);
- uint32_t running_partition_flags =
- tfm_spm_partition_get_flags(running_partition_idx);
- uint32_t caller_partition_flags =
- tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
-
- if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
- curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
- curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
- /* This handler shouldn't be called from outside partition context.
- * Also if the current partition is handling IRQ, the caller partition
- * index might not be valid;
- * Partitions are only allowed to run while S domain is locked.
- */
- svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
- return;
- }
-
- /* Store return value in r0 */
- if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
- res = TFM_SUCCESS;
- }
- svc_args[0] = (uint32_t)res;
-}
-
-int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
- void *start_addr,
- size_t len,
- uint32_t alignment)
-{
- uintptr_t start_addr_value = (uintptr_t)start_addr;
- uintptr_t end_addr_value = (uintptr_t)start_addr + len;
- uintptr_t alignment_mask;
-
- alignment_mask = (((uintptr_t)1) << alignment) - 1;
-
- /* Check that the pointer is aligned properly */
- if (start_addr_value & alignment_mask) {
- /* not aligned, return error */
- return 0;
- }
-
- /* Protect against overflow (and zero len) */
- if (end_addr_value <= start_addr_value) {
- return 0;
- }
-
- /* For privileged partition execution, all secure data memory and stack
- * is accessible
- */
- if (start_addr_value >= S_DATA_START &&
- end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
- return 1;
- }
-
- return 0;
-}
-
-void tfm_core_get_caller_client_id_handler(uint32_t *svc_args)
-{
- uintptr_t result_ptr_value = svc_args[0];
- uint32_t running_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- const uint32_t running_partition_flags =
- tfm_spm_partition_get_flags(running_partition_idx);
- const struct spm_partition_runtime_data_t *curr_part_data =
- tfm_spm_partition_get_runtime_data(running_partition_idx);
- int res = 0;
-
- if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
- curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
- curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
- /* This handler shouldn't be called from outside partition context.
- * Also if the current partition is handling IRQ, the caller partition
- * index might not be valid;
- * Partitions are only allowed to run while S domain is locked.
- */
- svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
- return;
- }
-
- /* Make sure that the output pointer points to a memory area that is owned
- * by the partition
- */
- res = tfm_core_check_buffer_access(running_partition_idx,
- (void *)result_ptr_value,
- sizeof(curr_part_data->caller_client_id),
- 2);
- if (!res) {
- /* Not in accessible range, return error */
- svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
- return;
- }
-
- *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
-
- /* Store return value in r0 */
- svc_args[0] = (uint32_t)TFM_SUCCESS;
-}
-
-/* This SVC handler is called if veneer is running in thread mode */
-uint32_t tfm_core_partition_request_svc_handler(
- const struct tfm_state_context_t *svc_ctx, uint32_t excReturn)
-{
- struct tfm_sfn_req_s *desc_ptr;
-
- if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
- /* Service request SVC called with MSP active.
- * Either invalid configuration for Thread mode or SVC called
- * from Handler mode, which is not supported.
- * FixMe: error severity TBD
- */
- ERROR_MSG("Service request SVC called with MSP active!");
- tfm_secure_api_error_handler();
- }
-
- desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->r0;
-
- if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
- tfm_secure_api_error_handler();
- }
-
- return EXC_RETURN_SECURE_FUNCTION;
-}
-
-/* This SVC handler is called, if a thread mode execution environment is to
- * be set up, to run an unprivileged IRQ handler
- */
-uint32_t tfm_core_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
-{
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)svc_args;
-
- enum tfm_status_e res;
-
- if (excReturn & EXC_RETURN_STACK_PROCESS) {
- /* FixMe: error severity TBD */
- ERROR_MSG("Partition request SVC called with PSP active!");
- tfm_secure_api_error_handler();
- }
-
- res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
- if (res != TFM_SUCCESS) {
- /* The partition is in an invalid state (UNINIT or CLOSED), so none of
- * its code can be run
- */
- /* FixMe: For now this case is handled with TF-M panic, however it would
- * be possible to skip the execution of the interrupt handler, and
- * resume the execution of the interrupted code.
- */
- tfm_secure_api_error_handler();
- }
- return EXC_RETURN_SECURE_FUNCTION;
-}
-
-/* This SVC handler is called when sfn returns */
-uint32_t tfm_core_partition_return_handler(uint32_t lr)
-{
- enum tfm_status_e res;
-
- if (!(lr & EXC_RETURN_STACK_PROCESS)) {
- /* Partition return SVC called with MSP active.
- * This should not happen!
- */
- ERROR_MSG("Partition return SVC called with MSP active!");
- tfm_secure_api_error_handler();
- }
-
- res = tfm_return_from_partition(&lr);
- if (res != TFM_SUCCESS) {
- /* Unlock errors indicate ctx database corruption or unknown anomalies
- * Halt execution
- */
- ERROR_MSG("Secure API error during unlock!");
- tfm_secure_api_error_handler();
- }
-
- return lr;
-}
-
-/* This SVC handler is called if a deprivileged IRQ handler was executed, and
- * the execution environment is to be set back for the privileged handler mode
- */
-uint32_t tfm_core_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
-{
- struct tfm_state_context_t *irq_svc_ctx =
- (struct tfm_state_context_t *)irq_svc_args;
-
- if (!(lr & EXC_RETURN_STACK_PROCESS)) {
- /* Partition request SVC called with MSP active.
- * FixMe: error severity TBD
- */
- ERROR_MSG("Partition request SVC called with MSP active!");
- tfm_secure_api_error_handler();
- }
-
- enum tfm_status_e res;
-
- res = tfm_return_from_partition_irq_handling(&lr);
- if (res != TFM_SUCCESS) {
- /* Unlock errors indicate ctx database corruption or unknown anomalies
- * Halt execution
- */
- ERROR_MSG("Secure API error during unlock!");
- tfm_secure_api_error_handler();
- }
-
- irq_svc_ctx->ra = lr;
-
- return EXC_RETURN_SECURE_HANDLER;
-}
-
-/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
-/**
- * \brief Return the IRQ line number associated with a signal
- *
- * \param[in] partition_id The ID of the partition in which we look for the
- * signal
- * \param[in] signal The signal we do the query for
- *
- * \retval >=0 The IRQ line number associated with a signal in the partition
- * \retval <0 error
- */
-static int32_t get_irq_line_for_signal(int32_t partition_id,
- psa_signal_t signal)
-{
- size_t i;
-
- for (i = 0; i < tfm_core_irq_signals_count; ++i) {
- if (tfm_core_irq_signals[i].partition_id == partition_id &&
- tfm_core_irq_signals[i].signal_value == signal) {
- return tfm_core_irq_signals[i].irq_line;
- }
- }
- return -1;
-}
-
-/* FIXME: tfm_core_psa_eoi, tfm_core_enable_irq_handler and
- * tfm_core_disable_irq_handler function has an implementation in
- * tfm_svcalls.c for the IPC model.
- * The two implementations should be merged as part of restructuring common code
- * among library and IPC model.
- */
-void tfm_core_enable_irq_handler(uint32_t *svc_args)
-{
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)svc_args;
- psa_signal_t irq_signal = svc_ctx->r0;
- uint32_t running_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- uint32_t running_partition_id =
- tfm_spm_partition_get_partition_id(running_partition_idx);
- int32_t irq_line;
-
- /* Only a single signal is allowed */
- if (!tfm_is_one_bit_set(irq_signal)) {
- /* FixMe: error severity TBD */
- tfm_secure_api_error_handler();
- }
-
- irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
-
- if (irq_line < 0) {
- /* FixMe: error severity TBD */
- tfm_secure_api_error_handler();
- }
-
- tfm_spm_hal_enable_irq(irq_line);
-}
-
-void tfm_core_disable_irq_handler(uint32_t *svc_args)
-{
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)svc_args;
- psa_signal_t irq_signal = svc_ctx->r0;
- uint32_t running_partition_idx =
- tfm_spm_partition_get_running_partition_idx();
- uint32_t running_partition_id =
- tfm_spm_partition_get_partition_id(running_partition_idx);
- int32_t irq_line;
-
- /* Only a single signal is allowed */
- if (!tfm_is_one_bit_set(irq_signal)) {
- /* FixMe: error severity TBD */
- tfm_secure_api_error_handler();
- }
-
- irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
-
- if (irq_line < 0) {
- /* FixMe: error severity TBD */
- tfm_secure_api_error_handler();
- }
-
- tfm_spm_hal_disable_irq(irq_line);
-}
-
-void tfm_core_psa_wait(uint32_t *svc_args)
-{
- /* Look for partition that is ready for run */
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)svc_args;
- uint32_t running_partition_idx;
- const struct spm_partition_runtime_data_t *curr_part_data;
-
- psa_signal_t signal_mask = svc_ctx->r0;
- uint32_t timeout = svc_ctx->r1;
-
- /*
- * Timeout[30:0] are reserved for future use.
- * SPM must ignore the value of RES.
- */
- timeout &= PSA_TIMEOUT_MASK;
-
- running_partition_idx = tfm_spm_partition_get_running_partition_idx();
- curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
-
- if (timeout == PSA_BLOCK) {
- /* FIXME: Scheduling is not available in library model, and busy wait is
- * also not possible as this code is running in SVC context, and it
- * cannot be pre-empted by interrupts. So do nothing here for now
- */
- (void) signal_mask;
- }
-
- svc_ctx->r0 = curr_part_data->signal_mask;
-}
-
-void tfm_core_psa_eoi(uint32_t *svc_args)
-{
- struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)svc_args;
- psa_signal_t irq_signal = svc_ctx->r0;
- uint32_t signal_mask;
- uint32_t running_partition_idx;
- uint32_t running_partition_id;
- const struct spm_partition_runtime_data_t *curr_part_data;
- int32_t irq_line;
-
- running_partition_idx = tfm_spm_partition_get_running_partition_idx();
- running_partition_id =
- tfm_spm_partition_get_partition_id(running_partition_idx);
- curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
-
- /* Only a single signal is allowed */
- if (!tfm_is_one_bit_set(irq_signal)) {
- tfm_secure_api_error_handler();
- }
-
- irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
-
- if (irq_line < 0) {
- /* FixMe: error severity TBD */
- tfm_secure_api_error_handler();
- }
-
- tfm_spm_hal_clear_pending_irq(irq_line);
- tfm_spm_hal_enable_irq(irq_line);
-
- signal_mask = curr_part_data->signal_mask & ~irq_signal;
- tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
-}
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index 0ed8893..ea5bc9b 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -381,6 +381,89 @@
*/
void tfm_spm_partition_set_signal_mask(uint32_t partition_idx,
uint32_t signal_mask);
+
+/**
+ * \brief Signal that secure partition initialisation is finished
+ */
+void tfm_spm_secure_api_init_done(void);
+
+/**
+ * \brief Called if veneer is running in thread mode
+ */
+uint32_t tfm_spm_partition_request_svc_handler(
+ const uint32_t *svc_args, uint32_t lr);
+
+/**
+ * \brief Called when secure service returns
+ */
+uint32_t tfm_spm_partition_return_handler(uint32_t lr);
+
+/**
+ * \brief Called by secure service to check if client is secure
+ */
+void tfm_spm_validate_secure_caller_handler(uint32_t *svc_args);
+
+/**
+ * \brief Stores caller's client id in state context
+ */
+void tfm_spm_get_caller_client_id_handler(uint32_t *svc_args);
+
+/**
+ * \brief Checks if a secure service's access to a memory location is permitted
+ */
+void tfm_spm_memory_permission_check_handler(uint32_t *svc_args);
+
+/**
+ * \brief Check whether a buffer is ok for writing to by the privileged API
+ * function.
+ *
+ * This function checks whether the caller partition owns the buffer, can write
+ * to it, and the buffer has proper alignment.
+ *
+ * \param[in] partition_idx Partition index
+ * \param[in] start_addr The start address of the buffer
+ * \param[in] len The length of the buffer
+ * \param[in] alignment The expected alignment (in bits)
+ *
+ * \return 1 if the check passes, 0 otherwise.
+ *
+ * \note For a 0 long buffer the check fails.
+ */
+int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
+ void *start_addr,
+ size_t len,
+ uint32_t alignment);
+
+/**
+ * \brief Handle deprivileged request
+ */
+extern uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args,
+ uint32_t excReturn);
+
+/**
+ * \brief Handle request to return to privileged
+ */
+uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr);
+
+/**
+ * \brief Handle IRQ enable request
+ */
+void tfm_spm_enable_irq_handler(uint32_t *svc_args);
+
+/**
+ * \brief Handle IRQ disable request
+ */
+void tfm_spm_disable_irq_handler(uint32_t *svc_args);
+
+/**
+ * \brief Handle signal wait request
+ */
+void tfm_spm_psa_wait(uint32_t *svc_args);
+
+/**
+ * \brief Handle request to record IRQ processed
+ */
+void tfm_spm_psa_eoi(uint32_t *svc_args);
#endif /* !defined(TFM_PSA_API) */
#ifdef TFM_PSA_API
diff --git a/secure_fw/spm/spm_func.c b/secure_fw/spm/spm_func.c
index d855256..ca11814 100644
--- a/secure_fw/spm/spm_func.c
+++ b/secure_fw/spm/spm_func.c
@@ -1,30 +1,1070 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
-/* All the APIs defined in this file are used for library model. */
-
-#include <inttypes.h>
-#include <limits.h>
+#include <stdint.h>
#include <stdbool.h>
-#include <stdlib.h>
-#include "tfm_utils.h"
+#include <arm_cmse.h>
+#include "tfm_nspm.h"
+#include "secure_utilities.h"
+#include "tfm_api.h"
+#include "tfm_arch.h"
+#include "tfm_irq_list.h"
+#include "psa/service.h"
+#include "tfm_core_mem_check.h"
+#include "tfm_secure_api.h"
#include "tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
#include "region_defs.h"
-#include "tfm_nspm.h"
-#include "tfm_memory_utils.h"
-#include "tfm_internal.h"
+#include "region.h"
+
+#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
+#define EXC_RETURN_SECURE_HANDLER 0xFFFFFFF1
+
+#ifndef TFM_LVL
+#error TFM_LVL is not defined!
+#endif
+
+REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Base, uint32_t);
+REGION_DECLARE_T(Image$$, TFM_SECURE_STACK, $$ZI$$Limit, struct iovec_args_t)[];
+
+/*
+ * This is the "Big Lock" on the secure side, to guarantee single entry
+ * to SPE
+ */
+extern int32_t tfm_secure_lock;
+static int32_t tfm_secure_api_initializing = 1;
extern struct spm_partition_db_t g_spm_partition_db;
-typedef enum {
- TFM_INIT_FAILURE,
-} sp_error_type_t;
+static uint32_t *prepare_partition_iovec_ctx(
+ const struct tfm_state_context_t *svc_ctx,
+ const struct tfm_sfn_req_s *desc_ptr,
+ const struct iovec_args_t *iovec_args,
+ uint32_t *dst)
+{
+ /* XPSR = as was when called, but make sure it's thread mode */
+ *(--dst) = svc_ctx->xpsr & 0xFFFFFE00U;
+ /* ReturnAddress = resume veneer in new context */
+ *(--dst) = svc_ctx->ra;
+ /* LR = sfn address */
+ *(--dst) = (uint32_t)desc_ptr->sfn;
+ /* R12 = don't care */
+ *(--dst) = 0U;
+
+ /* R0-R3 = sfn arguments */
+ *(--dst) = iovec_args->out_len;
+ *(--dst) = (uint32_t)iovec_args->out_vec;
+ *(--dst) = iovec_args->in_len;
+ *(--dst) = (uint32_t)iovec_args->in_vec;
+
+ return dst;
+}
+
+/**
+ * \brief Create a stack frame that sets the execution environment to thread
+ * mode on exception return.
+ *
+ * \param[in] svc_ctx The stacked SVC context
+ * \param[in] unpriv_handler The unprivileged IRQ handler to be called
+ * \param[in] dst A pointer where the context is to be created. (the
+ * pointer is considered to be a stack pointer, and
+ * the frame is created below it)
+ *
+ * \return A pointer pointing at the created stack frame.
+ */
+static int32_t *prepare_partition_irq_ctx(
+ const struct tfm_state_context_t *svc_ctx,
+ sfn_t unpriv_handler,
+ int32_t *dst)
+{
+ int i;
+
+ /* XPSR = as was when called, but make sure it's thread mode */
+ *(--dst) = svc_ctx->xpsr & 0xFFFFFE00;
+ /* ReturnAddress = resume to the privileged handler code, but execute it
+ * unprivileged.
+ */
+ *(--dst) = svc_ctx->ra;
+ /* LR = start address */
+ *(--dst) = (int32_t)unpriv_handler;
+
+ /* R12, R0-R3 unused arguments */
+ for (i = 0; i < 5; ++i) {
+ *(--dst) = 0;
+ }
+
+ return dst;
+}
+
+static void restore_caller_ctx(const struct tfm_state_context_t *svc_ctx,
+ struct tfm_state_context_t *target_ctx)
+{
+ /* ReturnAddress = resume veneer after second SVC */
+ target_ctx->ra = svc_ctx->ra;
+
+ /* R0 = function return value */
+ target_ctx->r0 = svc_ctx->r0;
+
+ return;
+}
+
+/**
+ * \brief Check whether the iovec parameters are valid, and the memory ranges
+ * are in the possession of the calling partition.
+ *
+ * \param[in] desc_ptr The secure function request descriptor
+ *
+ * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
+ * otherwise as in /ref tfm_status_e
+ */
+static enum tfm_status_e tfm_core_check_sfn_parameters(
+ const struct tfm_sfn_req_s *desc_ptr)
+{
+ struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
+ size_t in_len;
+ struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
+ size_t out_len;
+ uint32_t i;
+
+ if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+
+ in_len = (size_t)(desc_ptr->args[1]);
+ out_len = (size_t)(desc_ptr->args[3]);
+
+ /* The number of vectors are within range. Extra checks to avoid overflow */
+ if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
+ (in_len + out_len > PSA_MAX_IOVEC)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+
+ /* Check whether the caller partition has at write access to the iovec
+ * structures themselves. Use the TT instruction for this.
+ */
+ if (in_len > 0) {
+ if ((in_vec == NULL) ||
+ (tfm_core_has_write_access_to_region(in_vec,
+ sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
+ TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ } else {
+ if (in_vec != NULL) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ }
+ if (out_len > 0) {
+ if ((out_vec == NULL) ||
+ (tfm_core_has_write_access_to_region(out_vec,
+ sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
+ TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ } else {
+ if (out_vec != NULL) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ /* Check whether the caller partition has access to the data inside the
+ * iovecs
+ */
+ for (i = 0; i < in_len; ++i) {
+ if (in_vec[i].len > 0) {
+ if ((in_vec[i].base == NULL) ||
+ (tfm_core_has_read_access_to_region(in_vec[i].base,
+ in_vec[i].len, desc_ptr->ns_caller,
+ TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+ for (i = 0; i < out_len; ++i) {
+ if (out_vec[i].len > 0) {
+ if ((out_vec[i].base == NULL) ||
+ (tfm_core_has_write_access_to_region(out_vec[i].base,
+ out_vec[i].len, desc_ptr->ns_caller,
+ TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return TFM_SUCCESS;
+}
+
+static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
+ const struct iovec_args_t *source)
+{
+ size_t i;
+
+ /* The vectors have been sanity checked already, and since then the
+ * interrupts have been kept disabled. So we can be sure that the
+ * vectors haven't been tampered with since the check. So it is safe to pass
+ * it to the called partition.
+ */
+
+ target->in_len = source->in_len;
+ for (i = 0; i < source->in_len; ++i) {
+ target->in_vec[i].base = source->in_vec[i].base;
+ target->in_vec[i].len = source->in_vec[i].len;
+ }
+ target->out_len = source->out_len;
+ for (i = 0; i < source->out_len; ++i) {
+ target->out_vec[i].base = source->out_vec[i].base;
+ target->out_vec[i].len = source->out_vec[i].len;
+ }
+}
+
+static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
+{
+ int i;
+
+ args->in_len = 0;
+ for (i = 0; i < PSA_MAX_IOVEC; ++i) {
+ args->in_vec[i].base = NULL;
+ args->in_vec[i].len = 0;
+ }
+ args->out_len = 0;
+ for (i = 0; i < PSA_MAX_IOVEC; ++i) {
+ args->out_vec[i].base = NULL;
+ args->out_vec[i].len = 0;
+ }
+}
+
+/**
+ * \brief Check whether the partitions for the secure function call are in a
+ * proper state.
+ *
+ * \param[in] curr_partition_state State of the partition to be called
+ * \param[in] caller_partition_state State of the caller partition
+ *
+ * \return \ref TFM_SUCCESS if the check passes, error otherwise.
+ */
+static enum tfm_status_e check_partition_state(uint32_t curr_partition_state,
+ uint32_t caller_partition_state)
+{
+ if (caller_partition_state != SPM_PARTITION_STATE_RUNNING) {
+ /* Calling partition from non-running state (e.g. during handling IRQ)
+ * is not allowed.
+ */
+ return TFM_ERROR_INVALID_EXC_MODE;
+ }
+
+ if (curr_partition_state == SPM_PARTITION_STATE_RUNNING ||
+ curr_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
+ curr_partition_state == SPM_PARTITION_STATE_BLOCKED) {
+ /* Active partitions cannot be called! */
+ return TFM_ERROR_PARTITION_NON_REENTRANT;
+ } else if (curr_partition_state != SPM_PARTITION_STATE_IDLE) {
+ /* The partition to be called is not in a proper state */
+ return TFM_SECURE_LOCK_FAILED;
+ }
+ return TFM_SUCCESS;
+}
+
+/**
+ * \brief Check whether the partitions for the secure function call of irq are
+ * in a proper state.
+ *
+ * \param[in] called_partition_state State of the partition to be called
+ *
+ * \return \ref TFM_SUCCESS if the check passes, error otherwise.
+ */
+static enum tfm_status_e check_irq_partition_state(
+ uint32_t called_partition_state)
+{
+ if (called_partition_state == SPM_PARTITION_STATE_IDLE ||
+ called_partition_state == SPM_PARTITION_STATE_RUNNING ||
+ called_partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ called_partition_state == SPM_PARTITION_STATE_SUSPENDED ||
+ called_partition_state == SPM_PARTITION_STATE_BLOCKED) {
+ return TFM_SUCCESS;
+ }
+ return TFM_SECURE_LOCK_FAILED;
+}
+
+/**
+ * \brief Calculate the address where the iovec parameters are to be saved for
+ * the called partition.
+ *
+ * \param[in] partition_idx The index of the partition to be called.
+ *
+ * \return The address where the iovec parameters should be saved.
+ */
+static struct iovec_args_t *get_iovec_args_stack_address(uint32_t partition_idx)
+{
+ /* Save the iovecs on the common stack. */
+ return (struct iovec_args_t *)((uint8_t *)®ION_NAME(Image$$,
+ TFM_SECURE_STACK, $$ZI$$Limit) -
+ sizeof(struct iovec_args_t));
+}
+
+static enum tfm_status_e tfm_start_partition(
+ const struct tfm_sfn_req_s *desc_ptr,
+ uint32_t excReturn)
+{
+ enum tfm_status_e res;
+ uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
+ const struct spm_partition_runtime_data_t *curr_part_data;
+ const struct spm_partition_runtime_data_t *caller_part_data;
+ uint32_t caller_flags;
+ register uint32_t partition_idx;
+ uint32_t psp;
+ uint32_t partition_psp, partition_psplim;
+ uint32_t partition_state;
+ uint32_t caller_partition_state;
+ uint32_t partition_flags;
+ struct tfm_state_context_t *svc_ctx;
+ uint32_t caller_partition_id;
+ int32_t client_id;
+ struct iovec_args_t *iovec_args;
+
+ psp = __get_PSP();
+ svc_ctx = (struct tfm_state_context_t *)psp;
+ caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
+
+ /* Check partition state consistency */
+ if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
+ != (!desc_ptr->ns_caller)) {
+ /* Partition state inconsistency detected */
+ return TFM_SECURE_LOCK_FAILED;
+ }
+
+ partition_idx = get_partition_idx(desc_ptr->sp_id);
+
+ curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
+ caller_part_data = tfm_spm_partition_get_runtime_data(caller_partition_idx);
+ partition_state = curr_part_data->partition_state;
+ caller_partition_state = caller_part_data->partition_state;
+ partition_flags = tfm_spm_partition_get_flags(partition_idx);
+ caller_partition_id = tfm_spm_partition_get_partition_id(
+ caller_partition_idx);
+
+ if (!tfm_secure_api_initializing) {
+ res = check_partition_state(partition_state, caller_partition_state);
+ if (res != TFM_SUCCESS) {
+ return res;
+ }
+ }
+
+ /* Prepare switch to shared secure partition stack */
+ /* In case the call is coming from the non-secure world, we save the iovecs
+ * on the stop of the stack. So the memory area, that can actually be used
+ * as stack by the partitions starts at a lower address
+ */
+ partition_psp =
+ (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
+ sizeof(struct iovec_args_t);
+ partition_psplim =
+ (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+
+ /* Store the context for the partition call */
+ tfm_spm_partition_set_caller_partition_idx(partition_idx,
+ caller_partition_idx);
+ tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
+
+ if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
+ tfm_spm_partition_set_caller_client_id(partition_idx,
+ caller_partition_id);
+ } else {
+ client_id = tfm_nspm_get_current_client_id();
+ if (client_id >= 0) {
+ return TFM_SECURE_LOCK_FAILED;
+ }
+ tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
+ }
+
+ /* In level one, only switch context and return from exception if in
+ * handler mode
+ */
+ if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
+ if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
+ SPM_ERR_OK) {
+ return TFM_ERROR_GENERIC;
+ }
+ iovec_args = get_iovec_args_stack_address(partition_idx);
+ tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
+
+ /* Prepare the partition context, update stack ptr */
+ psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
+ iovec_args,
+ (uint32_t *)partition_psp);
+ __set_PSP(psp);
+ tfm_arch_set_psplim(partition_psplim);
+ }
+
+ tfm_spm_partition_set_state(caller_partition_idx,
+ SPM_PARTITION_STATE_BLOCKED);
+ tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
+ tfm_secure_lock++;
+
+ return TFM_SUCCESS;
+}
+
+static enum tfm_status_e tfm_start_partition_for_irq_handling(
+ uint32_t excReturn,
+ struct tfm_state_context_t *svc_ctx)
+{
+ uint32_t handler_partition_id = svc_ctx->r0;
+ sfn_t unpriv_handler = (sfn_t)svc_ctx->r1;
+ uint32_t irq_signal = svc_ctx->r2;
+ uint32_t irq_line = svc_ctx->r3;
+ enum tfm_status_e res;
+ uint32_t psp = __get_PSP();
+ uint32_t handler_partition_psp;
+ uint32_t handler_partition_state;
+ uint32_t interrupted_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *handler_part_data;
+ uint32_t handler_partition_idx;
+
+ handler_partition_idx = get_partition_idx(handler_partition_id);
+ handler_part_data = tfm_spm_partition_get_runtime_data(
+ handler_partition_idx);
+ handler_partition_state = handler_part_data->partition_state;
+
+ res = check_irq_partition_state(handler_partition_state);
+ if (res != TFM_SUCCESS) {
+ return res;
+ }
+
+ /* set mask for the partition */
+ tfm_spm_partition_set_signal_mask(
+ handler_partition_idx,
+ handler_part_data->signal_mask | irq_signal);
+
+ tfm_spm_hal_disable_irq(irq_line);
+
+ /* save the current context of the interrupted partition */
+ tfm_spm_partition_push_interrupted_ctx(interrupted_partition_idx);
+
+ handler_partition_psp = psp;
+
+ /* save the current context of the handler partition */
+ tfm_spm_partition_push_handler_ctx(handler_partition_idx);
+
+ /* Store caller for the partition */
+ tfm_spm_partition_set_caller_partition_idx(handler_partition_idx,
+ interrupted_partition_idx);
+
+ psp = (uint32_t)prepare_partition_irq_ctx(svc_ctx, unpriv_handler,
+ (int32_t *)handler_partition_psp);
+ __set_PSP(psp);
+
+ tfm_spm_partition_set_state(interrupted_partition_idx,
+ SPM_PARTITION_STATE_SUSPENDED);
+ tfm_spm_partition_set_state(handler_partition_idx,
+ SPM_PARTITION_STATE_HANDLING_IRQ);
+
+ return TFM_SUCCESS;
+}
+
+static enum tfm_status_e tfm_return_from_partition(uint32_t *excReturn)
+{
+ uint32_t current_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
+ uint32_t current_partition_flags;
+ uint32_t return_partition_idx;
+ uint32_t return_partition_flags;
+ uint32_t psp = __get_PSP();
+ size_t i;
+ struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
+ struct iovec_args_t *iovec_args;
+
+ if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+ curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
+ return_partition_idx = curr_part_data->caller_partition_idx;
+
+ if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+ ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
+
+ return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
+ current_partition_flags = tfm_spm_partition_get_flags(
+ current_partition_idx);
+
+ tfm_secure_lock--;
+
+ if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ (tfm_secure_api_initializing)) {
+ /* In TFM level 1 context restore is only done when
+ * returning to NS or after initialization
+ */
+ /* Restore caller context */
+ restore_caller_ctx(svc_ctx,
+ (struct tfm_state_context_t *)ret_part_data->stack_ptr);
+ *excReturn = ret_part_data->lr;
+ __set_PSP(ret_part_data->stack_ptr);
+ REGION_DECLARE(Image$$, ARM_LIB_STACK, $$ZI$$Base)[];
+ uint32_t psp_stack_bottom =
+ (uint32_t)REGION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Base);
+ tfm_arch_set_psplim(psp_stack_bottom);
+
+ iovec_args = (struct iovec_args_t *)
+ ((uint8_t *)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit) -
+ sizeof(struct iovec_args_t));
+
+ for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
+ curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
+ }
+ tfm_clear_iovec_parameters(iovec_args);
+ }
+
+ tfm_spm_partition_cleanup_context(current_partition_idx);
+
+ tfm_spm_partition_set_state(current_partition_idx,
+ SPM_PARTITION_STATE_IDLE);
+ tfm_spm_partition_set_state(return_partition_idx,
+ SPM_PARTITION_STATE_RUNNING);
+
+ return TFM_SUCCESS;
+}
+
+static enum tfm_status_e tfm_return_from_partition_irq_handling(
+ uint32_t *excReturn)
+{
+ uint32_t handler_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *handler_part_data;
+ uint32_t interrupted_partition_idx;
+ uint32_t psp = __get_PSP();
+ struct tfm_state_context_t *svc_ctx = (struct tfm_state_context_t *)psp;
+
+ if (handler_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+ handler_part_data = tfm_spm_partition_get_runtime_data(
+ handler_partition_idx);
+ interrupted_partition_idx = handler_part_data->caller_partition_idx;
+
+ if (interrupted_partition_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_SECURE_UNLOCK_FAILED;
+ }
+
+ /* For level 1, modify PSP, so that the SVC stack frame disappears,
+ * and return to the privileged handler using the stack frame still on the
+ * MSP stack.
+ */
+ *excReturn = svc_ctx->ra;
+ psp += sizeof(struct tfm_state_context_t);
+
+ tfm_spm_partition_pop_handler_ctx(handler_partition_idx);
+ tfm_spm_partition_pop_interrupted_ctx(interrupted_partition_idx);
+
+ __set_PSP(psp);
+
+ return TFM_SUCCESS;
+}
+
+static enum tfm_status_e tfm_check_sfn_req_integrity(
+ const struct tfm_sfn_req_s *desc_ptr)
+{
+ if ((desc_ptr == NULL) ||
+ (desc_ptr->sp_id == 0) ||
+ (desc_ptr->sfn == NULL)) {
+ /* invalid parameter */
+ return TFM_ERROR_INVALID_PARAMETER;
+ }
+ return TFM_SUCCESS;
+}
+
+static enum tfm_status_e tfm_core_check_sfn_req_rules(
+ const struct tfm_sfn_req_s *desc_ptr)
+{
+ /* Check partition idx validity */
+ if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
+ return TFM_ERROR_NO_ACTIVE_PARTITION;
+ }
+
+ if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
+ /* Secure domain is already locked!
+ * This should only happen if caller is secure partition!
+ */
+ /* This scenario is a potential security breach.
+ * Error is handled in caller.
+ */
+ return TFM_ERROR_SECURE_DOMAIN_LOCKED;
+ }
+
+ if (tfm_secure_api_initializing) {
+ int32_t id =
+ tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
+
+ if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
+ /* Invalid request during system initialization */
+ ERROR_MSG("Invalid service request during initialization!");
+ return TFM_ERROR_NOT_INITIALIZED;
+ }
+ }
+
+ return TFM_SUCCESS;
+}
+
+void tfm_spm_secure_api_init_done(void)
+{
+ tfm_secure_api_initializing = 0;
+}
+
+enum tfm_status_e tfm_spm_sfn_request_handler(
+ struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
+{
+ enum tfm_status_e res;
+
+ res = tfm_check_sfn_req_integrity(desc_ptr);
+ if (res != TFM_SUCCESS) {
+ ERROR_MSG("Invalid service request!");
+ tfm_secure_api_error_handler();
+ }
+
+ __disable_irq();
+
+ desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
+
+ res = tfm_core_check_sfn_parameters(desc_ptr);
+ if (res != TFM_SUCCESS) {
+ /* The sanity check of iovecs failed. */
+ __enable_irq();
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_core_check_sfn_req_rules(desc_ptr);
+ if (res != TFM_SUCCESS) {
+ /* FixMe: error compartmentalization TBD */
+ tfm_spm_partition_set_state(
+ desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
+ __enable_irq();
+ ERROR_MSG("Unauthorized service request!");
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_start_partition(desc_ptr, excReturn);
+ if (res != TFM_SUCCESS) {
+ /* FixMe: consider possible fault scenarios */
+ __enable_irq();
+ ERROR_MSG("Failed to process service request!");
+ tfm_secure_api_error_handler();
+ }
+
+ __enable_irq();
+
+ return res;
+}
+
+int32_t tfm_spm_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
+{
+ enum tfm_status_e res;
+ int32_t *args;
+ int32_t retVal;
+
+ res = tfm_core_check_sfn_parameters(desc_ptr);
+ if (res != TFM_SUCCESS) {
+ /* The sanity check of iovecs failed. */
+ return (int32_t)res;
+ }
+
+ /* No excReturn value is needed as no exception handling is used */
+ res = tfm_spm_sfn_request_handler(desc_ptr, 0);
+
+ if (res != TFM_SUCCESS) {
+ tfm_secure_api_error_handler();
+ }
+
+ /* Secure partition to secure partition call in TFM level 1 */
+ args = desc_ptr->args;
+ retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
+
+ /* return handler should restore original exc_return value... */
+ res = tfm_return_from_partition(NULL);
+ if (res == TFM_SUCCESS) {
+ /* If unlock successful, pass SS return value to caller */
+ return retVal;
+ } else {
+ /* Unlock errors indicate ctx database corruption or unknown
+ * anomalies. Halt execution
+ */
+ ERROR_MSG("Secure API error during unlock!");
+ tfm_secure_api_error_handler();
+ }
+ return (int32_t)res;
+}
+
+void tfm_spm_validate_secure_caller_handler(uint32_t *svc_args)
+{
+
+ enum tfm_status_e res = TFM_ERROR_GENERIC;
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const struct spm_partition_runtime_data_t *curr_part_data =
+ tfm_spm_partition_get_runtime_data(running_partition_idx);
+ uint32_t running_partition_flags =
+ tfm_spm_partition_get_flags(running_partition_idx);
+ uint32_t caller_partition_flags =
+ tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
+
+ if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
+ /* This handler shouldn't be called from outside partition context.
+ * Also if the current partition is handling IRQ, the caller partition
+ * index might not be valid;
+ * Partitions are only allowed to run while S domain is locked.
+ */
+ svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ /* Store return value in r0 */
+ if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
+ res = TFM_SUCCESS;
+ }
+ svc_args[0] = (uint32_t)res;
+}
+
+int32_t tfm_spm_check_buffer_access(uint32_t partition_idx,
+ void *start_addr,
+ size_t len,
+ uint32_t alignment)
+{
+ uintptr_t start_addr_value = (uintptr_t)start_addr;
+ uintptr_t end_addr_value = (uintptr_t)start_addr + len;
+ uintptr_t alignment_mask;
+
+ alignment_mask = (((uintptr_t)1) << alignment) - 1;
+
+ /* Check that the pointer is aligned properly */
+ if (start_addr_value & alignment_mask) {
+ /* not aligned, return error */
+ return 0;
+ }
+
+ /* Protect against overflow (and zero len) */
+ if (end_addr_value <= start_addr_value) {
+ return 0;
+ }
+
+ /* For privileged partition execution, all secure data memory and stack
+ * is accessible
+ */
+ if (start_addr_value >= S_DATA_START &&
+ end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void tfm_spm_get_caller_client_id_handler(uint32_t *svc_args)
+{
+ uintptr_t result_ptr_value = svc_args[0];
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ const uint32_t running_partition_flags =
+ tfm_spm_partition_get_flags(running_partition_idx);
+ const struct spm_partition_runtime_data_t *curr_part_data =
+ tfm_spm_partition_get_runtime_data(running_partition_idx);
+ int res = 0;
+
+ if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_HANDLING_IRQ ||
+ curr_part_data->partition_state == SPM_PARTITION_STATE_SUSPENDED) {
+ /* This handler shouldn't be called from outside partition context.
+ * Also if the current partition is handling IRQ, the caller partition
+ * index might not be valid;
+ * Partitions are only allowed to run while S domain is locked.
+ */
+ svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ /* Make sure that the output pointer points to a memory area that is owned
+ * by the partition
+ */
+ res = tfm_spm_check_buffer_access(running_partition_idx,
+ (void *)result_ptr_value,
+ sizeof(curr_part_data->caller_client_id),
+ 2);
+ if (!res) {
+ /* Not in accessible range, return error */
+ svc_args[0] = (uint32_t)TFM_ERROR_INVALID_PARAMETER;
+ return;
+ }
+
+ *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
+
+ /* Store return value in r0 */
+ svc_args[0] = (uint32_t)TFM_SUCCESS;
+}
+
+/* This SVC handler is called if veneer is running in thread mode */
+uint32_t tfm_spm_partition_request_svc_handler(
+ const uint32_t *svc_ctx, uint32_t excReturn)
+{
+ struct tfm_sfn_req_s *desc_ptr;
+
+ if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
+ /* Service request SVC called with MSP active.
+ * Either invalid configuration for Thread mode or SVC called
+ * from Handler mode, which is not supported.
+ * FixMe: error severity TBD
+ */
+ ERROR_MSG("Service request SVC called with MSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
+
+ if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
+ tfm_secure_api_error_handler();
+ }
+
+ return EXC_RETURN_SECURE_FUNCTION;
+}
+
+/* This SVC handler is called, if a thread mode execution environment is to
+ * be set up, to run an unprivileged IRQ handler
+ */
+uint32_t tfm_spm_depriv_req_handler(uint32_t *svc_args, uint32_t excReturn)
+{
+ struct tfm_state_context_t *svc_ctx =
+ (struct tfm_state_context_t *)svc_args;
+
+ enum tfm_status_e res;
+
+ if (excReturn & EXC_RETURN_STACK_PROCESS) {
+ /* FixMe: error severity TBD */
+ ERROR_MSG("Partition request SVC called with PSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_start_partition_for_irq_handling(excReturn, svc_ctx);
+ if (res != TFM_SUCCESS) {
+ /* The partition is in an invalid state (UNINIT or CLOSED), so none of
+ * its code can be run
+ */
+ /* FixMe: For now this case is handled with TF-M panic, however it would
+ * be possible to skip the execution of the interrupt handler, and
+ * resume the execution of the interrupted code.
+ */
+ tfm_secure_api_error_handler();
+ }
+ return EXC_RETURN_SECURE_FUNCTION;
+}
+
+/* This SVC handler is called when sfn returns */
+uint32_t tfm_spm_partition_return_handler(uint32_t lr)
+{
+ enum tfm_status_e res;
+
+ if (!(lr & EXC_RETURN_STACK_PROCESS)) {
+ /* Partition return SVC called with MSP active.
+ * This should not happen!
+ */
+ ERROR_MSG("Partition return SVC called with MSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_return_from_partition(&lr);
+ if (res != TFM_SUCCESS) {
+ /* Unlock errors indicate ctx database corruption or unknown anomalies
+ * Halt execution
+ */
+ ERROR_MSG("Secure API error during unlock!");
+ tfm_secure_api_error_handler();
+ }
+
+ return lr;
+}
+
+/* This SVC handler is called if a deprivileged IRQ handler was executed, and
+ * the execution environment is to be set back for the privileged handler mode
+ */
+uint32_t tfm_spm_depriv_return_handler(uint32_t *irq_svc_args, uint32_t lr)
+{
+ enum tfm_status_e res;
+ struct tfm_state_context_t *irq_svc_ctx =
+ (struct tfm_state_context_t *)irq_svc_args;
+
+ if (!(lr & EXC_RETURN_STACK_PROCESS)) {
+ /* Partition request SVC called with MSP active.
+ * FixMe: error severity TBD
+ */
+ ERROR_MSG("Partition request SVC called with MSP active!");
+ tfm_secure_api_error_handler();
+ }
+
+ res = tfm_return_from_partition_irq_handling(&lr);
+ if (res != TFM_SUCCESS) {
+ /* Unlock errors indicate ctx database corruption or unknown anomalies
+ * Halt execution
+ */
+ ERROR_MSG("Secure API error during unlock!");
+ tfm_secure_api_error_handler();
+ }
+
+ irq_svc_ctx->ra = lr;
+
+ return EXC_RETURN_SECURE_HANDLER;
+}
+
+/* FIXME: get_irq_line_for_signal is also implemented in the ipc folder. */
+/**
+ * \brief Return the IRQ line number associated with a signal
+ *
+ * \param[in] partition_id The ID of the partition in which we look for the
+ * signal
+ * \param[in] signal The signal we do the query for
+ *
+ * \retval >=0 The IRQ line number associated with a signal in the partition
+ * \retval <0 error
+ */
+static int32_t get_irq_line_for_signal(int32_t partition_id,
+ psa_signal_t signal)
+{
+ size_t i;
+
+ for (i = 0; i < tfm_core_irq_signals_count; ++i) {
+ if (tfm_core_irq_signals[i].partition_id == partition_id &&
+ tfm_core_irq_signals[i].signal_value == signal) {
+ return tfm_core_irq_signals[i].irq_line;
+ }
+ }
+ return -1;
+}
+
+void tfm_spm_enable_irq_handler(uint32_t *svc_args)
+{
+ struct tfm_state_context_t *svc_ctx =
+ (struct tfm_state_context_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->r0;
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ uint32_t running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ int32_t irq_line;
+
+ /* Only a single signal is allowed */
+ if (!tfm_is_one_bit_set(irq_signal)) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_enable_irq(irq_line);
+}
+
+void tfm_spm_disable_irq_handler(uint32_t *svc_args)
+{
+ struct tfm_state_context_t *svc_ctx =
+ (struct tfm_state_context_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->r0;
+ uint32_t running_partition_idx =
+ tfm_spm_partition_get_running_partition_idx();
+ uint32_t running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ int32_t irq_line;
+
+ /* Only a single signal is allowed */
+ if (!tfm_is_one_bit_set(irq_signal)) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_disable_irq(irq_line);
+}
+
+void tfm_spm_psa_wait(uint32_t *svc_args)
+{
+ /* Look for partition that is ready for run */
+ struct tfm_state_context_t *svc_ctx =
+ (struct tfm_state_context_t *)svc_args;
+ uint32_t running_partition_idx;
+ const struct spm_partition_runtime_data_t *curr_part_data;
+
+ psa_signal_t signal_mask = svc_ctx->r0;
+ uint32_t timeout = svc_ctx->r1;
+
+ /*
+ * Timeout[30:0] are reserved for future use.
+ * SPM must ignore the value of RES.
+ */
+ timeout &= PSA_TIMEOUT_MASK;
+
+ running_partition_idx = tfm_spm_partition_get_running_partition_idx();
+ curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
+
+ if (timeout == PSA_BLOCK) {
+ /* FIXME: Scheduling is not available in library model, and busy wait is
+ * also not possible as this code is running in SVC context, and it
+ * cannot be pre-empted by interrupts. So do nothing here for now
+ */
+ (void) signal_mask;
+ }
+
+ svc_ctx->r0 = curr_part_data->signal_mask;
+}
+
+void tfm_spm_psa_eoi(uint32_t *svc_args)
+{
+ struct tfm_state_context_t *svc_ctx =
+ (struct tfm_state_context_t *)svc_args;
+ psa_signal_t irq_signal = svc_ctx->r0;
+ uint32_t signal_mask;
+ uint32_t running_partition_idx;
+ uint32_t running_partition_id;
+ const struct spm_partition_runtime_data_t *curr_part_data;
+ int32_t irq_line;
+
+ running_partition_idx = tfm_spm_partition_get_running_partition_idx();
+ running_partition_id =
+ tfm_spm_partition_get_partition_id(running_partition_idx);
+ curr_part_data = tfm_spm_partition_get_runtime_data(running_partition_idx);
+
+ /* Only a single signal is allowed */
+ if (!tfm_is_one_bit_set(irq_signal)) {
+ tfm_secure_api_error_handler();
+ }
+
+ irq_line = get_irq_line_for_signal(running_partition_id, irq_signal);
+
+ if (irq_line < 0) {
+ /* FixMe: error severity TBD */
+ tfm_secure_api_error_handler();
+ }
+
+ tfm_spm_hal_clear_pending_irq(irq_line);
+ tfm_spm_hal_enable_irq(irq_line);
+
+ signal_mask = curr_part_data->signal_mask & ~irq_signal;
+ tfm_spm_partition_set_signal_mask(running_partition_idx, signal_mask);
+}
/*
* This function is called when a secure partition causes an error.
@@ -33,10 +1073,8 @@
*/
static void tfm_spm_partition_err_handler(
const struct spm_partition_desc_t *partition,
- sp_error_type_t err_type,
int32_t err_code)
{
- (void)err_type;
(void)err_code;
tfm_spm_partition_set_state(partition->static_data->partition_id,
@@ -68,7 +1106,7 @@
if (part->static_data->partition_init == NULL) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
tfm_spm_partition_set_caller_partition_idx(idx,
- SPM_INVALID_PARTITION_IDX);
+ SPM_INVALID_PARTITION_IDX);
} else {
int32_t res;
@@ -80,13 +1118,13 @@
if (res == TFM_SUCCESS) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
} else {
- tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, res);
+ tfm_spm_partition_err_handler(part, res);
fail_cnt++;
}
}
}
- tfm_secure_api_init_done();
+ tfm_spm_secure_api_init_done();
if (fail_cnt == 0) {
return SPM_ERR_OK;