1 /*
2 * Copyright (c) 2017-2022, 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 <errno.h>
10
11 #include <bl31/bl31.h>
12 #include <bl31/ehf.h>
13 #include <common/debug.h>
14 #include <common/runtime_svc.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/smccc.h>
17 #include <lib/spinlock.h>
18 #include <lib/utils.h>
19 #include <lib/xlat_tables/xlat_tables_v2.h>
20 #include <plat/common/platform.h>
21 #include <services/spm_mm_partition.h>
22 #include <services/spm_mm_svc.h>
23 #include <smccc_helpers.h>
24
25 #include "spm_common.h"
26 #include "spm_mm_private.h"
27
28 /*******************************************************************************
29 * Secure Partition context information.
30 ******************************************************************************/
31 static sp_context_t sp_ctx;
32
33 /*******************************************************************************
34 * Set state of a Secure Partition context.
35 ******************************************************************************/
sp_state_set(sp_context_t * sp_ptr,sp_state_t state)36 void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
37 {
38 spin_lock(&(sp_ptr->state_lock));
39 sp_ptr->state = state;
40 spin_unlock(&(sp_ptr->state_lock));
41 }
42
43 /*******************************************************************************
44 * Wait until the state of a Secure Partition is the specified one and change it
45 * to the desired state.
46 ******************************************************************************/
sp_state_wait_switch(sp_context_t * sp_ptr,sp_state_t from,sp_state_t to)47 void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
48 {
49 int success = 0;
50
51 while (success == 0) {
52 spin_lock(&(sp_ptr->state_lock));
53
54 if (sp_ptr->state == from) {
55 sp_ptr->state = to;
56
57 success = 1;
58 }
59
60 spin_unlock(&(sp_ptr->state_lock));
61 }
62 }
63
64 /*******************************************************************************
65 * Check if the state of a Secure Partition is the specified one and, if so,
66 * change it to the desired state. Returns 0 on success, -1 on error.
67 ******************************************************************************/
sp_state_try_switch(sp_context_t * sp_ptr,sp_state_t from,sp_state_t to)68 int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
69 {
70 int ret = -1;
71
72 spin_lock(&(sp_ptr->state_lock));
73
74 if (sp_ptr->state == from) {
75 sp_ptr->state = to;
76
77 ret = 0;
78 }
79
80 spin_unlock(&(sp_ptr->state_lock));
81
82 return ret;
83 }
84
85 /*******************************************************************************
86 * This function takes an SP context pointer and performs a synchronous entry
87 * into it.
88 ******************************************************************************/
spm_sp_synchronous_entry(sp_context_t * ctx)89 static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
90 {
91 uint64_t rc;
92
93 assert(ctx != NULL);
94
95 /* Assign the context of the SP to this CPU */
96 cm_set_context(&(ctx->cpu_ctx), SECURE);
97
98 /* Restore the context assigned above */
99 cm_el1_sysregs_context_restore(SECURE);
100 cm_set_next_eret_context(SECURE);
101
102 /* Invalidate TLBs at EL1. */
103 tlbivmalle1();
104 dsbish();
105
106 /* Enter Secure Partition */
107 rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
108
109 /* Save secure state */
110 cm_el1_sysregs_context_save(SECURE);
111
112 return rc;
113 }
114
115 /*******************************************************************************
116 * This function returns to the place where spm_sp_synchronous_entry() was
117 * called originally.
118 ******************************************************************************/
spm_sp_synchronous_exit(uint64_t rc)119 __dead2 static void spm_sp_synchronous_exit(uint64_t rc)
120 {
121 sp_context_t *ctx = &sp_ctx;
122
123 /*
124 * The SPM must have initiated the original request through a
125 * synchronous entry into the secure partition. Jump back to the
126 * original C runtime context with the value of rc in x0;
127 */
128 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
129
130 panic();
131 }
132
133 /*******************************************************************************
134 * Jump to each Secure Partition for the first time.
135 ******************************************************************************/
spm_init(void)136 static int32_t spm_init(void)
137 {
138 uint64_t rc;
139 sp_context_t *ctx;
140
141 INFO("Secure Partition init...\n");
142
143 ctx = &sp_ctx;
144
145 ctx->state = SP_STATE_RESET;
146
147 rc = spm_sp_synchronous_entry(ctx);
148 assert(rc == 0);
149
150 ctx->state = SP_STATE_IDLE;
151
152 INFO("Secure Partition initialized.\n");
153
154 return !rc;
155 }
156
157 /*******************************************************************************
158 * Initialize contexts of all Secure Partitions.
159 ******************************************************************************/
spm_mm_setup(void)160 int32_t spm_mm_setup(void)
161 {
162 sp_context_t *ctx;
163
164 /* Disable MMU at EL1 (initialized by BL2) */
165 disable_mmu_icache_el1();
166
167 /* Initialize context of the SP */
168 INFO("Secure Partition context setup start...\n");
169
170 ctx = &sp_ctx;
171
172 /* Assign translation tables context. */
173 ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
174
175 spm_sp_setup(ctx);
176
177 /* Register init function for deferred init. */
178 bl31_register_bl32_init(&spm_init);
179
180 INFO("Secure Partition setup done.\n");
181
182 return 0;
183 }
184
185 /*******************************************************************************
186 * Function to perform a call to a Secure Partition.
187 ******************************************************************************/
spm_mm_sp_call(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3)188 uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
189 {
190 uint64_t rc;
191 sp_context_t *sp_ptr = &sp_ctx;
192
193 #if CTX_INCLUDE_FPREGS
194 /*
195 * SP runs to completion, no need to restore FP registers of secure context.
196 * Save FP registers only for non secure context.
197 */
198 fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
199 #endif
200
201 /* Wait until the Secure Partition is idle and set it to busy. */
202 sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
203
204 /* Set values for registers on SP entry */
205 cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
206
207 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
208 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
209 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
210 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
211
212 /* Jump to the Secure Partition. */
213 rc = spm_sp_synchronous_entry(sp_ptr);
214
215 /* Flag Secure Partition as idle. */
216 assert(sp_ptr->state == SP_STATE_BUSY);
217 sp_state_set(sp_ptr, SP_STATE_IDLE);
218
219 #if CTX_INCLUDE_FPREGS
220 /*
221 * SP runs to completion, no need to save FP registers of secure context.
222 * Restore only non secure world FP registers.
223 */
224 fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
225 #endif
226
227 return rc;
228 }
229
230 /*******************************************************************************
231 * MM_COMMUNICATE handler
232 ******************************************************************************/
mm_communicate(uint32_t smc_fid,uint64_t mm_cookie,uint64_t comm_buffer_address,uint64_t comm_size_address,void * handle)233 static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
234 uint64_t comm_buffer_address,
235 uint64_t comm_size_address, void *handle)
236 {
237 uint64_t rc;
238
239 /* Cookie. Reserved for future use. It must be zero. */
240 if (mm_cookie != 0U) {
241 ERROR("MM_COMMUNICATE: cookie is not zero\n");
242 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
243 }
244
245 if (comm_buffer_address == 0U) {
246 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
247 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
248 }
249
250 if (comm_size_address != 0U) {
251 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
252 }
253
254 /*
255 * The current secure partition design mandates
256 * - at any point, only a single core can be
257 * executing in the secure partiton.
258 * - a core cannot be preempted by an interrupt
259 * while executing in secure partition.
260 * Raise the running priority of the core to the
261 * interrupt level configured for secure partition
262 * so as to block any interrupt from preempting this
263 * core.
264 */
265 ehf_activate_priority(PLAT_SP_PRI);
266
267 /* Save the Normal world context */
268 cm_el1_sysregs_context_save(NON_SECURE);
269
270 rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
271 plat_my_core_pos());
272
273 /* Restore non-secure state */
274 cm_el1_sysregs_context_restore(NON_SECURE);
275 cm_set_next_eret_context(NON_SECURE);
276
277 /*
278 * Exited from secure partition. This core can take
279 * interrupts now.
280 */
281 ehf_deactivate_priority(PLAT_SP_PRI);
282
283 SMC_RET1(handle, rc);
284 }
285
286 /*******************************************************************************
287 * Secure Partition Manager SMC handler.
288 ******************************************************************************/
spm_mm_smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)289 uint64_t spm_mm_smc_handler(uint32_t smc_fid,
290 uint64_t x1,
291 uint64_t x2,
292 uint64_t x3,
293 uint64_t x4,
294 void *cookie,
295 void *handle,
296 uint64_t flags)
297 {
298 unsigned int ns;
299
300 /* Determine which security state this SMC originated from */
301 ns = is_caller_non_secure(flags);
302
303 if (ns == SMC_FROM_SECURE) {
304
305 /* Handle SMCs from Secure world. */
306
307 assert(handle == cm_get_context(SECURE));
308
309 /* Make next ERET jump to S-EL0 instead of S-EL1. */
310 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
311
312 switch (smc_fid) {
313
314 case SPM_MM_VERSION_AARCH32:
315 SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
316
317 case MM_SP_EVENT_COMPLETE_AARCH64:
318 spm_sp_synchronous_exit(x1);
319
320 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
321 INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
322
323 if (sp_ctx.state != SP_STATE_RESET) {
324 WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
325 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
326 }
327 SMC_RET1(handle,
328 spm_memory_attributes_get_smc_handler(
329 &sp_ctx, x1));
330
331 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
332 INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
333
334 if (sp_ctx.state != SP_STATE_RESET) {
335 WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
336 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
337 }
338 SMC_RET1(handle,
339 spm_memory_attributes_set_smc_handler(
340 &sp_ctx, x1, x2, x3));
341 default:
342 break;
343 }
344 } else {
345
346 /* Handle SMCs from Non-secure world. */
347
348 assert(handle == cm_get_context(NON_SECURE));
349
350 switch (smc_fid) {
351
352 case MM_VERSION_AARCH32:
353 SMC_RET1(handle, MM_VERSION_COMPILED);
354
355 case MM_COMMUNICATE_AARCH32:
356 case MM_COMMUNICATE_AARCH64:
357 return mm_communicate(smc_fid, x1, x2, x3, handle);
358
359 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
360 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
361 /* SMC interfaces reserved for secure callers. */
362 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
363
364 default:
365 break;
366 }
367 }
368
369 SMC_RET1(handle, SMC_UNK);
370 }
371