• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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