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/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 */