SPM: Library mode SPM processing optimisations
This patch moves the bulk of SPM processing in Library mode
to request or return from a secure partition from Handler
to Secure Privileged Thread mode. It also allows the SPM
functions to be pre-empted by secure IRQs in order to reduce
interrupts servicing latency.
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: Iadd96438514d3ffb62f4a60050460617a2b83846
diff --git a/secure_fw/spm/cmsis_func/arch.c b/secure_fw/spm/cmsis_func/arch.c
index 9d45336..bf637da 100644
--- a/secure_fw/spm/cmsis_func/arch.c
+++ b/secure_fw/spm/cmsis_func/arch.c
@@ -57,6 +57,15 @@
}
__attribute__((naked))
+void tfm_sfn_completion(enum tfm_status_e res, uint32_t exc_return, uintptr_t msp)
+{
+ __ASM volatile("MSR msp, r2\n"
+ "SVC %0\n"
+ "BX LR\n"
+ : : "I" (TFM_SVC_SFN_COMPLETION) : );
+}
+
+__attribute__((naked))
static psa_signal_t psa_wait_internal(psa_signal_t signal_mask,
uint32_t timeout)
{
@@ -84,6 +93,12 @@
}
__attribute__((naked))
+void tfm_arch_trigger_exc_return(uint32_t exc_return)
+{
+ __ASM volatile("BX R0");
+}
+
+__attribute__((naked))
void psa_eoi(psa_signal_t irq_signal)
{
__ASM("SVC %0\n"
diff --git a/secure_fw/spm/cmsis_func/arch.h b/secure_fw/spm/cmsis_func/arch.h
index 556f0de..c483d7c 100644
--- a/secure_fw/spm/cmsis_func/arch.h
+++ b/secure_fw/spm/cmsis_func/arch.h
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*
*/
+#include <stdint.h>
+#include "tfm_api.h"
#ifndef __ARCH_H__
#define __ARCH_H__
@@ -24,4 +26,27 @@
*/
void jump_to_ns_code(void);
+/**
+ * \brief Trigger EXC_RETURN
+ *
+ * \param[in] exc_return The EXC_RETURN value to initiate the return
+ * procedure
+ *
+ * \returns Does not return
+ */
+void tfm_arch_trigger_exc_return(uint32_t exc_return);
+
+/**
+ * \brief Trigger an sfn request/return completion from Thread mode
+ *
+ * \param[in] res The tfm_status_e return value to report back to SPM
+ * \param[in] exc_return The EXC_RETURN value to use to return from the original
+ * request/return
+ * \param[in] msp The value of the top of the MSP to reset the MSP before
+ * trigger the TFM_SVC_SFN_COMPLETION
+ *
+ * \return Does not return
+ */
+void tfm_sfn_completion(enum tfm_status_e res, uint32_t exc_return, uintptr_t msp);
+
#endif /* __ARCH_H__ */
diff --git a/secure_fw/spm/cmsis_func/include/spm_func.h b/secure_fw/spm/cmsis_func/include/spm_func.h
index 2fbaa25..568b456 100644
--- a/secure_fw/spm/cmsis_func/include/spm_func.h
+++ b/secure_fw/spm/cmsis_func/include/spm_func.h
@@ -13,6 +13,7 @@
#include "spm_partition_defs.h"
#include "tfm_arch.h"
#include "psa/client.h"
+#include "tfm_api.h"
#define SPM_PARTITION_STATE_UNINIT 0
#define SPM_PARTITION_STATE_IDLE 1
@@ -271,16 +272,17 @@
void tfm_spm_secure_api_init_done(void);
/**
- * \brief Called if veneer is running in thread mode
+ * \brief Called for requests or returns from partition
*/
-uint32_t tfm_spm_partition_request_svc_handler(
- const uint32_t *svc_args, uint32_t lr);
+void tfm_spm_partition_request_return_handler(
+ const uint32_t *svc_args, uint32_t exc_return, uint32_t *msp);
/**
- * \brief Called when secure service returns
+ * \brief Called when SPM has completed a partition request or return
*/
-uint32_t tfm_spm_partition_return_handler(uint32_t lr);
-
+void tfm_spm_partition_completion_handler(enum tfm_status_e res,
+ uint32_t exc_return,
+ uint32_t *msp);
/**
* \brief Stores caller's client id in state context
*/
diff --git a/secure_fw/spm/cmsis_func/include/tfm_core_svc.h b/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
index 1c06a33..ce4eed8 100644
--- a/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
+++ b/secure_fw/spm/cmsis_func/include/tfm_core_svc.h
@@ -15,6 +15,7 @@
#define TFM_SVC_PSA_EOI (0x1)
#define TFM_SVC_SFN_REQUEST (0x2)
#define TFM_SVC_SFN_RETURN (0x3)
+#define TFM_SVC_SFN_COMPLETION (0x4)
#define TFM_SVC_SPM_REQUEST (0x5)
#define TFM_SVC_GET_BOOT_DATA (0x6)
#define TFM_SVC_DEPRIV_REQ (0x7)
diff --git a/secure_fw/spm/cmsis_func/spm_func.c b/secure_fw/spm/cmsis_func/spm_func.c
index 443ea02..252716e 100644
--- a/secure_fw/spm/cmsis_func/spm_func.c
+++ b/secure_fw/spm/cmsis_func/spm_func.c
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <arm_cmse.h>
+#include "arch.h"
#include "bitops.h"
#include "fih.h"
#include "tfm_nspm.h"
@@ -789,7 +790,7 @@
tfm_secure_api_initializing = 0;
}
-enum tfm_status_e tfm_spm_sfn_request_handler(
+static enum tfm_status_e tfm_spm_sfn_request_handler(
struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
{
enum tfm_status_e res;
@@ -801,14 +802,11 @@
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, &iovecs);
if (res != TFM_SUCCESS) {
/* The sanity check of iovecs failed. */
- __enable_irq();
tfm_secure_api_error_handler();
}
@@ -817,7 +815,6 @@
/* FixMe: error compartmentalization TBD */
tfm_spm_partition_set_state(
desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
- __enable_irq();
SPMLOG_ERRMSG("Unauthorized service request!\r\n");
tfm_secure_api_error_handler();
}
@@ -825,13 +822,10 @@
res = tfm_start_partition(desc_ptr, &iovecs, excReturn);
if (res != TFM_SUCCESS) {
/* FixMe: consider possible fault scenarios */
- __enable_irq();
SPMLOG_ERRMSG("Failed to process service request!\r\n");
tfm_secure_api_error_handler();
}
- __enable_irq();
-
return res;
}
@@ -900,13 +894,30 @@
return TFM_ERROR_INVALID_PARAMETER;
}
-/* 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)
+static void tfm_spm_partition_requests_thread(struct tfm_sfn_req_s *desc_ptr,
+ uint32_t exc_return,
+ uint32_t is_return,
+ uintptr_t msp)
{
- struct tfm_sfn_req_s *desc_ptr;
+ enum tfm_status_e res;
+ uint32_t exc_ret;
- if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
+ if (!is_return) {
+ res = tfm_spm_sfn_request_handler(desc_ptr, exc_return);
+ exc_ret = EXC_RETURN_SECURE_FUNCTION;
+ } else {
+ res = tfm_return_from_partition(&exc_return);
+ exc_ret = exc_return;
+ }
+ /* Reset MSP at top of stack and do TFM_SVC_SFN_COMPLETION */
+ tfm_sfn_completion(res, exc_ret, msp);
+}
+
+/* This SVC handler is called if veneer is running in thread mode */
+void tfm_spm_partition_request_return_handler(
+ const uint32_t *svc_ctx, uint32_t exc_return, uint32_t *msp)
+{
+ if (!(exc_return & 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.
@@ -916,13 +927,37 @@
tfm_secure_api_error_handler();
}
- desc_ptr = (struct tfm_sfn_req_s *)svc_ctx[0];
+ /* Setup a context on the stack to trigger exception return */
+ struct tfm_state_context_t ctx = {0};
- if (tfm_spm_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
+ ctx.r0 = svc_ctx ? svc_ctx[0] : (uintptr_t) NULL;
+ ctx.r1 = exc_return;
+ ctx.r2 = svc_ctx ? 0 : 1;
+ ctx.r3 = (uintptr_t) msp;
+ ctx.xpsr = XPSR_T32;
+ ctx.ra = (uint32_t) tfm_spm_partition_requests_thread & ~0x1UL;
+
+ __set_MSP((uint32_t)&ctx);
+
+ tfm_arch_trigger_exc_return(EXC_RETURN_THREAD_S_MSP);
+}
+
+void tfm_spm_partition_completion_handler(enum tfm_status_e res, uint32_t exc_return, uint32_t *msp)
+{
+ if (res != TFM_SUCCESS) {
tfm_secure_api_error_handler();
}
- return EXC_RETURN_SECURE_FUNCTION;
+ uint32_t msp_stack_val = (uint32_t)msp + sizeof(struct tfm_state_context_t);
+
+ /* Equivalent to a call to __set_MSP() and then tfm_arch_trigger_exc_return
+ * with the exc_return value received as parameter in the handler
+ */
+ __ASM volatile (
+ "MSR msp, %0\n"
+ "MOV R0, %1\n"
+ "BX R0"
+ : : "r" (msp_stack_val), "r" (exc_return) : );
}
/* This SVC handler is called, if a thread mode execution environment is to
@@ -955,31 +990,6 @@
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
*/
diff --git a/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c b/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
index a06edc1..e6412a5 100644
--- a/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
+++ b/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
@@ -28,7 +28,6 @@
*/
#include "tfm_secure_irq_handlers.inc"
-
uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return)
{
uint8_t svc_number = 0;
@@ -61,10 +60,13 @@
}
switch (svc_number) {
case TFM_SVC_SFN_REQUEST:
- retval = tfm_spm_partition_request_svc_handler(svc_args, exc_return);
+ tfm_spm_partition_request_return_handler(svc_args, exc_return, msp);
break;
case TFM_SVC_SFN_RETURN:
- retval = tfm_spm_partition_return_handler(exc_return);
+ tfm_spm_partition_request_return_handler(NULL, exc_return, msp);
+ break;
+ case TFM_SVC_SFN_COMPLETION:
+ tfm_spm_partition_completion_handler(svc_args[0], svc_args[1], msp);
break;
case TFM_SVC_SPM_REQUEST:
tfm_spm_request_handler((struct tfm_state_context_t *)svc_args);