Core: Thread mode transition from NS to S
Change TF-M Core to require NS client to make secure
function requests in thread mode instead of handler
mode.
Different secure API options of DEPRIORITIZE and
SVCCLEAR are obsolete, remove them.
Clear registers on secure function entry to avoid
leaking data.
Set AIRCR.PRIS flag by default to avoid NS pre-emption
of secure fault handler and SVC handlers.
Change-Id: Ib771485ebc6b28c0080316ab8d028ba9849a9fcb
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/app/tfm_integ_test.c b/app/tfm_integ_test.c
index acef4d6..37421fb 100644
--- a/app/tfm_integ_test.c
+++ b/app/tfm_integ_test.c
@@ -92,8 +92,7 @@
TEST_TYPE_6 /*!< Like TEST_TYPE_2, but the high priority task has now a
timeout to acquire the NS lock. The timeout will
expire only if TFM Core is built with the
- de-prioritization disabled (i.e. TFM_API_SVCCLEAR
- defined) */
+ de-prioritization disabled */
};
static const osThreadAttr_t tattr_seq = {
diff --git a/secure_fw/core/secure_utilities.h b/secure_fw/core/secure_utilities.h
index 8f12bb4..9630bc0 100644
--- a/secure_fw/core/secure_utilities.h
+++ b/secure_fw/core/secure_utilities.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -24,6 +24,17 @@
#define EXC_NUM_PENDSV (14)
#define EXC_NUM_SYSTICK (15)
+struct tfm_exc_stack_t {
+ uint32_t R0;
+ uint32_t R1;
+ uint32_t R2;
+ uint32_t R3;
+ uint32_t R12;
+ uint32_t LR;
+ uint32_t RetAddr;
+ uint32_t XPSR;
+};
+
#ifdef TFM_CORE_DEBUG
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
#else
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index 0cb5afc..0905714 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -9,6 +9,7 @@
#include "region_defs.h"
#include "tfm_core.h"
#include "tfm_internal.h"
+#include "tfm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "uart_stdout.h"
#include "secure_utilities.h"
@@ -147,6 +148,24 @@
return 0;
}
+static int32_t tfm_core_set_secure_exception_priorities(void)
+{
+ uint32_t VECTKEY;
+ SCB_Type *scb = SCB;
+ uint32_t AIRCR;
+
+ /* Set PRIS flag is AIRCR */
+ AIRCR = scb->AIRCR;
+ VECTKEY = (~AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
+ scb->AIRCR = SCB_AIRCR_PRIS_Msk |
+ VECTKEY |
+ (AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
+
+ /* FixMe: Explicitly set secure fault and Secure SVC priority to highest */
+
+ return TFM_SUCCESS;
+}
+
int main(void)
{
tfm_core_init();
@@ -179,5 +198,10 @@
tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
SPM_PARTITION_STATE_RUNNING);
+ /* Prioritise secure exceptions to avoid NS being able to pre-empt secure
+ * SVC or SecureFault
+ */
+ tfm_core_set_secure_exception_priorities();
+
jump_to_ns_code();
}
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index 61c0236..2e8b805 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -17,16 +17,16 @@
#include "tfm_api.h"
/* This SVC handler is called if veneer is running in thread mode */
-extern void tfm_core_partition_request_svc_handler(
- uint32_t *svc_args, uint32_t *lr_ptr);
+extern uint32_t tfm_core_partition_request_svc_handler(
+ uint32_t *svc_args, uint32_t lr);
/* This SVC handler is called when sfn returns */
-extern int32_t tfm_core_partition_return_handler(uint32_t *lr_ptr);
+extern uint32_t tfm_core_partition_return_handler(uint32_t lr);
-extern int32_t
+extern void
tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
-extern int32_t
+extern void
tfm_core_memory_permission_check_handler(const uint32_t svc_args[]);
/* This SVC handler is called when a secure partition requests access to a
@@ -108,14 +108,13 @@
{
__ASM(
"TST lr, #4\n" /* Check store SP in thread mode to r0 */
- "ITE EQ\n"
- "MRSEQ r0, MSP\n"
- "MRSNE r0, PSP\n"
- "PUSH {r0, lr}\n"
- "MOV r1, sp\n"
- "ADD r1, r1, #4\n"
+ "IT EQ\n"
+ "BXEQ lr\n"
+ "MRS r0, PSP\n"
+ "MOV r1, lr\n"
"BL SVCHandler_main\n"
- "POP {r1, pc}\n");
+ "BX r0\n"
+ );
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) void SVC_Handler(void)
@@ -129,20 +128,18 @@
"MRS r0, PSP\n" /* Coming from thread mode */
"B sp_stored\n"
"handler:\n"
- "MRS r0, MSP\n" /* Coming from handler mode */
+ "BX lr\n" /* Coming from handler mode */
"sp_stored:\n"
- "PUSH {r0, lr}\n"
- "MOV r1, sp\n"
- "ADDS r1, r1, #4\n"
+ "MOV r1, lr\n"
"BL SVCHandler_main\n"
- "POP {r1, pc}\n");
+ "BX r0\n"
+ );
}
#else
#error "Unsupported ARM Architecture."
#endif
-
-int32_t SVCHandler_main(uint32_t *svc_args, uint32_t *lr_ptr)
+uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr)
{
uint8_t svc_number;
/*
@@ -150,7 +147,7 @@
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
* First argument (r0) is svc_args[0]
*/
- if (*lr_ptr & EXC_RETURN_SECURE_STACK) {
+ if (lr & EXC_RETURN_SECURE_STACK) {
/* SV called directly from secure context. Check instruction for
* svc_number
*/
@@ -160,32 +157,33 @@
* NS cannot directly trigger S SVC so this should not happen
* FixMe: check for security implications
*/
- return TFM_ERROR_GENERIC;
+ return lr;
}
switch (svc_number) {
case TFM_SVC_SFN_REQUEST:
- tfm_core_partition_request_svc_handler(svc_args, lr_ptr);
- return TFM_SUCCESS;
+ lr = tfm_core_partition_request_svc_handler(svc_args, lr);
+ break;
case TFM_SVC_SFN_RETURN:
- return tfm_core_partition_return_handler(lr_ptr);
+ lr = tfm_core_partition_return_handler(lr);
+ break;
case TFM_SVC_VALIDATE_SECURE_CALLER:
tfm_core_validate_secure_caller_handler(svc_args);
- return TFM_SUCCESS;
+ break;
case TFM_SVC_MEMORY_CHECK:
tfm_core_memory_permission_check_handler(svc_args);
- return TFM_SUCCESS;
+ break;
case TFM_SVC_SET_SHARE_AREA:
tfm_core_set_buffer_area_handler(svc_args);
- return TFM_SUCCESS;
+ break;
case TFM_SVC_PRINT:
printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
- return TFM_SUCCESS;
+ break;
default:
LOG_MSG("Unknown SVC number requested!");
break;
}
- return TFM_ERROR_GENERIC;
+ return lr;
}
void tfm_access_violation_handler(void)
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index 1ffe46a..280c266 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -16,8 +16,7 @@
#include "region_defs.h"
#include "tfm_api.h"
-/* NOTE: this does not account for possible FP stacking */
-#define SVC_STACK_FRAME_SIZE 0x20
+#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
#ifndef TFM_LVL
#error TFM_LVL is not defined!
@@ -41,15 +40,17 @@
static int32_t tfm_secure_lock;
static int32_t tfm_secure_api_init = 1;
-static uint32_t *prepare_partition_ctx(
- struct tfm_sfn_req_s *desc_ptr, uint32_t *dst)
+static int32_t *prepare_partition_ctx(
+ struct tfm_exc_stack_t *svc_ctx,
+ struct tfm_sfn_req_s *desc_ptr,
+ int32_t *dst)
{
- /* XPSR = Thumb, nothing else */
- *(--dst) = 0x01000000;
- /* ReturnAddress = sfn to be executed */
- *(--dst) = (uint32_t)(desc_ptr->sfn);
- /* LR = function to be called when sfn exits */
- *(--dst) = (uint32_t)tfm_core_partition_return_svc;
+ /* XPSR = as was when called, but make sure it's thread mode */
+ *(--dst) = svc_ctx->XPSR & 0xFFFFFE00;
+ /* ReturnAddress = resume veneer in new context */
+ *(--dst) = svc_ctx->RetAddr;
+ /* LR = sfn address */
+ *(--dst) = (int32_t)desc_ptr->sfn;
/* R12 = don't care */
*(--dst) = 0;
@@ -63,17 +64,31 @@
return dst;
}
-static int32_t tfm_push_lock(struct tfm_sfn_req_s *desc_ptr, uint32_t lr)
+static void restore_caller_ctx(
+ struct tfm_exc_stack_t *svc_ctx,
+ struct tfm_exc_stack_t *target_ctx)
+{
+ /* ReturnAddress = resume veneer after second SVC */
+ target_ctx->RetAddr = svc_ctx->RetAddr;
+
+ /* R0 = function return value */
+ target_ctx->R0 = svc_ctx->R0;
+
+ return;
+}
+
+static int32_t tfm_push_lock(struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
{
uint32_t caller_partition_idx =
tfm_spm_partition_get_running_partition_idx();
const struct spm_partition_runtime_data_t *curr_part_data;
uint32_t caller_flags;
register uint32_t partition_idx;
- uint32_t psp;
+ uint32_t psp = __get_PSP();
uint32_t partition_psp, partition_psplim;
uint32_t partition_state;
uint32_t partition_flags;
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
/* Check partition idx validity */
if (caller_partition_idx == SPM_INVALID_PARTITION_IDX) {
@@ -89,7 +104,6 @@
}
partition_idx = get_partition_idx(desc_ptr->sp_id);
- psp = __get_PSP();
curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
partition_state = curr_part_data->partition_state;
@@ -130,21 +144,13 @@
partition_psplim =
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
#else
- if (caller_flags&SPM_PART_FLAG_SECURE) {
- /* Store the caller PSP in case we are doing a partition to
- * partition call
- */
- tfm_spm_partition_set_stack(caller_partition_idx, psp);
- }
partition_psp = curr_part_data->stack_ptr;
partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
#endif
- /* Stack the context for the partition call */
- tfm_spm_partition_set_orig_psp(partition_idx, psp);
- tfm_spm_partition_set_orig_psplim(partition_idx, __get_PSPLIM());
- tfm_spm_partition_set_orig_lr(partition_idx, lr);
+ /* 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 (TFM_LVL != 1) && (TFM_LVL != 2)
/* Dynamic partitioning is only done is TFM level 3 */
@@ -168,17 +174,17 @@
/* In level one, only switch context and return from exception if in
* handler mode
*/
- if ((desc_ptr->exc_num != EXC_NUM_THREAD_MODE) || (tfm_secure_api_init)) {
+ if ((desc_ptr->ns_caller) || (tfm_secure_api_init)) {
/* Prepare the partition context, update stack ptr */
psp = (uint32_t)prepare_partition_ctx(
- desc_ptr, (uint32_t *)partition_psp);
+ svc_ctx, desc_ptr, (int32_t *)partition_psp);
__set_PSP(psp);
__set_PSPLIM(partition_psplim);
}
#else
/* Prepare the partition context, update stack ptr */
- psp = (uint32_t)prepare_partition_ctx(desc_ptr,
- (uint32_t *)partition_psp);
+ psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
+ (int32_t *)partition_psp);
__set_PSP(psp);
__set_PSPLIM(partition_psplim);
#endif
@@ -191,17 +197,16 @@
return TFM_SUCCESS;
}
-static int32_t tfm_pop_lock(uint32_t *lr_ptr)
+static int32_t tfm_pop_lock(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;
+ 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;
-#if TFM_LVL != 1
- uint32_t psp;
-#endif
+ uint32_t psp = __get_PSP();
+ struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
return TFM_SECURE_UNLOCK_FAILED;
@@ -214,6 +219,8 @@
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);
@@ -255,30 +262,31 @@
#endif
#if TFM_LVL == 1
- if (!(return_partition_flags&SPM_PART_FLAG_SECURE) ||
+ if (!(return_partition_flags & SPM_PART_FLAG_SECURE) ||
(tfm_secure_api_init)) {
/* In TFM level 1 context restore is only done when
* returning to NS or after initialization
*/
- /* Restore caller PSP and LR ptr */
- __set_PSP(curr_part_data->orig_psp);
- __set_PSPLIM(curr_part_data->orig_psplim);
- *lr_ptr = curr_part_data->orig_lr;
+ /* Restore caller context */
+ restore_caller_ctx(svc_ctx,
+ (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
+ *excReturn = ret_part_data->lr;
+ __set_PSP(ret_part_data->stack_ptr);
+ extern uint32_t Stack_Mem[];
+ __set_PSPLIM((uint32_t)Stack_Mem);
}
#else
- psp = __get_PSP();
-
- /* Discount SVC call stack frame when storing sfn ctx */
+ /* Restore caller context */
+ restore_caller_ctx(svc_ctx,
+ (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
+ *excReturn = ret_part_data->lr;
+ __set_PSP(ret_part_data->stack_ptr);
+ __set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
+ /* Clear the context entry before returning */
tfm_spm_partition_set_stack(
- current_partition_idx, psp + SVC_STACK_FRAME_SIZE);
-
- /* Restore caller PSP and LR ptr */
- __set_PSP(curr_part_data->orig_psp);
- __set_PSPLIM(curr_part_data->orig_psplim);
- *lr_ptr = curr_part_data->orig_lr;
+ current_partition_idx, psp - sizeof(struct tfm_exc_stack_t));
#endif
- /* Clear the context entry in the context stack before returning */
tfm_spm_partition_cleanup_context(current_partition_idx);
tfm_spm_partition_set_state(current_partition_idx,
@@ -293,7 +301,7 @@
void tfm_secure_api_error_handler(void)
{
- ERROR_MSG("Secure fault when calling secure API");
+ ERROR_MSG("Security violation when calling secure API");
while (1) {
;
}
@@ -313,145 +321,25 @@
static int32_t tfm_core_check_sfn_req_rules(
struct tfm_sfn_req_s *desc_ptr)
{
- if ((desc_ptr->exc_num != EXC_NUM_THREAD_MODE) &&
- (desc_ptr->exc_num != EXC_NUM_SVCALL)) {
+ if (desc_ptr->exc_num != EXC_NUM_THREAD_MODE) {
+ /* Veneer should not be called from handler mode!
+ * FixMe: this is potential attack, trigger fault handling
+ */
return TFM_ERROR_INVALID_EXC_MODE;
}
- if (desc_ptr->ns_caller) {
- if (desc_ptr->exc_num == EXC_NUM_THREAD_MODE) {
- /* Veneer should not be called from NS thread mode!
- * FixMe: this is potential attack, trigger fault handling
- */
- return TFM_ERROR_NS_THREAD_MODE_CALL;
- }
- if (tfm_secure_lock != 0) {
- /* Secure domain is already locked!
- * This should only happen if caller is secure partition!
- * FixMe: This scenario is a potential security breach
- * Take appropriate action!
- */
- return TFM_ERROR_SECURE_DOMAIN_LOCKED;
- }
- } else {
- if (desc_ptr->exc_num != EXC_NUM_THREAD_MODE) {
- /* Secure partition can only call a different secure partition
- * from thread mode
- */
- return TFM_ERROR_INVALID_EXC_MODE;
- }
+ if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
+ /* Secure domain is already locked!
+ * This should only happen if caller is secure partition!
+ * FixMe: This scenario is a potential security breach
+ * Take appropriate action!
+ */
+ return TFM_ERROR_SECURE_DOMAIN_LOCKED;
}
- return TFM_SUCCESS;
-}
-
-static union ns_state_u {
- uint32_t AIRCR;
- uint32_t SHCSR_NS;
-} ns_state;
-
-static int32_t tfm_core_configure_secure_exception(void)
-{
-#ifdef TFM_API_DEPRIORITIZE
- uint32_t VECTKEY;
- SCB_Type *scb = SCB;
-
- ns_state.AIRCR = scb->AIRCR;
- VECTKEY = (~ns_state.AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
-#endif
-
- SCB->SHCSR |= SCB_SHCSR_SVCALLACT_Msk;
-
-#ifdef TFM_API_DEPRIORITIZE
- scb->AIRCR = SCB_AIRCR_PRIS_Msk |
- VECTKEY |
- (ns_state.AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
-#elif defined(TFM_API_SVCCLEAR)
- ns_state.SHCSR_NS = SCB_NS->SHCSR;
- SCB_NS->SHCSR &= ~SCB_SHCSR_SVCALLACT_Msk;
-#endif
return TFM_SUCCESS;
}
-static int32_t tfm_core_deconfigure_secure_exception(void)
-{
-#ifdef TFM_API_DEPRIORITIZE
- SCB_Type *scb = SCB;
- uint32_t VECTKEY = (~ns_state.AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
-
- scb->AIRCR = (~SCB_AIRCR_PRIS_Msk) &
- (VECTKEY | (ns_state.AIRCR & ~SCB_AIRCR_VECTKEY_Msk));
-#elif defined(TFM_API_SVCCLEAR)
- SCB_NS->SHCSR = ns_state.SHCSR_NS;
-#endif
- SCB->SHCSR &= ~SCB_SHCSR_SVCALLACT_Msk;
-
- /*
- * SPSEL value is cleared by HW when entering Handler mode (e.g.
- * partition return SVC).
- * If execution is returned to NS instead of performing an Exception
- * return, HW will not restore original SPSEL value so this has to
- * be done manually.
- */
- __set_CONTROL_SPSEL(1);
-
- return TFM_SUCCESS;
-}
-
-#if defined(__ARM_ARCH_8M_MAIN__)
-__attribute__((naked)) static int32_t tfm_core_exc_return_to_sfn(void)
-{
- /* Save all callee-saved registers to prevent malicious partition from
- * modifying execution state.
- * Save LR for return address.
- * r12 is used as padding for 8-byte stack alignment
- */
- __ASM(
- "PUSH {r4-r12, lr}\n"
- "MVN r0, #2\n"
- "BX r0\n"
-"return_from_sfn:\n"
- "POP {r4-r12, pc}\n");
-}
-#elif defined(__ARM_ARCH_8M_BASE__)
-__attribute__((naked)) static int32_t tfm_core_exc_return_to_sfn(void)
-{
- /* Save all callee-saved registers to prevent malicious partition from
- * modifying execution state.
- * Save LR for return address.
- * r12 is used as padding for 8-byte stack alignment
- */
- __ASM(
- ".syntax unified\n"
- "PUSH {lr}\n"
- "PUSH {r4-r7}\n"
- "MOV r4, r8\n"
- "MOV r5, r9\n"
- "MOV r6, r10\n"
- "MOV r7, r11\n"
- "PUSH {r4-r7}\n"
- "MOV r4, r12\n"
- "PUSH {r4}\n"
- "MOVS r0, #2\n"
- "MVNS r0, r0\n"
- "BX r0\n"
-"return_from_sfn:\n"
- "POP {r4}\n"
- "MOV r12, r4\n"
- "POP {r4-r7}\n"
- "MOV r8, r4\n"
- "MOV r9, r5\n"
- "MOV r10, r6\n"
- "MOV r11, r7\n"
- "POP {r4-r7}\n"
- "POP {pc}\n");
-}
-#else
-#error "Unsupported ARM Architecture."
-#endif
-
-extern void return_from_sfn(void);
-
void tfm_secure_api_init_done(void)
{
tfm_secure_api_init = 0;
@@ -463,35 +351,8 @@
#endif
}
-static int32_t tfm_core_call_sfn(struct tfm_sfn_req_s *desc_ptr)
-{
-#if TFM_LVL == 1
- if ((desc_ptr->exc_num == EXC_NUM_THREAD_MODE) && (!tfm_secure_api_init)) {
- /* Secure partition to secure partition call in TFM level 1 */
- int32_t res;
- int32_t *args = desc_ptr->args;
- int32_t retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
- /* return handler should restore original exc_return value... */
- res = tfm_pop_lock(NULL);
- if (res == TFM_SUCCESS) {
- /* If unlock successful, pass SS return value to caller */
- res = 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 res;
- }
-#endif
-
- /* Exception return to partition start */
- return tfm_core_exc_return_to_sfn();
-}
-
-int32_t tfm_core_sfn_request_function(struct tfm_sfn_req_s *desc_ptr)
+int32_t tfm_core_sfn_request_handler(
+ struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
{
int32_t res;
@@ -507,30 +368,51 @@
return TFM_ERROR_STATUS(res);
}
- /* return to ASM label in tfm_core_exc_return_to_sfn() function */
- res = tfm_push_lock(desc_ptr, (uint32_t)return_from_sfn | 1);
+ res = tfm_push_lock(desc_ptr, excReturn);
if (res != TFM_SUCCESS) {
/* FixMe: consider possible fault scenarios */
__enable_irq();
return TFM_ERROR_STATUS(res);
}
- if (desc_ptr->ns_caller) {
- tfm_core_configure_secure_exception();
- }
-
__enable_irq();
- res = tfm_core_call_sfn(desc_ptr);
-
- if (desc_ptr->ns_caller) {
- __disable_irq();
- tfm_core_deconfigure_secure_exception();
- __enable_irq();
- }
return res;
}
+#if TFM_LVL == 1
+int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
+{
+ int32_t res;
+ int32_t *args;
+ int32_t retVal;
+ /* No excReturn value is needed as no exception handling is used */
+ res = tfm_core_sfn_request_handler(desc_ptr, 0);
+
+ if (res != TFM_SUCCESS) {
+ return res;
+ }
+
+ /* 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_pop_lock(NULL);
+ if (res == TFM_SUCCESS) {
+ /* If unlock successful, pass SS return value to caller */
+ res = 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 res;
+}
+#endif
+
void tfm_core_validate_secure_caller_handler(uint32_t *svc_args)
{
@@ -663,10 +545,10 @@
}
/* This SVC handler is called if veneer is running in thread mode */
-void tfm_core_partition_request_svc_handler(
- uint32_t *svc_ctx, uint32_t *lr_ptr)
+uint32_t tfm_core_partition_request_svc_handler(
+ struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
{
- if (!(*lr_ptr & EXC_RETURN_STACK_PROCESS)) {
+ if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
/* Partition request SVC called with MSP active.
* Either invalid configuration for Thread mode or SVC called
* from Handler mode, which is not supported.
@@ -676,7 +558,7 @@
tfm_secure_api_error_handler();
}
- struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) svc_ctx[0];
+ struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
int32_t res = tfm_check_sfn_req_integrity(desc_ptr);
@@ -684,30 +566,42 @@
/* The descriptor is incorrectly filled
* FixMe: error severity TBD
*/
- svc_ctx[0] = TFM_ERROR_STATUS(res);
- return;
+ svc_ctx->LR = (int32_t)tfm_secure_api_error_handler;
+ return excReturn;
}
if (desc_ptr->exc_num != EXC_NUM_THREAD_MODE) {
/* The descriptor is incorrectly filled for SVC handler
* FixMe: error severity TBD
*/
- svc_ctx[0] = TFM_ERROR_STATUS(TFM_ERROR_INVALID_PARAMETER);
+ svc_ctx->LR = (int32_t)tfm_secure_api_error_handler;
+ return excReturn;
} else {
- svc_ctx[0] = (uint32_t)tfm_core_sfn_request_function(desc_ptr);
+ if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
+ svc_ctx->LR = (int32_t)tfm_secure_api_error_handler;
+ return excReturn;
+ }
}
- return;
+ return EXC_RETURN_SECURE_FUNCTION;
}
/* This SVC handler is called when sfn returns */
-int32_t tfm_core_partition_return_handler(uint32_t *lr_ptr)
+uint32_t tfm_core_partition_return_handler(uint32_t lr)
{
int32_t res;
- __disable_irq();
+ if (!(lr & EXC_RETURN_STACK_PROCESS)) {
+ /* Partition 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("Partition request SVC called with MSP active!");
+ tfm_secure_api_error_handler();
+ }
/* Store return value from secure partition */
- if (!(*lr_ptr & EXC_RETURN_STACK_PROCESS)) {
+ if (!(lr & EXC_RETURN_STACK_PROCESS)) {
/* Partition return SVC called with MSP active.
* This should not happen!
*/
@@ -716,32 +610,21 @@
}
int32_t retVal = *(int32_t *)__get_PSP();
- switch (retVal) {
- case TFM_SUCCESS:
- case TFM_PARTITION_BUSY:
- /* Secure partition is allowed to return these pre-defined values */
- break;
- default:
- if ((retVal > TFM_SUCCESS) &&
- (retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
- /* Secure function returned a reserved value */
+ if ((retVal > TFM_SUCCESS) &&
+ (retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
+ /* Secure function returned a reserved value */
#ifdef TFM_CORE_DEBUG
- LOG_MSG("Invalid return value from secure partition!");
+ LOG_MSG("Invalid return value from secure partition!");
#endif
- /* FixMe: error can be traced to specific secure partition
- * and Core is not compromised. Error handling flow can be
- * refined
- */
- tfm_secure_api_error_handler();
- }
+ /* FixMe: error can be traced to specific secure partition
+ * and Core is not compromised. Error handling flow can be
+ * refined
+ */
+ tfm_secure_api_error_handler();
}
- /* return handler should restore original exc_return value... */
- res = tfm_pop_lock(lr_ptr);
- if (res == TFM_SUCCESS) {
- /* If unlock successful, pass SS return value to caller */
- res = retVal;
- } else {
+ res = tfm_pop_lock(&lr);
+ if (res != TFM_SUCCESS) {
/* Unlock errors indicate ctx database corruption or unknown anomalies
* Halt execution
*/
@@ -749,17 +632,7 @@
tfm_secure_api_error_handler();
}
- /* FixMe: keeping legacy requirement to check consistency, can be removed
- * when push/pop lock is updated to not store redundant return value
- */
- if (*lr_ptr != ((uint32_t)return_from_sfn | 1)) {
- /* Return address does not match expected value
- * This indicates an inconsistency in ctx database
- */
- tfm_secure_api_error_handler();
- }
- __enable_irq();
- return res;
+ return lr;
}
void tfm_core_set_buffer_area_handler(uint32_t *args)
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 03359aa..3d4a9ae 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -12,6 +12,7 @@
#include "tfm_svc.h"
#include "secure_utilities.h"
#include "tfm_core.h"
+#include "tfm_api.h"
/*!
* \def __tfm_secure_gateway_attributes__
@@ -21,13 +22,6 @@
#define __tfm_secure_gateway_attributes__ \
__attribute__((cmse_nonsecure_entry, noinline, section("SFN")))
-/* Currently only fully blocking NS while partitions are running is supported */
-#define TFM_API_DEPRIORITIZE
-
-#if !(defined(TFM_API_DEPRIORITIZE) || defined(TFM_API_SVCCLEAR))
-#error "No API type selected!"
-#endif
-
/* Hide specific errors if not debugging */
#ifdef TFM_CORE_DEBUG
#define TFM_ERROR_STATUS(status) (status)
@@ -75,10 +69,6 @@
TFM_MEMORY_ACCESS_RW = 2,
};
-/* This function is called if veneer is running in handler mode */
-extern int32_t tfm_core_sfn_request_function(
- struct tfm_sfn_req_s *desc_ptr);
-
extern int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share);
extern int32_t tfm_core_validate_secure_caller(void);
@@ -86,6 +76,10 @@
extern int32_t tfm_core_memory_permission_check(
void *ptr, uint32_t size, int32_t access);
+int32_t tfm_core_sfn_request(struct tfm_sfn_req_s *desc_ptr);
+
+int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
+
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
return tfm_core_partition_request(id, fn, (int32_t)a, (int32_t)b, \
(int32_t)c, (int32_t)d)
@@ -102,20 +96,20 @@
desc.args = args;
desc.ns_caller = cmse_nonsecure_caller();
desc.exc_num = __get_active_exc_num();
-#if TFM_LVL != 1
- if (desc.exc_num == EXC_NUM_THREAD_MODE) {
- int32_t res;
-
- __ASM("MOV r0, %1\n"
- "SVC %2\n"
- "MOV %0, r0\n"
- : "=r" (res)
- : "r" (desc_ptr), "I" (TFM_SVC_SFN_REQUEST)
- : "r0");
- return res;
- }
+ if (desc.exc_num != EXC_NUM_THREAD_MODE) {
+ return TFM_ERROR_GENERIC;
+ } else {
+#if TFM_LVL == 1
+ if (desc.ns_caller) {
+ return tfm_core_sfn_request(desc_ptr);
+ } else {
+ return tfm_core_sfn_request_thread_mode(desc_ptr);
+ }
+#else
+ return tfm_core_sfn_request(desc_ptr);
#endif
- return tfm_core_sfn_request_function(desc_ptr);
+
+ }
}
#endif /* __TFM_SECURE_API_H__ */
diff --git a/secure_fw/core/tfm_unpriv_api.c b/secure_fw/core/tfm_unpriv_api.c
index a3761de..ceac806 100644
--- a/secure_fw/core/tfm_unpriv_api.c
+++ b/secure_fw/core/tfm_unpriv_api.c
@@ -33,19 +33,78 @@
ns_entry();
}
-__attribute__((naked)) void tfm_core_partition_return_svc(void)
+#if defined(__ARM_ARCH_8M_MAIN__)
+__attribute__((naked)) int32_t tfm_core_sfn_request(
+ struct tfm_sfn_req_s *desc_ptr)
{
- SVC(TFM_SVC_SFN_RETURN);
+ __ASM(
+ "PUSH {r4-r12, lr}\n"
+ "SVC %[SVC_REQ]\n"
+ "MOV r4, #0\n"
+ "MOV r5, #0\n"
+ "MOV r6, #0\n"
+ "MOV r7, #0\n"
+ "MOV r8, #0\n"
+ "MOV r9, #0\n"
+ "MOV r10, #0\n"
+ "MOV r11, #0\n"
+ "BLX lr\n"
+ "SVC %[SVC_RET]\n"
+ "POP {r4-r12, pc}\n"
+ : : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
+ , [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
+ : "r0");
}
+#elif defined(__ARM_ARCH_8M_BASE__)
+__attribute__((naked)) int32_t tfm_core_sfn_request(
+ struct tfm_sfn_req_s *desc_ptr)
+{
+ __ASM(
+ ".syntax unified\n"
+ "PUSH {lr}\n"
+ "PUSH {r4-r7}\n"
+ "MOV r4, r8\n"
+ "MOV r5, r9\n"
+ "MOV r6, r10\n"
+ "MOV r7, r11\n"
+ "PUSH {r4-r7}\n"
+ "MOV r4, r12\n"
+ "PUSH {r4}\n"
+ "SVC %[SVC_REQ]\n"
+ "MOVS r4, #0\n"
+ "MOV r5, r4\n"
+ "MOV r6, r4\n"
+ "MOV r7, r4\n"
+ "MOV r8, r4\n"
+ "MOV r9, r4\n"
+ "MOV r10, r4\n"
+ "MOV r11, r4\n"
+ "BLX lr\n"
+ "SVC %[SVC_RET]\n"
+ "POP {r4}\n"
+ "MOV r12, r4\n"
+ "POP {r4-r7}\n"
+ "MOV r8, r4\n"
+ "MOV r9, r5\n"
+ "MOV r10, r6\n"
+ "MOV r11, r7\n"
+ "POP {r4-r7}\n"
+ "POP {pc}\n"
+ : : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
+ , [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
+ : "r0");
+}
+#else
+#error "Unsupported ARM Architecture."
+#endif
__attribute__((naked))
int32_t tfm_core_memory_permission_check(
void *ptr, uint32_t len, int32_t access)
{
__ASM(
- "PUSH {r7, lr}\n"
- "SVC %0\n"
- "POP {r7, pc}\n"
+ "SVC %0\n"
+ "BX lr\n"
: : "I" (TFM_SVC_MEMORY_CHECK));
}
@@ -53,9 +112,8 @@
int32_t tfm_core_validate_secure_caller(void)
{
__ASM(
- "PUSH {r7, lr}\n"
- "SVC %0\n"
- "POP {r7, pc}\n"
+ "SVC %0\n"
+ "BX lr\n"
: : "I" (TFM_SVC_VALIDATE_SECURE_CALLER));
}
@@ -63,8 +121,7 @@
int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share)
{
__ASM(
- "PUSH {r7, lr}\n"
- "SVC %0\n"
- "POP {r7, pc}\n"
+ "SVC %0\n"
+ "BX lr\n"
: : "I" (TFM_SVC_SET_SHARE_AREA));
}
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index 91d30e0..ee08e8c 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -128,7 +128,7 @@
enum spm_err_t tfm_spm_partition_init(void)
{
struct spm_partition_desc_t *part;
- struct tfm_sfn_req_s desc, *desc_ptr = &desc;
+ struct tfm_sfn_req_s desc;
int32_t args[4] = {0};
int32_t fail_cnt = 0;
uint32_t idx;
@@ -142,24 +142,18 @@
tfm_spm_partition_set_caller_partition_idx(idx,
SPM_INVALID_PARTITION_IDX);
} else {
- int32_t ret;
+ int32_t res;
desc.args = args;
desc.exc_num = EXC_NUM_THREAD_MODE;
desc.ns_caller = 0;
desc.sfn = (sfn_t)part->static_data.partition_init;
desc.sp_id = part->static_data.partition_id;
- __ASM("MOV r0, %1\n"
- "SVC %2\n"
- "MOV %0, r0\n"
- : "=r" (ret)
- : "r" (desc_ptr), "I" (TFM_SVC_SFN_REQUEST)
- : "r0");
-
- if (ret == TFM_SUCCESS) {
+ res = tfm_core_sfn_request(&desc);
+ if (res == TFM_SUCCESS) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
} else {
- tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, ret);
+ tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, res);
fail_cnt++;
}
}
@@ -221,6 +215,15 @@
}
#endif
+void tfm_spm_partition_store_context(uint32_t partition_idx,
+ uint32_t stack_ptr, uint32_t lr)
+{
+ g_spm_partition_db.partitions[partition_idx].
+ runtime_data.stack_ptr = stack_ptr;
+ g_spm_partition_db.partitions[partition_idx].
+ runtime_data.lr = lr;
+}
+
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
@@ -255,25 +258,6 @@
caller_partition_idx = caller_partition_idx;
}
-void tfm_spm_partition_set_orig_psp(uint32_t partition_idx,
- uint32_t orig_psp)
-{
- g_spm_partition_db.partitions[partition_idx].runtime_data.orig_psp =
- orig_psp;
-}
-
-void tfm_spm_partition_set_orig_psplim(uint32_t partition_idx,
- uint32_t orig_psplim)
-{
- g_spm_partition_db.partitions[partition_idx].runtime_data.orig_psplim =
- orig_psplim;
-}
-
-void tfm_spm_partition_set_orig_lr(uint32_t partition_idx, uint32_t orig_lr)
-{
- g_spm_partition_db.partitions[partition_idx].runtime_data.orig_lr = orig_lr;
-}
-
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share)
{
@@ -300,8 +284,5 @@
struct spm_partition_desc_t *partition =
&(g_spm_partition_db.partitions[partition_idx]);
partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
- partition->runtime_data.orig_psp = 0;
- partition->runtime_data.orig_psplim = 0;
- partition->runtime_data.orig_lr = 0;
partition->runtime_data.share = 0;
}
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index 7743d45..67cbfbf 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -42,13 +42,9 @@
struct spm_partition_runtime_data_t {
uint32_t partition_state;
uint32_t caller_partition_idx;
- uint32_t orig_psp;
- uint32_t orig_psplim;
- uint32_t orig_lr;
uint32_t share;
-#if TFM_LVL != 1
uint32_t stack_ptr;
-#endif
+ uint32_t lr;
};
@@ -159,6 +155,18 @@
void tfm_spm_partition_set_stack(uint32_t partition_id, uint32_t stack_ptr);
/**
+ * \brief Save stack pointer and link register for partition in database
+ *
+ * \param[in] partition_idx Partition index
+ * \param[in] stack_ptr Stack pointer to be stored
+ * \param[in] lr Link register to be stored
+ *
+ * \note This function doesn't check if partition_idx is valid.
+ */
+void tfm_spm_partition_store_context(uint32_t partition_idx,
+ uint32_t stack_ptr, uint32_t lr);
+
+/**
* \brief Set the current state of a partition
*
* \param[in] partition_idx Partition index
@@ -181,37 +189,6 @@
uint32_t caller_partition_idx);
/**
- * \brief Set the original PSP value of a partition
- *
- * \param[in] partition_idx Partition index
- * \param[in] orig_psp The PSP value to set
- *
- * \note This function doesn't check if partition_idx is valid.
- */
-void tfm_spm_partition_set_orig_psp(uint32_t partition_idx, uint32_t orig_psp);
-
-/**
- * \brief Set the original PSP limit value of a partition
- *
- * \param[in] partition_idx Partition index
- * \param[in] orig_psplim The PSP limit value to set
- *
- * \note This function doesn't check if partition_idx is valid.
- */
-void tfm_spm_partition_set_orig_psplim(uint32_t partition_idx,
- uint32_t orig_psplim);
-
-/**
- * \brief Set the original link register value of a partition
- *
- * \param[in] partition_idx Partition index
- * \param[in] orig_lr The link register value to set
- *
- * \note This function doesn't check if partition_id is valid.
- */
-void tfm_spm_partition_set_orig_lr(uint32_t partition_idx, uint32_t orig_lr);
-
-/**
* \brief Set the buffer share region of the partition
*
* \param[in] partition_idx Partition index