1 /*
2 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <bl_common.h>
10 #include <context_mgmt.h>
11 #include <debug.h>
12 #include <platform.h>
13 #include "opteed_private.h"
14
15 /*******************************************************************************
16 * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any
17 * actions needed. Nothing at the moment.
18 ******************************************************************************/
opteed_cpu_on_handler(uint64_t target_cpu)19 static void opteed_cpu_on_handler(uint64_t target_cpu)
20 {
21 }
22
23 /*******************************************************************************
24 * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
25 * needed
26 ******************************************************************************/
opteed_cpu_off_handler(uint64_t unused)27 static int32_t opteed_cpu_off_handler(uint64_t unused)
28 {
29 int32_t rc = 0;
30 uint32_t linear_id = plat_my_core_pos();
31 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
32
33 assert(optee_vectors);
34 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
35
36 /* Program the entry point and enter OPTEE */
37 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_off_entry);
38 rc = opteed_synchronous_sp_entry(optee_ctx);
39
40 /*
41 * Read the response from OPTEE. A non-zero return means that
42 * something went wrong while communicating with OPTEE.
43 */
44 if (rc != 0)
45 panic();
46
47 /*
48 * Reset OPTEE's context for a fresh start when this cpu is turned on
49 * subsequently.
50 */
51 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
52
53 return 0;
54 }
55
56 /*******************************************************************************
57 * This cpu is being suspended. S-EL1 state must have been saved in the
58 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
59 ******************************************************************************/
opteed_cpu_suspend_handler(uint64_t max_off_pwrlvl)60 static void opteed_cpu_suspend_handler(uint64_t max_off_pwrlvl)
61 {
62 int32_t rc = 0;
63 uint32_t linear_id = plat_my_core_pos();
64 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
65
66 assert(optee_vectors);
67 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
68
69 /* Program the entry point and enter OPTEE */
70 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_suspend_entry);
71 rc = opteed_synchronous_sp_entry(optee_ctx);
72
73 /*
74 * Read the response from OPTEE. A non-zero return means that
75 * something went wrong while communicating with OPTEE.
76 */
77 if (rc != 0)
78 panic();
79
80 /* Update its context to reflect the state OPTEE is in */
81 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
82 }
83
84 /*******************************************************************************
85 * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
86 * before passing control back to the Secure Monitor. Entry in S-El1 is done
87 * after initialising minimal architectural state that guarantees safe
88 * execution.
89 ******************************************************************************/
opteed_cpu_on_finish_handler(uint64_t unused)90 static void opteed_cpu_on_finish_handler(uint64_t unused)
91 {
92 int32_t rc = 0;
93 uint32_t linear_id = plat_my_core_pos();
94 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
95 entry_point_info_t optee_on_entrypoint;
96
97 assert(optee_vectors);
98 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
99
100 opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
101 (uint64_t)&optee_vectors->cpu_on_entry,
102 0, 0, 0, optee_ctx);
103
104 /* Initialise this cpu's secure context */
105 cm_init_my_context(&optee_on_entrypoint);
106
107 /* Enter OPTEE */
108 rc = opteed_synchronous_sp_entry(optee_ctx);
109
110 /*
111 * Read the response from OPTEE. A non-zero return means that
112 * something went wrong while communicating with OPTEE.
113 */
114 if (rc != 0)
115 panic();
116
117 /* Update its context to reflect the state OPTEE is in */
118 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
119 }
120
121 /*******************************************************************************
122 * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
123 * completed the preceding suspend call. Use that context to program an entry
124 * into OPTEE to allow it to do any remaining book keeping
125 ******************************************************************************/
opteed_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl)126 static void opteed_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl)
127 {
128 int32_t rc = 0;
129 uint32_t linear_id = plat_my_core_pos();
130 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
131
132 assert(optee_vectors);
133 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
134
135 /* Program the entry point, max_off_pwrlvl and enter the SP */
136 write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
137 CTX_GPREG_X0,
138 max_off_pwrlvl);
139 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry);
140 rc = opteed_synchronous_sp_entry(optee_ctx);
141
142 /*
143 * Read the response from OPTEE. A non-zero return means that
144 * something went wrong while communicating with OPTEE.
145 */
146 if (rc != 0)
147 panic();
148
149 /* Update its context to reflect the state OPTEE is in */
150 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
151 }
152
153 /*******************************************************************************
154 * Return the type of OPTEE the OPTEED is dealing with. Report the current
155 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
156 ******************************************************************************/
opteed_cpu_migrate_info(uint64_t * resident_cpu)157 static int32_t opteed_cpu_migrate_info(uint64_t *resident_cpu)
158 {
159 return OPTEE_MIGRATE_INFO;
160 }
161
162 /*******************************************************************************
163 * System is about to be switched off. Allow the OPTEED/OPTEE to perform
164 * any actions needed.
165 ******************************************************************************/
opteed_system_off(void)166 static void opteed_system_off(void)
167 {
168 uint32_t linear_id = plat_my_core_pos();
169 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
170
171 assert(optee_vectors);
172 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
173
174 /* Program the entry point */
175 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_off_entry);
176
177 /* Enter OPTEE. We do not care about the return value because we
178 * must continue the shutdown anyway */
179 opteed_synchronous_sp_entry(optee_ctx);
180 }
181
182 /*******************************************************************************
183 * System is about to be reset. Allow the OPTEED/OPTEE to perform
184 * any actions needed.
185 ******************************************************************************/
opteed_system_reset(void)186 static void opteed_system_reset(void)
187 {
188 uint32_t linear_id = plat_my_core_pos();
189 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
190
191 assert(optee_vectors);
192 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
193
194 /* Program the entry point */
195 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_reset_entry);
196
197 /* Enter OPTEE. We do not care about the return value because we
198 * must continue the reset anyway */
199 opteed_synchronous_sp_entry(optee_ctx);
200 }
201
202
203 /*******************************************************************************
204 * Structure populated by the OPTEE Dispatcher to be given a chance to
205 * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
206 * operation.
207 ******************************************************************************/
208 const spd_pm_ops_t opteed_pm = {
209 .svc_on = opteed_cpu_on_handler,
210 .svc_off = opteed_cpu_off_handler,
211 .svc_suspend = opteed_cpu_suspend_handler,
212 .svc_on_finish = opteed_cpu_on_finish_handler,
213 .svc_suspend_finish = opteed_cpu_suspend_finish_handler,
214 .svc_migrate = NULL,
215 .svc_migrate_info = opteed_cpu_migrate_info,
216 .svc_system_off = opteed_system_off,
217 .svc_system_reset = opteed_system_reset,
218 };
219