1 /*
2 * Copyright (c) 2021-2024, 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 "tfm_nspm.h"
17 #include "ffm/backend.h"
18 #include "stack_watermark.h"
19 #include "load/partition_defs.h"
20 #include "load/service_defs.h"
21 #include "load/spm_load_api.h"
22 #include "psa/error.h"
23 #include "psa/service.h"
24 #include "spm.h"
25 #include "memory_symbols.h"
26 #include "private/assert.h"
27
28 /* SFN Partition state */
29 #define SFN_PARTITION_STATE_NOT_INITED 0
30 #define SFN_PARTITION_STATE_INITED 1
31
32 /* Declare the global component list */
33 struct partition_head_t partition_listhead;
34
35 /* Current running partition. */
36 struct partition_t *p_current_partition;
37
38 /*
39 * Send message and wake up the SP who is waiting on message queue, block the
40 * current component state and activate the next component.
41 */
backend_messaging(struct connection_t * p_connection)42 psa_status_t backend_messaging(struct connection_t *p_connection)
43 {
44 struct partition_t *p_target;
45 psa_status_t status;
46
47 if (!p_connection || !p_connection->service ||
48 !p_connection->service->p_ldinf ||
49 !p_connection->service->partition) {
50 return PSA_ERROR_PROGRAMMER_ERROR;
51 }
52
53 p_target = p_connection->service->partition;
54 p_target->p_handles = p_connection;
55
56 SET_CURRENT_COMPONENT(p_target);
57
58 if (p_target->state == SFN_PARTITION_STATE_NOT_INITED) {
59 if (p_target->p_ldinf->entry != 0) {
60 status = ((sfn_init_fn_t)p_target->p_ldinf->entry)(NULL);
61 /* Negative value indicates errors. */
62 if (status < PSA_SUCCESS) {
63 return PSA_ERROR_PROGRAMMER_ERROR;
64 }
65 }
66 p_target->state = SFN_PARTITION_STATE_INITED;
67 }
68
69 status = ((service_fn_t)p_connection->service->p_ldinf->sfn)(&p_connection->msg);
70
71 p_connection->status = TFM_HANDLE_STATUS_ACTIVE;
72
73 return status;
74 }
75
backend_replying(struct connection_t * handle,int32_t status)76 psa_status_t backend_replying(struct connection_t *handle, int32_t status)
77 {
78 SET_CURRENT_COMPONENT(handle->p_client);
79
80 /*
81 * Returning a value here is necessary, because 'psa_reply' is absent
82 * for SFN clients, the 'reply' method is performed by SPM internally
83 * when SFN case, to forward the 'status' to the caller.
84 *
85 * For example:
86 * 'status' MAY contain a 'psa_handle_t' returned by SPM 'connect' and
87 * SPM needs to 'reply' it back to the caller. Treat 'psa_handle_t' value
88 * as SPM specific return value and represnent it as 'psa_status_t'.
89 */
90 return status;
91 }
92
spm_init_function(uint32_t param)93 static uint32_t spm_init_function(uint32_t param)
94 {
95 struct partition_t *p_part, *p_curr;
96 psa_status_t status;
97
98 p_curr = GET_CURRENT_COMPONENT();
99 /* Call partition initialization routine one by one. */
100 UNI_LIST_FOREACH(p_part, PARTITION_LIST_ADDR, next) {
101 if (IS_IPC_MODEL(p_part->p_ldinf)) {
102 continue;
103 }
104
105 if (p_part->state == SFN_PARTITION_STATE_INITED) {
106 continue;
107 }
108
109 SET_CURRENT_COMPONENT(p_part);
110
111 if (p_part->p_ldinf->entry != 0) {
112 status = ((sfn_init_fn_t)p_part->p_ldinf->entry)(NULL);
113 if (status < PSA_SUCCESS) {
114 tfm_core_panic();
115 }
116 }
117
118 p_part->state = SFN_PARTITION_STATE_INITED;
119 }
120
121 SET_CURRENT_COMPONENT(p_curr);
122
123 return param;
124 }
125
126 /* Parameters are treated as assuredly */
backend_init_comp_assuredly(struct partition_t * p_pt,uint32_t service_set)127 void backend_init_comp_assuredly(struct partition_t *p_pt,
128 uint32_t service_set)
129 {
130 const struct partition_load_info_t *p_pldi = p_pt->p_ldinf;
131
132 p_pt->p_handles = NULL;
133 p_pt->state = SFN_PARTITION_STATE_NOT_INITED;
134
135 watermark_stack(p_pt);
136
137 /*
138 * Built-in partitions have only one thread instance: NS Agent (TZ or Mailbox)
139 * It needs to be specific cared here.
140 */
141 if (IS_NS_AGENT(p_pldi)) {
142 if (IS_NS_AGENT_TZ(p_pldi)) {
143 tz_ns_agent_register_client_id_range(p_pt->p_ldinf->client_id_base,
144 p_pt->p_ldinf->client_id_limit);
145 }
146 SET_CURRENT_COMPONENT(p_pt);
147 }
148 }
149
backend_system_run(void)150 uint32_t backend_system_run(void)
151 {
152 void *param;
153 uint32_t psp;
154 uint32_t psp_limit;
155 const struct partition_load_info_t *pldi;
156 struct partition_t *partition = GET_CURRENT_COMPONENT();
157
158 SPM_ASSERT(partition != NULL);
159
160 pldi = partition->p_ldinf;
161
162 if (!IS_NS_AGENT(pldi)) {
163 tfm_core_panic();
164 }
165
166 /* NS agent expects NSPE entry point as the parameter */
167 param = (void *)tfm_hal_get_ns_entry_point();
168
169 /* Assign stack and stack limit. */
170 psp = arch_seal_thread_stack(((uint32_t)(LOAD_ALLOCED_STACK_ADDR(pldi)) +
171 (uint32_t)(pldi->stack_size)) & ~0x7UL);
172 psp_limit = ((uint32_t)(LOAD_ALLOCED_STACK_ADDR(pldi)) + 7) & ~0x7UL;
173
174 arch_update_process_sp(psp, psp_limit);
175
176 /*
177 * The current execution is Thread mode using MSP.
178 * Change to use PSP and reset MSP.
179 */
180 arch_clean_stack_and_launch(param, (uintptr_t)spm_init_function,
181 pldi->entry, SPM_BOOT_STACK_BOTTOM);
182
183 return 0;
184 }
185
backend_wait_signals(struct partition_t * p_pt,psa_signal_t signals)186 psa_signal_t backend_wait_signals(struct partition_t *p_pt, psa_signal_t signals)
187 {
188 while (!(p_pt->signals_asserted & signals)) {
189 __WFI();
190 }
191
192 return p_pt->signals_asserted & signals;
193 }
194
backend_assert_signal(struct partition_t * p_pt,psa_signal_t signal)195 psa_status_t backend_assert_signal(struct partition_t *p_pt, psa_signal_t signal)
196 {
197 p_pt->signals_asserted |= signal;
198
199 return PSA_SUCCESS;
200 }
201