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