1 /*
2 * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
3 * Copyright (c) 2022-2023 Cypress Semiconductor Corporation (an Infineon
4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5 * reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #include <stdint.h>
12 #include "compiler_ext_defs.h"
13 #include "current.h"
14 #include "runtime_defs.h"
15 #include "tfm_hal_platform.h"
16 #include "ffm/backend.h"
17 #include "stack_watermark.h"
18 #include "load/partition_defs.h"
19 #include "load/service_defs.h"
20 #include "load/spm_load_api.h"
21 #include "psa/error.h"
22 #include "psa/service.h"
23 #include "spm.h"
24
25 /* SFN Partition state */
26 #define SFN_PARTITION_STATE_NOT_INITED 0
27 #define SFN_PARTITION_STATE_INITED 1
28
29 /* Declare the global component list */
30 struct partition_head_t partition_listhead;
31
32 /* Current running partition. */
33 struct partition_t *p_current_partition;
34
35 /*
36 * Send message and wake up the SP who is waiting on message queue, block the
37 * current component state and activate the next component.
38 */
backend_messaging(struct connection_t * p_connection)39 psa_status_t backend_messaging(struct connection_t *p_connection)
40 {
41 struct partition_t *p_target;
42 psa_status_t status;
43
44 if (!p_connection || !p_connection->service ||
45 !p_connection->service->p_ldinf ||
46 !p_connection->service->partition) {
47 return PSA_ERROR_PROGRAMMER_ERROR;
48 }
49
50 p_target = p_connection->service->partition;
51 p_target->p_handles = p_connection;
52
53 SET_CURRENT_COMPONENT(p_target);
54
55 if (p_target->state == SFN_PARTITION_STATE_NOT_INITED) {
56 if (p_target->p_ldinf->entry != 0) {
57 status = ((sfn_init_fn_t)p_target->p_ldinf->entry)(NULL);
58 /* Negative value indicates errors. */
59 if (status < PSA_SUCCESS) {
60 return PSA_ERROR_PROGRAMMER_ERROR;
61 }
62 }
63 p_target->state = SFN_PARTITION_STATE_INITED;
64 }
65
66 status = ((service_fn_t)p_connection->service->p_ldinf->sfn)(&p_connection->msg);
67
68 p_connection->status = TFM_HANDLE_STATUS_ACTIVE;
69
70 return status;
71 }
72
backend_replying(struct connection_t * handle,int32_t status)73 psa_status_t backend_replying(struct connection_t *handle, int32_t status)
74 {
75 SET_CURRENT_COMPONENT(handle->p_client);
76
77 /*
78 * Returning a value here is necessary, because 'psa_reply' is absent
79 * for SFN clients, the 'reply' method is performed by SPM internally
80 * when SFN case, to forward the 'status' to the caller.
81 *
82 * For example:
83 * 'status' MAY contain a 'psa_handle_t' returned by SPM 'connect' and
84 * SPM needs to 'reply' it back to the caller. Treat 'psa_handle_t' value
85 * as SPM specific return value and represnent it as 'psa_status_t'.
86 */
87 return status;
88 }
89
spm_thread_fn(uint32_t param)90 static uint32_t spm_thread_fn(uint32_t param)
91 {
92 struct partition_t *p_part, *p_curr;
93 psa_status_t status;
94
95 p_curr = GET_CURRENT_COMPONENT();
96 /* Call partition initialization routine one by one. */
97 UNI_LIST_FOREACH(p_part, PARTITION_LIST_ADDR, next) {
98 if (IS_IPC_MODEL(p_part->p_ldinf)) {
99 continue;
100 }
101
102 if (p_part->state == SFN_PARTITION_STATE_INITED) {
103 continue;
104 }
105
106 SET_CURRENT_COMPONENT(p_part);
107
108 if (p_part->p_ldinf->entry != 0) {
109 status = ((sfn_init_fn_t)p_part->p_ldinf->entry)(NULL);
110 if (status < PSA_SUCCESS) {
111 tfm_core_panic();
112 }
113 }
114
115 p_part->state = SFN_PARTITION_STATE_INITED;
116 }
117
118 SET_CURRENT_COMPONENT(p_curr);
119
120 return param;
121 }
122
123 /* Parameters are treated as assuredly */
backend_init_comp_assuredly(struct partition_t * p_pt,uint32_t service_set)124 void backend_init_comp_assuredly(struct partition_t *p_pt,
125 uint32_t service_set)
126 {
127 const struct partition_load_info_t *p_pldi = p_pt->p_ldinf;
128 struct context_ctrl_t ns_agent_ctrl;
129 void *param = NULL;
130
131 p_pt->p_handles = NULL;
132 p_pt->state = SFN_PARTITION_STATE_NOT_INITED;
133
134 watermark_stack(p_pt);
135
136 /*
137 * Built-in partitions have only one thread instance: NS Agent (TZ) and it
138 * needs to be specific cared here.
139 */
140 if (IS_NS_AGENT(p_pldi)) {
141 if (IS_NS_AGENT_TZ(p_pldi)) {
142 /* NS agent TZ expects NSPE entry point as the parameter */
143 param = (void *)tfm_hal_get_ns_entry_point();
144 }
145 ARCH_CTXCTRL_INIT(&ns_agent_ctrl,
146 LOAD_ALLOCED_STACK_ADDR(p_pldi),
147 p_pldi->stack_size);
148 tfm_arch_init_context(&ns_agent_ctrl, (uintptr_t)spm_thread_fn,
149 param, p_pldi->entry);
150 tfm_arch_refresh_hardware_context(&ns_agent_ctrl);
151 SET_CURRENT_COMPONENT(p_pt);
152 }
153 }
154
backend_system_run(void)155 uint32_t backend_system_run(void)
156 {
157 return EXC_RETURN_THREAD_PSP;
158 }
159
backend_wait_signals(struct partition_t * p_pt,psa_signal_t signals)160 psa_signal_t backend_wait_signals(struct partition_t *p_pt, psa_signal_t signals)
161 {
162 while (!(p_pt->signals_asserted & signals)) {
163 __WFI();
164 }
165
166 return p_pt->signals_asserted & signals;
167 }
168
backend_assert_signal(struct partition_t * p_pt,psa_signal_t signal)169 psa_status_t backend_assert_signal(struct partition_t *p_pt, psa_signal_t signal)
170 {
171 p_pt->signals_asserted |= signal;
172
173 return PSA_SUCCESS;
174 }
175