SPM: Check both MODE and SPSEL to choose the stack during SVC
The exception frame is never placed on PSP when in handler mode.
If SPSEL is 1 (PSP), it is "read as 0", which means that the SVC handler
must also check the MODE bit of the EXC_RETURN to properly know which
stack the exception frame is on.
Previously, the checking of the SPSEL bit was done in assembly in a number
of places. This patch refactors that logic out of assembly, into C code,
since the new logic is more complicated.
Note that the logic works just as well for ARMv7 and below.
This patch is initially created by:
Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
Change-Id: I62dda123d7a410251091c416954d2ac4904568ba
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/secure_fw/spm/cmsis_func/arch.c b/secure_fw/spm/cmsis_func/arch.c
index c615d13..6fe0550 100644
--- a/secure_fw/spm/cmsis_func/arch.c
+++ b/secure_fw/spm/cmsis_func/arch.c
@@ -10,7 +10,7 @@
#include "tfm/tfm_spm_services.h"
#if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t lr, uint32_t *msp);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
#pragma required=tfm_core_svc_handler
#endif
@@ -308,26 +308,23 @@
#if !defined(__ICCARM__)
".syntax unified \n"
#endif
- "MRS r0, PSP \n"
- "MRS r2, MSP \n"
- "MOVS r1, #4 \n"
- "MOV r3, lr \n"
- "TST r1, r3 \n"
+ "MRS r0, MSP \n"
+ "MOV r2, lr \n"
+ "MOVS r3, #8 \n"
+ "TST r2, r3 \n"
"BNE from_thread \n"
/*
* This branch is taken when the code is being invoked from handler mode.
* This happens when a de-privileged interrupt handler is to be run. Seal
* the stack before de-privileging.
*/
- "LDR r0, =0xFEF5EDA5 \n"
- "MOVS r3, r0 \n"
- "PUSH {r0, r3} \n"
- /* Overwrite r0 with MSP */
- "MOV r0, r2 \n"
+ "LDR r1, =0xFEF5EDA5 \n"
+ "MOVS r3, r1 \n"
+ "PUSH {r1, r3} \n"
"from_thread: \n"
- "MOV r1, lr \n"
+ "MRS r1, PSP \n"
"BL tfm_core_svc_handler \n"
- "MOVS r1, #4 \n"
+ "MOVS r1, #8 \n"
"TST r1, r0 \n"
"BNE to_thread \n"
/*
@@ -345,18 +342,11 @@
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- "MOVS r0, #4 \n" /* Check store SP in thread mode to r0 */
- "MOV r1, lr \n"
- "TST r0, r1 \n"
- "BEQ handler \n"
- "MRS r0, PSP \n" /* Coming from thread mode */
- "B sp_stored \n"
- "handler: \n"
- "BX lr \n" /* Coming from handler mode */
- "sp_stored: \n"
- "MOV r1, lr \n"
- "BL tfm_core_svc_handler \n"
- "BX r0 \n"
+ "MRS r0, MSP \n"
+ "MRS r1, PSP \n"
+ "MOV r2, lr \n"
+ "BL tfm_core_svc_handler \n"
+ "BX r0 \n"
);
}
#endif
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 95a95ae..a3c536b 100644
--- a/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
+++ b/secure_fw/spm/cmsis_func/tfm_core_svcalls_func.c
@@ -29,15 +29,26 @@
*/
#include "tfm_secure_irq_handlers.inc"
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t lr, uint32_t *msp)
+
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return)
{
uint8_t svc_number = 0;
+ uint32_t *svc_args = msp;
+ uint32_t retval = exc_return;
+
+ if ((exc_return & EXC_RETURN_MODE) && (exc_return & EXC_RETURN_SPSEL)) {
+ /* Use PSP when both EXC_RETURN.MODE and EXC_RETURN.SPSEL are set */
+ svc_args = psp;
+ } else {
+ svc_args = msp;
+ }
+
/*
* Stack contains:
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
* First argument (r0) is svc_args[0]
*/
- if (is_return_secure_stack(lr)) {
+ if (is_return_secure_stack(exc_return)) {
/* SV called directly from secure context. Check instruction for
* svc_number
*/
@@ -51,10 +62,10 @@
}
switch (svc_number) {
case TFM_SVC_SFN_REQUEST:
- lr = tfm_spm_partition_request_svc_handler(svc_args, lr);
+ retval = tfm_spm_partition_request_svc_handler(svc_args, exc_return);
break;
case TFM_SVC_SFN_RETURN:
- lr = tfm_spm_partition_return_handler(lr);
+ retval = tfm_spm_partition_return_handler(exc_return);
break;
case TFM_SVC_GET_CALLER_CLIENT_ID:
tfm_spm_get_caller_client_id_handler(svc_args);
@@ -63,10 +74,10 @@
tfm_spm_request_handler((struct tfm_state_context_t *)svc_args);
break;
case TFM_SVC_DEPRIV_REQ:
- lr = tfm_spm_depriv_req_handler(svc_args, lr);
+ retval = tfm_spm_depriv_req_handler(svc_args, exc_return);
break;
case TFM_SVC_DEPRIV_RET:
- lr = tfm_spm_depriv_return_handler(msp, lr);
+ retval = tfm_spm_depriv_return_handler(msp, exc_return);
break;
case TFM_SVC_PSA_WAIT:
tfm_spm_psa_wait(svc_args);
@@ -85,12 +96,12 @@
break;
default:
#ifdef PLATFORM_SVC_HANDLERS
- svc_args[0] = platform_svc_handlers(svc_num, svc_args, lr);
+ svc_args[0] = platform_svc_handlers(svc_num, svc_args, exc_return);
#endif
break;
}
- return lr;
+ return retval;
}
void tfm_access_violation_handler(void)
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
index fd3e8b6..dad9667 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.c
@@ -85,25 +85,18 @@
}
#if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
#pragma required = tfm_core_svc_handler
#endif
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- "MOVS r0, #4 \n" /* Check store SP in thread mode to r0 */
- "MOV r1, lr \n"
- "TST r0, r1 \n"
- "BEQ handler \n"
- "MRS r0, PSP \n" /* Coming from thread mode */
- "B sp_stored \n"
- "handler: \n"
- "BX lr \n" /* Coming from handler mode */
- "sp_stored: \n"
- "MOV r1, lr \n"
- "BL tfm_core_svc_handler \n"
- "BX r0 \n"
+ "MRS r0, MSP \n"
+ "MRS r1, PSP \n"
+ "MOV r2, lr \n"
+ "BL tfm_core_svc_handler \n"
+ "BX r0 \n"
);
}
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.h b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.h
index 0d8b79d..4f2fb3a 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.h
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v6m_v7m.h
@@ -23,6 +23,13 @@
/* Initial EXC_RETURN value in LR when a thread is loaded at the first time */
#define EXC_RETURN_THREAD_S_PSP 0xFFFFFFFD
+/* Exception return behavior */
+
+/* stack pointer used to restore context: 0=MSP 1=PSP. */
+#define EXC_RETURN_SPSEL (1UL << 2)
+/* processor mode for return: 0=Handler mode 1=Thread mod. */
+#define EXC_RETURN_MODE (1UL << 3)
+
struct tfm_arch_ctx_t {
uint32_t r8;
uint32_t r9;
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
index 4379707..a210ee0 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_base.c
@@ -108,23 +108,16 @@
}
#if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
#pragma required = tfm_core_svc_handler
#endif
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- "MRS r2, MSP \n"
- "MOVS r1, #4 \n"
- "MOV r3, lr \n"
- "MOV r0, r2 \n"
- "TST r1, r3 \n"
- "BEQ handler \n"
- /* If SVC was made from thread mode, overwrite r0 with PSP */
- "MRS r0, PSP \n"
- "handler: \n"
- "MOV r1, lr \n"
+ "MRS r0, MSP \n"
+ "MRS r1, PSP \n"
+ "MOV r2, lr \n"
"BL tfm_core_svc_handler \n"
"BX r0 \n"
);
diff --git a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
index 7ee1141..7b9f169 100644
--- a/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
+++ b/secure_fw/spm/cmsis_psa/arch/tfm_arch_v8m_main.c
@@ -94,20 +94,16 @@
}
#if defined(__ICCARM__)
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
#pragma required = tfm_core_svc_handler
#endif
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
- "MRS r2, MSP \n"
- /* Check store SP in thread mode to r0 */
- "TST lr, #4 \n"
- "ITE EQ \n"
- "MOVEQ r0, r2 \n"
- "MRSNE r0, PSP \n"
- "MOV r1, lr \n"
+ "MRS r0, MSP \n"
+ "MRS r1, PSP \n"
+ "MOV r2, lr \n"
"BL tfm_core_svc_handler \n"
"BX r0 \n"
);
diff --git a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
index 042b04a..cff1ee3 100644
--- a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
@@ -123,9 +123,19 @@
return PSA_SUCCESS;
}
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t exc_return)
+
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return)
{
tfm_svc_number_t svc_number = TFM_SVC_PSA_FRAMEWORK_VERSION;
+ uint32_t *svc_args = msp;
+
+ if ((exc_return & EXC_RETURN_MODE) && (exc_return & EXC_RETURN_SPSEL)) {
+ /* Use PSP when both EXC_RETURN.MODE and EXC_RETURN.SPSEL are set */
+ svc_args = psp;
+ } else {
+ svc_args = msp;
+ }
+
/*
* Stack contains:
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
diff --git a/secure_fw/spm/cmsis_psa/tfm_svcalls.h b/secure_fw/spm/cmsis_psa/tfm_svcalls.h
index d553fc8..d3b374f 100644
--- a/secure_fw/spm/cmsis_psa/tfm_svcalls.h
+++ b/secure_fw/spm/cmsis_psa/tfm_svcalls.h
@@ -12,11 +12,12 @@
/**
* \brief The C source of SVCall handlers
*
- * \param[in] svc_args The arguments list.
+ * \param[in] msp MSP at SVCall entry.
+ * \param[in] psp PSP at SVCall entry.
* \param[in] exc_return EXC_RETURN value of the SVC.
*
* \returns EXC_RETURN value indicates where to return.
*/
-uint32_t tfm_core_svc_handler(uint32_t *svc_args, uint32_t exc_return);
+uint32_t tfm_core_svc_handler(uint32_t *msp, uint32_t *psp, uint32_t exc_return);
#endif