Core: Initialize IPC SPM in handler mode
- IPC SPM needs to update non-secure entry thread context in PSP
while this thread shared the same stack with initial thread mode,
so SPM can not run with PSP.
- While running with MSP, there needs to be a way to reset the MSP
value to initial value after SPM initialization is done. Exception
return can be an ideal way, so put SPM initialization in handler
mode and finally return to thread mode from handler mode.
- Set non-secure entry thread as the first 'current' thread, and
reset the current PSP/PSPLIMIT to initial value in case there
are used content makes PSP shifted to an unexpected value.
Change-Id: Ic17b3288478c014a0f21eb602b45b9c5e515960e
Signed-off-by: Ken Liu <ken.liu@arm.com>
diff --git a/secure_fw/core/arch/include/tfm_arch_v6m_v7m.h b/secure_fw/core/arch/include/tfm_arch_v6m_v7m.h
index fbb75a3..eafb69b 100644
--- a/secure_fw/core/arch/include/tfm_arch_v6m_v7m.h
+++ b/secure_fw/core/arch/include/tfm_arch_v6m_v7m.h
@@ -97,6 +97,16 @@
}
/**
+ * \brief Update context value into hardware
+ *
+ * \param[in] pctx Pointer of context data
+ */
+__STATIC_INLINE void tfm_arch_update_ctx(struct tfm_state_context_ext *pctx)
+{
+ __set_PSP(pctx->sp);
+}
+
+/**
* \brief Set MSP limit value.
*
* \param[in] msplim MSP limit value to be written.
diff --git a/secure_fw/core/arch/include/tfm_arch_v8m.h b/secure_fw/core/arch/include/tfm_arch_v8m.h
index 99420f8..2aa564e 100644
--- a/secure_fw/core/arch/include/tfm_arch_v8m.h
+++ b/secure_fw/core/arch/include/tfm_arch_v8m.h
@@ -101,6 +101,17 @@
}
/**
+ * \brief Update context value into hardware
+ *
+ * \param[in] pctx Pointer of context data
+ */
+__STATIC_INLINE void tfm_arch_update_ctx(struct tfm_state_context_ext *pctx)
+{
+ __set_PSP(pctx->sp);
+ __set_PSPLIM(pctx->sp_limit);
+}
+
+/**
* \brief Set MSPLIM register.
*
* \param[in] msplim Register value to be written into MSPLIM.
diff --git a/secure_fw/core/include/tfm_internal.h b/secure_fw/core/include/tfm_internal.h
index a756025..7da56c0 100644
--- a/secure_fw/core/include/tfm_internal.h
+++ b/secure_fw/core/include/tfm_internal.h
@@ -133,5 +133,9 @@
*/
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);
#endif /* __TFM_INTERNAL_H__ */
diff --git a/secure_fw/core/ipc/tfm_multi_core.c b/secure_fw/core/ipc/tfm_multi_core.c
index 5359ea1..c3382ac 100644
--- a/secure_fw/core/ipc/tfm_multi_core.c
+++ b/secure_fw/core/ipc/tfm_multi_core.c
@@ -10,6 +10,7 @@
#include "tfm_nspm.h"
#include "tfm_spe_mailbox.h"
#include "tfm_utils.h"
+#include "log/tfm_assert.h"
#include "log/tfm_log.h"
#include "log/tfm_assert.h"
diff --git a/secure_fw/core/ipc/tfm_thread.c b/secure_fw/core/ipc/tfm_thread.c
index 6b8d773..5c1ad17 100644
--- a/secure_fw/core/ipc/tfm_thread.c
+++ b/secure_fw/core/ipc/tfm_thread.c
@@ -170,14 +170,19 @@
void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth)
{
/*
- * There is no selected thread before scheduler start, assign
- * a caller provided thread as current thread. This function
- * should get called only ONCE; further calling triggers assert.
+ * There is no selected thread before scheduler start, assign the caller
+ * provided thread as the current thread. Update the hardware PSP/PSPLIM
+ * with the value in thread context to ensure they are identical.
+ * This function can be called only ONCE; further calling triggers assert.
*/
TFM_CORE_ASSERT(CURR_THRD == NULL);
TFM_CORE_ASSERT(pth != NULL);
+ TFM_CORE_ASSERT(pth->state_ctx.ctxb.sp != 0);
+
+ tfm_arch_update_ctx(&pth->state_ctx.ctxb);
CURR_THRD = pth;
+
tfm_thrd_activate_schedule();
}
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index a2688df..548609e 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -254,6 +254,8 @@
if (tfm_core_set_secure_exception_priorities() != TFM_SUCCESS) {
tfm_core_panic();
}
- tfm_spm_init();
+
+ /* Move to handler mode for further SPM initialization. */
+ tfm_core_handler_mode();
#endif /* !defined(TFM_PSA_API) */
}
diff --git a/secure_fw/core/tfm_core_svcalls_ipc.c b/secure_fw/core/tfm_core_svcalls_ipc.c
index 1da13d6..d6f2c45 100644
--- a/secure_fw/core/tfm_core_svcalls_ipc.c
+++ b/secure_fw/core/tfm_core_svcalls_ipc.c
@@ -11,6 +11,7 @@
#include "core/tfm_core_svc.h"
#include "tfm_utils.h"
#include "tfm_svcalls.h"
+#include "spm_api.h"
extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
@@ -35,6 +36,9 @@
tfm_core_panic();
}
switch (svc_number) {
+ case TFM_SVC_HANDLER_MODE:
+ tfm_spm_init();
+ break;
case TFM_SVC_IPC_REQUEST:
tfm_psa_ipc_request_handler(svc_args);
break;
@@ -49,6 +53,13 @@
return exc_return;
}
+__attribute__ ((naked)) void tfm_core_handler_mode(void)
+{
+ __ASM volatile("SVC %0 \n"
+ "BX LR \n"
+ : : "I" (TFM_SVC_HANDLER_MODE));
+}
+
void tfm_access_violation_handler(void)
{
while (1) {
diff --git a/secure_fw/include/core/tfm_core_svc.h b/secure_fw/include/core/tfm_core_svc.h
index ca57576..4306f37 100644
--- a/secure_fw/include/core/tfm_core_svc.h
+++ b/secure_fw/include/core/tfm_core_svc.h
@@ -24,6 +24,7 @@
TFM_SVC_DISABLE_IRQ,
TFM_SVC_PSA_WAIT,
TFM_SVC_PSA_EOI,
+ TFM_SVC_HANDLER_MODE,
#ifdef TFM_PSA_API
TFM_SVC_IPC_REQUEST,
TFM_SVC_EXIT_THRD,
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index e61b411..7c4a9a6 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -665,9 +665,6 @@
enum tfm_memory_access_e access,
uint32_t privileged);
-/* This function should be called before schedule function */
-void tfm_spm_init(void);
-
/*
* PendSV specified function.
*
@@ -680,6 +677,13 @@
*/
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb);
+/**
+ * \brief SPM initialization implementation
+ *
+ * \details This function must be called under handler mode.
+ */
+void tfm_spm_init(void);
+
#endif /* ifdef(TFM_PSA_API) */
#endif /*__SPM_API_H__ */
diff --git a/secure_fw/spm/spm_api_ipc.c b/secure_fw/spm/spm_api_ipc.c
index b36887f..9827e4d 100644
--- a/secure_fw/spm/spm_api_ipc.c
+++ b/secure_fw/spm/spm_api_ipc.c
@@ -526,7 +526,7 @@
{
uint32_t i, j, num;
struct spm_partition_desc_t *partition;
- struct tfm_thrd_ctx *pth, this_thrd;
+ struct tfm_thrd_ctx *pth, *p_ns_entry_thread = NULL;
const struct tfm_spm_partition_platform_data_t **platform_data_p;
tfm_pool_init(conn_handle_pool,
@@ -587,6 +587,10 @@
pth->prior = tfm_spm_partition_get_priority(i);
+ if (partition->static_data->partition_id == TFM_SP_NON_SECURE_ID) {
+ p_ns_entry_thread = pth;
+ }
+
/* Kick off */
if (tfm_thrd_start(pth) != THRD_SUCCESS) {
tfm_core_panic();
@@ -614,19 +618,14 @@
* All threads initialized, start the scheduler.
*
* NOTE:
- * Here is the booting privileged thread mode, and will never
- * return to this place after scheduler is started. The start
- * function has to save current runtime context to act as a
- * 'current thread' to avoid repeating NULL 'current thread'
- * checking while context switching. This saved context is worthy
- * of being saved somewhere if there are potential usage purpose.
- * Let's save this context in a local variable 'this_thrd' at
- * current since there is no usage for it.
- * Also set tfm_nspm_thread_entry as pfn for this thread to
- * use in detecting NS/S thread scheduling changes.
+ * It is worthy to give the thread object to scheduler if the background
+ * context belongs to one of the threads. Here the background thread is the
+ * initialization thread who calls SPM SVC, which re-uses the non-secure
+ * entry thread's stack. After SPM initialization is done, this stack is
+ * cleaned up and the background context is never going to return. Tell
+ * the scheduler that the current thread is non-secure entry thread.
*/
- this_thrd.pfn = (tfm_thrd_func_t)tfm_nspm_thread_entry;
- tfm_thrd_start_scheduler(&this_thrd);
+ tfm_thrd_start_scheduler(p_ns_entry_thread);
}
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb)