1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include <assert.h>
14 #include <bl_common.h>
15 #include <context_mgmt.h>
16 #include <arch_helpers.h>
17 #include <platform.h>
18 #include <runtime_svc.h>
19 #include <string.h>
20 #include <context.h>
21 #include <spinlock.h>
22 #include "teed_common.h"
23 #include "teed_private.h"
24
25 static uint32_t g_cpu_initialized[TEED_CORE_COUNT];
26
27 /* need to be implemented */
is_system_suspend(void)28 static int32_t is_system_suspend(void)
29 {
30 return 1;
31 }
32
33 /*
34 * The target cpu is being turned on. Allow the TEED/TEE to perform any actions
35 * needed. Nothing at the moment.
36 */
teed_cpu_on_handler(u_register_t target_cpu)37 static void teed_cpu_on_handler(u_register_t target_cpu)
38 {
39 (void)target_cpu;
40 }
41
42 /*
43 * This cpu is being turned off. Allow the TEED/TEE to perform
44 * any actions needed
45 */
teed_cpu_off_handler(u_register_t unused)46 static int32_t teed_cpu_off_handler(u_register_t unused)
47 {
48 uint32_t linear_id = plat_my_core_pos();
49 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
50 assert(tee_ctx != NULL);
51 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_ON);
52 /*
53 * Abort any preempted SMC request before overwriting the SECURE
54 * context.
55 */
56 set_tee_pstate(tee_ctx->state, TEE_PSTATE_OFF);
57
58 return 0;
59 }
60
61 /*
62 * This cpu is being suspended. S-EL1 state must have been saved in the
63 * resident cpu (mpidr format) if it is a UP/UP migratable TEE.
64 */
teed_cpu_suspend_handler(u_register_t max_off_pwrlvl)65 static void teed_cpu_suspend_handler(u_register_t max_off_pwrlvl)
66 {
67 int32_t rc;
68 uint64_t power_state;
69 uint32_t linear_id = plat_my_core_pos();
70 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
71 assert(tee_ctx != NULL);
72
73 tee_vectors_t* tee_vectors_tmp = get_tee_vectors_t();
74 (void)max_off_pwrlvl;
75 assert(tee_vectors_tmp != NULL);
76 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_ON);
77 /*
78 * Abort any preempted SMC request before overwriting the SECURE
79 * context.
80 */
81 if (is_system_suspend() != 0)
82 power_state = CPU_IDLE_STATE; /* stand for cpu idle */
83 else
84 power_state = CPU_SUSPEND_STATE; /* stand for cpu suspend */
85
86 /* Program the entry point and enter the TEE */
87 write_ctx_reg(get_gpregs_ctx(&tee_ctx->cpu_context),
88 CTX_GPREG_X0,
89 power_state);
90 tee_ctx->spsr_el3 = SMC_GET_EL3(&tee_ctx->cpu_context,
91 CTX_SPSR_EL3);
92 tee_ctx->elr_el3 = SMC_GET_EL3(&tee_ctx->cpu_context,
93 CTX_ELR_EL3);
94 cm_set_elr_spsr_el3(SECURE, (uintptr_t)&tee_vectors_tmp->cpu_suspend_entry,
95 SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
96 rc = teed_synchronous_sp_entry(tee_ctx);
97 /*
98 * Read the response from the TEE. A non-zero return means that
99 * something went wrong while communicating with the TEE.
100 */
101 if (rc != 0)
102 panic();
103 /* Update its context to reflect the state the TEE is in */
104 set_tee_pstate(tee_ctx->state, TEE_PSTATE_SUSPEND);
105 }
106
107 /*
108 * This cpu has been turned on. Enter the TEE to initialise S-EL1 and other bits
109 * before passing control back to the Secure Monitor. Entry in S-EL1 is done
110 * after initialising minimal architectural state that guarantees safe
111 * execution.
112 */
teed_cpu_on_finish_handler(u_register_t unused)113 static void teed_cpu_on_finish_handler(u_register_t unused)
114 {
115 int32_t rc;
116 uint32_t linear_id = plat_my_core_pos();
117 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
118 assert(tee_ctx != NULL);
119 entry_point_info_t tee_on_entrypoint;
120 el3_state_t *state = NULL;
121
122 tee_vectors_t *tee_vectors_tmp = get_tee_vectors_t();
123 assert(tee_vectors_tmp != NULL);
124 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_OFF);
125 set_tee_pstate(tee_ctx->state, TEE_PSTATE_ON);
126
127 uint64_t mpidr = read_mpidr();
128 uint64_t primary_cpu_mpidr_tmp = get_primary_cpu_mpidr();
129 if (linear_id >= TEED_CORE_COUNT)
130 return;
131
132 bool condition = (g_cpu_initialized[linear_id] == CPU_INIT_DONE ||
133 mpidr == primary_cpu_mpidr_tmp);
134 if (!condition) {
135 tee_context_t *teed_sp_init_context = get_teed_sp_init_context();
136 assert(teed_sp_init_context != NULL);
137 (void)memcpy(&tee_ctx->cpu_context, &(teed_sp_init_context->cpu_context), sizeof(cpu_context_t));
138 (void)memset(&tee_on_entrypoint, 0, sizeof(tee_on_entrypoint));
139 /* Initialise this cpu's secure context */
140 teed_init_tee_ep_state(&tee_on_entrypoint,
141 TEE_AARCH64,
142 (uintptr_t)&tee_vectors_tmp->cpu_on_entry,
143 tee_ctx);
144 state = get_el3state_ctx(&tee_ctx->cpu_context);
145 write_ctx_reg(state, CTX_ELR_EL3, tee_on_entrypoint.pc);
146 write_ctx_reg(state, CTX_SPSR_EL3, tee_on_entrypoint.spsr);
147 }
148 /* Enter the TEE */
149 rc = teed_synchronous_sp_entry(tee_ctx);
150 g_cpu_initialized[linear_id] = CPU_INIT_DONE;
151 /*
152 * Read the response from the TEE. A non-zero return means that
153 * something went wrong while communicating with the SP.
154 */
155 if (rc != 0)
156 panic();
157 /* Update its context to reflect the state the SP is in */
158 set_tee_pstate(tee_ctx->state, TEE_PSTATE_ON);
159 }
160
161 /*
162 * This cpu has resumed from suspend. The SPD saved the TEE context when it
163 * completed the preceding suspend call. Use that context to program an entry
164 * into the TEE to allow it to do any remaining book keeping
165 */
teed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)166 static void teed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)
167 {
168 int32_t rc;
169 uint64_t power_state;
170 uint32_t linear_id = plat_my_core_pos();
171 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
172 assert(tee_ctx != NULL);
173
174 (void)max_off_pwrlvl;
175 tee_vectors_t* tee_vectors_tmp = get_tee_vectors_t();
176 assert(tee_vectors_tmp != NULL);
177 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_SUSPEND);
178
179 if (is_system_suspend() != 0)
180 power_state = CPU_IDLE_STATE; /* stand for cpu idle */
181 else
182 power_state = CPU_SUSPEND_STATE; /* stand for cpu suspend */
183
184 /* Program the entry point, max_off_pwrlvl and enter the SP */
185 write_ctx_reg(get_gpregs_ctx(&tee_ctx->cpu_context),
186 CTX_GPREG_X0,
187 power_state);
188 tee_ctx->spsr_el3 = SMC_GET_EL3(&tee_ctx->cpu_context,
189 CTX_SPSR_EL3);
190 tee_ctx->elr_el3 = SMC_GET_EL3(&tee_ctx->cpu_context,
191 CTX_ELR_EL3);
192 cm_set_elr_spsr_el3(SECURE, (uintptr_t)&tee_vectors_tmp->cpu_resume_entry,
193 SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
194 rc = teed_synchronous_sp_entry(tee_ctx);
195 /*
196 * Read the response from the TEE. A non-zero return means that
197 * something went wrong while communicating with the TEE.
198 */
199 if (rc != 0)
200 panic();
201 /* Update its context to reflect the state the SP is in */
202 set_tee_pstate(tee_ctx->state, TEE_PSTATE_ON);
203 }
204
205 /*
206 * Return the type of TEE the TEED is dealing with. Report the current resident
207 * cpu (mpidr format) if it is a UP/UP migratable TEE.
208 */
teed_cpu_migrate_info(u_register_t * resident_cpu)209 static int32_t teed_cpu_migrate_info(u_register_t *resident_cpu)
210 {
211 (void)resident_cpu;
212 return TEE_MIGRATE_INFO;
213 }
214
215 /*
216 * System is about to be switched off. Allow the TEED/TEE to perform
217 * any actions needed.
218 */
teed_system_off(void)219 static void teed_system_off(void)
220 {
221 uint32_t linear_id = plat_my_core_pos();
222 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
223 tee_vectors_t* tee_vectors_tmp = get_tee_vectors_t();
224
225 assert(tee_vectors_tmp != NULL);
226 assert(tee_ctx != NULL);
227 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_ON);
228
229 /* Program the entry point */
230 cm_set_elr_spsr_el3(SECURE, (uintptr_t)&tee_vectors_tmp->system_off_entry,
231 SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
232 /*
233 * Enter the TEE. We do not care about the return value because we
234 * must continue the shutdown anyway
235 */
236 NOTICE("teed system off\n");
237 (void)teed_synchronous_sp_entry(tee_ctx);
238 }
239
240 /*
241 * System is about to be reset. Allow the TEED/TEE to perform
242 * any actions needed.
243 */
teed_system_reset(void)244 static void teed_system_reset(void)
245 {
246 uint32_t linear_id = plat_my_core_pos();
247 tee_context_t *tee_ctx = get_teed_sp_context(linear_id);
248 tee_vectors_t *tee_vectors_tmp = get_tee_vectors_t();
249
250 assert(tee_vectors_tmp != NULL);
251 assert(tee_ctx != NULL);
252 assert(get_tee_pstate(tee_ctx->state) == TEE_PSTATE_ON);
253 /*
254 * Abort any preempted SMC request before overwriting the SECURE
255 * context.
256 * Program the entry point
257 */
258 cm_set_elr_spsr_el3(SECURE, (uintptr_t)&tee_vectors_tmp->system_reset_entry,
259 SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
260 /*
261 * Enter the TEE. We do not care about the return value because we
262 * must continue the reset anyway
263 */
264 NOTICE("teed system reset\n");
265 (void)teed_synchronous_sp_entry(tee_ctx);
266 }
267
268 /*
269 * Structure populated by the TEE Dispatcher to be given a chance to perform any
270 * TEE bookkeeping before PSCI executes a power management operation.
271 */
272 static const spd_pm_ops_t g_teed_pm = {
273 .svc_on = teed_cpu_on_handler,
274 .svc_off = teed_cpu_off_handler,
275 .svc_suspend = teed_cpu_suspend_handler,
276 .svc_on_finish = teed_cpu_on_finish_handler,
277 .svc_suspend_finish = teed_cpu_suspend_finish_handler,
278 .svc_migrate = NULL,
279 .svc_migrate_info = teed_cpu_migrate_info,
280 .svc_system_off = teed_system_off,
281 .svc_system_reset = teed_system_reset
282 };
283
get_teed_pm()284 const spd_pm_ops_t *get_teed_pm()
285 {
286 return &g_teed_pm;
287 }
288