SPM: Involve SPM backends
Compare to the existing IPC runtime model and the upcoming SFN
runtime model, they:
- Have different component runtime initialization methods:
thread vs thread-less.
- Have different messaging mechanisms: scheduling vs function call.
- Have different system kick-off mechanisms: scheduling vs calling
into partition initialization routines one by one.
Create backends for addressing these differentiate. And IPC backend
is the first instance. Also fine-tunes backend related items, move
them into backend sources, such as partition list, and change the
way for binding service signals with partitions.
Change-Id: I954af30d65514a13ac9f5f86e5e718cf1c9a697c
Signed-off-by: Ken Liu <ken.liu@arm.com>
Co-authored-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/secure_fw/spm/CMakeLists.txt b/secure_fw/spm/CMakeLists.txt
index 443279f..f118fd0 100755
--- a/secure_fw/spm/CMakeLists.txt
+++ b/secure_fw/spm/CMakeLists.txt
@@ -52,6 +52,7 @@
$<$<BOOL:${TFM_PSA_API}>:cmsis_psa/spm_ipc.c>
$<$<BOOL:${TFM_PSA_API}>:cmsis_psa/static_load.c>
$<$<BOOL:${TFM_PSA_API}>:ffm/psa_api.c>
+ $<$<BOOL:${TFM_PSA_API}>:ffm/backend_ipc.c>
$<$<BOOL:${TFM_PSA_API}>:cmsis_psa/tfm_core_svcalls_ipc.c>
$<$<AND:$<BOOL:${TFM_PSA_API}>,$<NOT:$<BOOL:${TFM_MULTI_CORE_TOPOLOGY}>>>:cmsis_psa/tfm_nspm_ipc.c>
$<$<BOOL:${TFM_PSA_API}>:cmsis_psa/tfm_pools.c>
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.c b/secure_fw/spm/cmsis_psa/spm_ipc.c
index 4e8960f..054ee11 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.c
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.c
@@ -30,13 +30,13 @@
#include "tfm_pools.h"
#include "region.h"
#include "psa_manifest/pid.h"
+#include "ffm/backend.h"
#include "load/partition_defs.h"
#include "load/service_defs.h"
#include "load/asset_defs.h"
#include "load/spm_load_api.h"
/* Partition and service runtime data list head/runtime data table */
-static struct partition_head_t partitions_listhead;
static struct service_head_t services_listhead;
struct service_t *stateless_services_ref_tbl[STATIC_HANDLE_NUM_LIMIT];
@@ -294,7 +294,7 @@
{
struct partition_t *p_part;
- UNI_LIST_FOR_EACH(p_part, &partitions_listhead) {
+ UNI_LIST_FOR_EACH(p_part, PARTITION_LIST_ADDR) {
if (p_part->p_ldinf->pid == partition_id) {
return p_part;
}
@@ -472,41 +472,6 @@
}
}
-void tfm_spm_send_event(struct service_t *service,
- struct tfm_msg_body_t *msg)
-{
- struct partition_t *partition = NULL;
- psa_signal_t signal = 0;
-
- if (!msg || !service || !service->p_ldinf || !service->partition) {
- tfm_core_panic();
- }
-
- partition = service->partition;
- signal = service->p_ldinf->signal;
-
- /* Add message to partition message list tail */
- BI_LIST_INSERT_BEFORE(&partition->msg_list, &msg->msg_node);
-
- /* Messages put. Update signals */
- partition->signals_asserted |= signal;
-
- if (partition->signals_waiting & signal) {
- thrd_wake_up(
- &partition->waitobj,
- (partition->signals_asserted & partition->signals_waiting));
- partition->signals_waiting &= ~signal;
- }
-
- /*
- * If it is a NS request via RPC, it is unnecessary to block current
- * thread.
- */
- if (!is_tfm_rpc_msg(msg)) {
- thrd_wait_on(&msg->ack_evnt, CURRENT_THREAD);
- }
-}
-
int32_t tfm_spm_partition_get_running_partition_id(void)
{
struct partition_t *partition;
@@ -622,8 +587,8 @@
uint32_t tfm_spm_init(void)
{
struct partition_t *partition;
- const struct partition_load_info_t *p_ldinf;
- void *p_param, *p_boundaries = NULL;
+ const struct partition_load_info_t *p_pldi;
+ uint32_t service_setting = 0;
#ifdef TFM_FIH_PROFILE_ON
fih_int fih_rc = FIH_FAILURE;
@@ -634,62 +599,49 @@
sizeof(struct tfm_conn_handle_t),
TFM_CONN_HANDLE_MAX_NUM);
- UNI_LISI_INIT_HEAD(&partitions_listhead);
+ UNI_LISI_INIT_HEAD(PARTITION_LIST_ADDR);
UNI_LISI_INIT_HEAD(&services_listhead);
while (1) {
- partition = load_a_partition_assuredly(&partitions_listhead);
+ partition = load_a_partition_assuredly(PARTITION_LIST_ADDR);
if (partition == NO_MORE_PARTITION) {
break;
}
- p_ldinf = partition->p_ldinf;
+ p_pldi = partition->p_ldinf;
- if (p_ldinf->nservices) {
- load_services_assuredly(partition, &services_listhead,
- stateless_services_ref_tbl,
- sizeof(stateless_services_ref_tbl));
+ if (p_pldi->nservices) {
+ service_setting = load_services_assuredly(
+ partition,
+ &services_listhead,
+ stateless_services_ref_tbl,
+ sizeof(stateless_services_ref_tbl));
}
- if (p_ldinf->nirqs) {
+ if (p_pldi->nirqs) {
load_irqs_assuredly(partition);
}
- /* Bind the partition with plaform. */
+ /* Bind the partition with platform. */
#if TFM_FIH_PROFILE_ON
FIH_CALL(tfm_hal_bind_boundaries, fih_rc, partition->p_ldinf,
- &p_boundaries);
+ &partition->p_boundaries);
if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
tfm_core_panic();
}
#else /* TFM_FIH_PROFILE_ON */
if (tfm_hal_bind_boundaries(partition->p_ldinf,
- &p_boundaries) != TFM_HAL_SUCCESS) {
+ &partition->p_boundaries)
+ != TFM_HAL_SUCCESS) {
tfm_core_panic();
}
#endif /* TFM_FIH_PROFILE_ON */
- partition->p_boundaries = p_boundaries;
- partition->signals_allowed |= PSA_DOORBELL;
-
- THRD_SYNC_INIT(&partition->waitobj);
- BI_LIST_INIT_NODE(&partition->msg_list);
-
- THRD_INIT(&partition->thrd, &partition->ctx_ctrl,
- TO_THREAD_PRIORITY(PARTITION_PRIORITY(p_ldinf->flags)));
-
- p_param = NULL;
- if (p_ldinf->pid == TFM_SP_NON_SECURE_ID) {
- p_param = (void *)tfm_spm_hal_get_ns_entry_point();
- }
-
- thrd_start(&partition->thrd,
- POSITION_TO_ENTRY(p_ldinf->entry, thrd_fn_t), p_param,
- LOAD_ALLOCED_STACK_ADDR(p_ldinf),
- LOAD_ALLOCED_STACK_ADDR(p_ldinf) + p_ldinf->stack_size);
+ /* TODO: Replace this 'BACKEND_IPC' after SFN get involved. */
+ backend_instance.comp_init_assuredly(partition, service_setting);
}
- return thrd_start_scheduler(&CURRENT_THREAD);
+ return backend_instance.system_run();
}
/*
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.h b/secure_fw/spm/cmsis_psa/spm_ipc.h
index fd92f3e..2de04a9 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.h
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.h
@@ -287,19 +287,6 @@
psa_outvec *caller_outvec);
/**
- * \brief Send message and wake up the SP who is waiting on
- * message queue, block the current thread and
- * scheduler triggered
- *
- * \param[in] service Target service context pointer, which can be
- * obtained by partition management functions
- * \param[in] msg message created by tfm_spm_create_msg()
- * \ref tfm_msg_body_t structures
- */
-void tfm_spm_send_event(struct service_t *service,
- struct tfm_msg_body_t *msg);
-
-/**
* \brief Check the client version according to
* version policy
*
diff --git a/secure_fw/spm/cmsis_psa/static_load.c b/secure_fw/spm/cmsis_psa/static_load.c
index acd20c5..c319c74 100644
--- a/secure_fw/spm/cmsis_psa/static_load.c
+++ b/secure_fw/spm/cmsis_psa/static_load.c
@@ -98,10 +98,6 @@
tfm_core_panic();
}
- if (!(p_ptldinf->flags & PARTITION_MODEL_IPC)) {
- tfm_core_panic();
- }
-
if (p_ptldinf->pid < 0) {
/* 0 is the internal NS Agent, besides the normal positive PIDs */
tfm_core_panic();
@@ -117,12 +113,12 @@
return partition;
}
-void load_services_assuredly(struct partition_t *p_partition,
- struct service_head_t *services_listhead,
- struct service_t **stateless_services_ref_tbl,
- size_t ref_tbl_size)
+uint32_t load_services_assuredly(struct partition_t *p_partition,
+ struct service_head_t *services_listhead,
+ struct service_t **stateless_services_ref_tbl,
+ size_t ref_tbl_size)
{
- uint32_t i, serv_ldflags, hidx;
+ uint32_t i, serv_ldflags, hidx, service_setting = 0;
struct service_t *services;
const struct partition_load_info_t *p_ptldinf;
const struct service_load_info_t *p_servldinf;
@@ -140,11 +136,14 @@
*/
services = tfm_allocate_service_assuredly(p_ptldinf->nservices);
for (i = 0; i < p_ptldinf->nservices && services; i++) {
- p_partition->signals_allowed |= p_servldinf[i].signal;
services[i].p_ldinf = &p_servldinf[i];
services[i].partition = p_partition;
services[i].next = NULL;
+ if (p_ptldinf->flags & PARTITION_MODEL_IPC) {
+ service_setting |= p_servldinf[i].signal;
+ }
+
BI_LIST_INIT_NODE(&services[i].handle_list);
/* Populate the stateless service reference table */
@@ -168,6 +167,8 @@
UNI_LIST_INSERT_AFTER(services_listhead, &services[i]);
}
+
+ return service_setting;
}
void load_irqs_assuredly(struct partition_t *p_partition)
diff --git a/secure_fw/spm/ffm/backend_ipc.c b/secure_fw/spm/ffm/backend_ipc.c
new file mode 100644
index 0000000..4b2f8a2
--- /dev/null
+++ b/secure_fw/spm/ffm/backend_ipc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include "spm_ipc.h"
+#include "tfm_rpc.h"
+#include "tfm_spm_hal.h" /* To be checked */
+#include "ffm/backend.h"
+#include "load/partition_defs.h"
+#include "load/service_defs.h"
+#include "load/spm_load_api.h"
+#include "psa/error.h"
+
+/* Declare the global component list */
+struct partition_head_t partition_listhead;
+
+/*
+ * Send message and wake up the SP who is waiting on message queue, block the
+ * current thread and triggere scheduler.
+ */
+static psa_status_t ipc_messaging(struct service_t *service,
+ struct tfm_msg_body_t *msg)
+{
+ struct partition_t *p_owner = NULL;
+ psa_signal_t signal = 0;
+
+ if (!msg || !service || !service->p_ldinf || !service->partition) {
+ tfm_core_panic();
+ }
+
+ p_owner = service->partition;
+ signal = service->p_ldinf->signal;
+
+ /* Add message to partition message list tail */
+ BI_LIST_INSERT_BEFORE(&p_owner->msg_list, &msg->msg_node);
+
+ /* Messages put. Update signals */
+ p_owner->signals_asserted |= signal;
+
+ if (p_owner->signals_waiting & signal) {
+ thrd_wake_up(&p_owner->waitobj,
+ (p_owner->signals_asserted & p_owner->signals_waiting));
+ p_owner->signals_waiting &= ~signal;
+ }
+
+ /*
+ * If it is a NS request via RPC, it is unnecessary to block current
+ * thread.
+ */
+
+ if (!is_tfm_rpc_msg(msg)) {
+ thrd_wait_on(&msg->ack_evnt, CURRENT_THREAD);
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Parameters are treated as assuredly */
+static void ipc_comp_init_assuredly(struct partition_t *p_pt,
+ uint32_t service_setting)
+{
+ const struct partition_load_info_t *p_pldi = p_pt->p_ldinf;
+ void *p_param = NULL;
+
+ p_pt->signals_allowed |= PSA_DOORBELL | service_setting;
+
+ THRD_SYNC_INIT(&p_pt->waitobj);
+ BI_LIST_INIT_NODE(&p_pt->msg_list);
+
+ THRD_INIT(&p_pt->thrd, &p_pt->ctx_ctrl,
+ TO_THREAD_PRIORITY(PARTITION_PRIORITY(p_pldi->flags)));
+
+ if (p_pldi->pid == TFM_SP_NON_SECURE_ID) {
+ p_param = (void *)tfm_spm_hal_get_ns_entry_point();
+ }
+
+ thrd_start(&p_pt->thrd,
+ POSITION_TO_ENTRY(p_pldi->entry, thrd_fn_t), p_param,
+ LOAD_ALLOCED_STACK_ADDR(p_pldi),
+ LOAD_ALLOCED_STACK_ADDR(p_pldi) + p_pldi->stack_size);
+}
+
+static uint32_t ipc_system_run(void)
+{
+ return thrd_start_scheduler(&CURRENT_THREAD);
+}
+
+const struct backend_ops_t backend_instance = {
+ .comp_init_assuredly = ipc_comp_init_assuredly,
+ .system_run = ipc_system_run,
+ .messaging = ipc_messaging,
+};
diff --git a/secure_fw/spm/ffm/psa_api.c b/secure_fw/spm/ffm/psa_api.c
index 6e35c57..b38f85c 100644
--- a/secure_fw/spm/ffm/psa_api.c
+++ b/secure_fw/spm/ffm/psa_api.c
@@ -17,6 +17,7 @@
#include "load/interrupt_defs.h"
#include "psa_api.h"
#include "utilities.h"
+#include "ffm/backend.h"
#include "ffm/spm_error_base.h"
#include "tfm_rpc.h"
#include "tfm_spm_hal.h"
@@ -27,7 +28,6 @@
#define GET_STATELESS_SERVICE(index) (stateless_services_ref_tbl[index])
extern struct service_t *stateless_services_ref_tbl[];
-
uint32_t tfm_spm_get_lifecycle_state(void)
{
/*
@@ -130,13 +130,8 @@
tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
client_id, NULL, 0, NULL, 0, NULL);
- /*
- * Send message and wake up the SP who is waiting on message queue,
- * and scheduler triggered
- */
- tfm_spm_send_event(service, msg);
- return PSA_SUCCESS;
+ return backend_instance.messaging(service, msg);
}
psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
@@ -323,13 +318,7 @@
tfm_spm_fill_msg(msg, service, handle, type, client_id,
invecs, in_num, outvecs, out_num, outptr);
- /*
- * Send message and wake up the SP who is waiting on message queue,
- * and scheduler triggered
- */
- tfm_spm_send_event(service, msg);
-
- return PSA_SUCCESS;
+ return backend_instance.messaging(service, msg);
}
void tfm_spm_client_psa_close(psa_handle_t handle)
@@ -385,11 +374,7 @@
tfm_spm_fill_msg(msg, service, handle, PSA_IPC_DISCONNECT, client_id,
NULL, 0, NULL, 0, NULL);
- /*
- * Send message and wake up the SP who is waiting on message queue,
- * and scheduler triggered
- */
- tfm_spm_send_event(service, msg);
+ (void)backend_instance.messaging(service, msg);
}
/* PSA Partition API function body */
diff --git a/secure_fw/spm/include/ffm/backend.h b/secure_fw/spm/include/ffm/backend.h
new file mode 100644
index 0000000..c53c35c
--- /dev/null
+++ b/secure_fw/spm/include/ffm/backend.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __BACKEND_H__
+#define __BACKEND_H__
+
+#include <stdint.h>
+#include "psa/error.h"
+#include "spm_ipc.h"
+#include "load/spm_load_api.h"
+
+/* BASIC TYPE DEFINITIONS */
+
+struct backend_ops_t {
+ /*
+ * Runtime model-specific component initialization routine. This
+ * is an `assuredly` function, would panic if any error occurred.
+ */
+ void (*comp_init_assuredly)(struct partition_t *p_pt,
+ uint32_t service_setting);
+
+ /*
+ * Runtime model-specific kick-off method for the whole system.
+ * Returns a hardware-specific control value, which is transparent
+ * to SPM common logic.
+ */
+ uint32_t (*system_run)(void);
+
+ /* Runtime model-specific message handling mechanism. */
+ psa_status_t (*messaging)(struct service_t *p_serv,
+ struct tfm_msg_body_t *p_msg);
+
+};
+
+/* RUNTIME MODEL BACKENDS DECLARATION */
+
+/* IPC backend */
+extern const struct backend_ops_t backend_instance;
+
+/* The component list, and a MACRO indicate this is not a common global. */
+extern struct partition_head_t partition_listhead;
+#define PARTITION_LIST_ADDR (&partition_listhead)
+
+#endif /* __BACKEND_H__ */
diff --git a/secure_fw/spm/include/load/spm_load_api.h b/secure_fw/spm/include/load/spm_load_api.h
index d8fbc16..a402d9a 100644
--- a/secure_fw/spm/include/load/spm_load_api.h
+++ b/secure_fw/spm/include/load/spm_load_api.h
@@ -68,11 +68,13 @@
* contains.
* As an 'assuredly' function, errors simply panic the system and never
* return.
+ * This function returns the service signal set in a 32 bit number. Return
+ * ZERO if services are not represented by signals.
*/
-void load_services_assuredly(struct partition_t *p_partition,
- struct service_head_t *services_listhead,
- struct service_t **stateless_services_ref_tbl,
- size_t ref_tbl_size);
+uint32_t load_services_assuredly(struct partition_t *p_partition,
+ struct service_head_t *services_listhead,
+ struct service_t **stateless_services_ref_tbl,
+ size_t ref_tbl_size);
/*
* Append IRQ signals to Partition signals.