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