1 /*
2  * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <arch_helpers.h>
32 #include <assert.h>
33 #include <bl_common.h>
34 #include <context_mgmt.h>
35 #include <debug.h>
36 #include <platform.h>
37 #include "opteed_private.h"
38 
39 /*******************************************************************************
40  * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any
41  * actions needed. Nothing at the moment.
42  ******************************************************************************/
opteed_cpu_on_handler(uint64_t target_cpu)43 static void opteed_cpu_on_handler(uint64_t target_cpu)
44 {
45 }
46 
47 /*******************************************************************************
48  * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
49  * needed
50  ******************************************************************************/
opteed_cpu_off_handler(uint64_t unused)51 static int32_t opteed_cpu_off_handler(uint64_t unused)
52 {
53 	int32_t rc = 0;
54 	uint64_t mpidr = read_mpidr();
55 	uint32_t linear_id = platform_get_core_pos(mpidr);
56 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
57 
58 	assert(optee_vectors);
59 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
60 
61 	/* Program the entry point and enter OPTEE */
62 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_off_entry);
63 	rc = opteed_synchronous_sp_entry(optee_ctx);
64 
65 	/*
66 	 * Read the response from OPTEE. A non-zero return means that
67 	 * something went wrong while communicating with OPTEE.
68 	 */
69 	if (rc != 0)
70 		panic();
71 
72 	/*
73 	 * Reset OPTEE's context for a fresh start when this cpu is turned on
74 	 * subsequently.
75 	 */
76 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
77 
78 	 return 0;
79 }
80 
81 /*******************************************************************************
82  * This cpu is being suspended. S-EL1 state must have been saved in the
83  * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
84  ******************************************************************************/
opteed_cpu_suspend_handler(uint64_t unused)85 static void opteed_cpu_suspend_handler(uint64_t unused)
86 {
87 	int32_t rc = 0;
88 	uint64_t mpidr = read_mpidr();
89 	uint32_t linear_id = platform_get_core_pos(mpidr);
90 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
91 
92 	assert(optee_vectors);
93 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
94 
95 	/* Program the entry point and enter OPTEE */
96 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_suspend_entry);
97 	rc = opteed_synchronous_sp_entry(optee_ctx);
98 
99 	/*
100 	 * Read the response from OPTEE. A non-zero return means that
101 	 * something went wrong while communicating with OPTEE.
102 	 */
103 	if (rc != 0)
104 		panic();
105 
106 	/* Update its context to reflect the state OPTEE is in */
107 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
108 }
109 
110 /*******************************************************************************
111  * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
112  * before passing control back to the Secure Monitor. Entry in S-El1 is done
113  * after initialising minimal architectural state that guarantees safe
114  * execution.
115  ******************************************************************************/
opteed_cpu_on_finish_handler(uint64_t unused)116 static void opteed_cpu_on_finish_handler(uint64_t unused)
117 {
118 	int32_t rc = 0;
119 	uint64_t mpidr = read_mpidr();
120 	uint32_t linear_id = platform_get_core_pos(mpidr);
121 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
122 	entry_point_info_t optee_on_entrypoint;
123 
124 	assert(optee_vectors);
125 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
126 
127 	opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
128 				(uint64_t)&optee_vectors->cpu_on_entry,
129 				0, 0, optee_ctx);
130 
131 	/* Initialise this cpu's secure context */
132 	cm_init_context(mpidr, &optee_on_entrypoint);
133 
134 	/* Enter OPTEE */
135 	rc = opteed_synchronous_sp_entry(optee_ctx);
136 
137 	/*
138 	 * Read the response from OPTEE. A non-zero return means that
139 	 * something went wrong while communicating with OPTEE.
140 	 */
141 	if (rc != 0)
142 		panic();
143 
144 	/* Update its context to reflect the state OPTEE is in */
145 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
146 }
147 
148 /*******************************************************************************
149  * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
150  * completed the preceding suspend call. Use that context to program an entry
151  * into OPTEE to allow it to do any remaining book keeping
152  ******************************************************************************/
opteed_cpu_suspend_finish_handler(uint64_t suspend_level)153 static void opteed_cpu_suspend_finish_handler(uint64_t suspend_level)
154 {
155 	int32_t rc = 0;
156 	uint64_t mpidr = read_mpidr();
157 	uint32_t linear_id = platform_get_core_pos(mpidr);
158 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
159 
160 	assert(optee_vectors);
161 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
162 
163 	/* Program the entry point, suspend_level and enter the SP */
164 	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
165 		      CTX_GPREG_X0,
166 		      suspend_level);
167 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry);
168 	rc = opteed_synchronous_sp_entry(optee_ctx);
169 
170 	/*
171 	 * Read the response from OPTEE. A non-zero return means that
172 	 * something went wrong while communicating with OPTEE.
173 	 */
174 	if (rc != 0)
175 		panic();
176 
177 	/* Update its context to reflect the state OPTEE is in */
178 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
179 }
180 
181 /*******************************************************************************
182  * Return the type of OPTEE the OPTEED is dealing with. Report the current
183  * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
184  ******************************************************************************/
opteed_cpu_migrate_info(uint64_t * resident_cpu)185 static int32_t opteed_cpu_migrate_info(uint64_t *resident_cpu)
186 {
187 	return OPTEE_MIGRATE_INFO;
188 }
189 
190 /*******************************************************************************
191  * System is about to be switched off. Allow the OPTEED/OPTEE to perform
192  * any actions needed.
193  ******************************************************************************/
opteed_system_off(void)194 static void opteed_system_off(void)
195 {
196 	uint64_t mpidr = read_mpidr();
197 	uint32_t linear_id = platform_get_core_pos(mpidr);
198 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
199 
200 	assert(optee_vectors);
201 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
202 
203 	/* Program the entry point */
204 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_off_entry);
205 
206 	/* Enter OPTEE. We do not care about the return value because we
207 	 * must continue the shutdown anyway */
208 	opteed_synchronous_sp_entry(optee_ctx);
209 }
210 
211 /*******************************************************************************
212  * System is about to be reset. Allow the OPTEED/OPTEE to perform
213  * any actions needed.
214  ******************************************************************************/
opteed_system_reset(void)215 static void opteed_system_reset(void)
216 {
217 	uint64_t mpidr = read_mpidr();
218 	uint32_t linear_id = platform_get_core_pos(mpidr);
219 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
220 
221 	assert(optee_vectors);
222 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
223 
224 	/* Program the entry point */
225 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_reset_entry);
226 
227 	/* Enter OPTEE. We do not care about the return value because we
228 	 * must continue the reset anyway */
229 	opteed_synchronous_sp_entry(optee_ctx);
230 }
231 
232 
233 /*******************************************************************************
234  * Structure populated by the OPTEE Dispatcher to be given a chance to
235  * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
236  * operation.
237  ******************************************************************************/
238 const spd_pm_ops_t opteed_pm = {
239 	.svc_on = opteed_cpu_on_handler,
240 	.svc_off = opteed_cpu_off_handler,
241 	.svc_suspend = opteed_cpu_suspend_handler,
242 	.svc_on_finish = opteed_cpu_on_finish_handler,
243 	.svc_suspend_finish = opteed_cpu_suspend_finish_handler,
244 	.svc_migrate = NULL,
245 	.svc_migrate_info = opteed_cpu_migrate_info,
246 	.svc_system_off = opteed_system_off,
247 	.svc_system_reset = opteed_system_reset,
248 };
249 
250