blob: 1ff7bb77c195e3ecbfb0c4ce3e1317b81751200c [file] [log] [blame]
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +00001/*
Marc Bonnici758bd242021-12-19 21:37:50 +00002 * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +00003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <assert.h>
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +00009#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
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>
Paul Beesley45f40282019-10-15 10:57:42 +000021#include <services/spm_mm_partition.h>
Paul Beesleye9754e62019-10-15 12:51:55 +000022#include <services/spm_mm_svc.h>
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000023#include <smccc_helpers.h>
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000024
Marc Bonnici758bd242021-12-19 21:37:50 +000025#include "spm_common.h"
Paul Beesley15a96a92019-10-15 14:23:23 +000026#include "spm_mm_private.h"
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000027
28/*******************************************************************************
29 * Secure Partition context information.
30 ******************************************************************************/
31static sp_context_t sp_ctx;
32
33/*******************************************************************************
34 * Set state of a Secure Partition context.
35 ******************************************************************************/
36void 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 ******************************************************************************/
47void 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 ******************************************************************************/
68int 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 ******************************************************************************/
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010089static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000090{
91 uint64_t rc;
92
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010093 assert(ctx != NULL);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000094
95 /* Assign the context of the SP to this CPU */
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010096 cm_set_context(&(ctx->cpu_ctx), SECURE);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000097
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 */
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +0100107 rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000108
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 ******************************************************************************/
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 ******************************************************************************/
136static 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
Ard Biesheuvel0b429162019-01-01 11:03:08 +0100154 return !rc;
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000155}
156
157/*******************************************************************************
158 * Initialize contexts of all Secure Partitions.
159 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000160int32_t spm_mm_setup(void)
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000161{
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 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000188uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000189{
190 uint64_t rc;
191 sp_context_t *sp_ptr = &sp_ctx;
192
Nishant Sharma9c393522022-04-19 10:16:48 +0100193#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
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000201 /* 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
Nishant Sharma9c393522022-04-19 10:16:48 +0100219#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
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000227 return rc;
228}
229
230/*******************************************************************************
231 * MM_COMMUNICATE handler
232 ******************************************************************************/
233static 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");
Paul Beesleye9754e62019-10-15 12:51:55 +0000242 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000243 }
244
245 if (comm_buffer_address == 0U) {
246 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
Paul Beesleye9754e62019-10-15 12:51:55 +0000247 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000248 }
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
Elyes Haouas2be03c02023-02-13 09:14:48 +0100257 * executing in the secure partition.
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000258 * - 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
Paul Beesleye9754e62019-10-15 12:51:55 +0000270 rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
271 plat_my_core_pos());
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000272
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 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000289uint64_t spm_mm_smc_handler(uint32_t smc_fid,
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000290 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
Paul Beesleye9754e62019-10-15 12:51:55 +0000314 case SPM_MM_VERSION_AARCH32:
315 SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000316
Paul Beesleye9754e62019-10-15 12:51:55 +0000317 case MM_SP_EVENT_COMPLETE_AARCH64:
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000318 spm_sp_synchronous_exit(x1);
319
Paul Beesleye9754e62019-10-15 12:51:55 +0000320 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
321 INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000322
323 if (sp_ctx.state != SP_STATE_RESET) {
Paul Beesleye9754e62019-10-15 12:51:55 +0000324 WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
325 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000326 }
327 SMC_RET1(handle,
328 spm_memory_attributes_get_smc_handler(
329 &sp_ctx, x1));
330
Paul Beesleye9754e62019-10-15 12:51:55 +0000331 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
332 INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000333
334 if (sp_ctx.state != SP_STATE_RESET) {
Paul Beesleye9754e62019-10-15 12:51:55 +0000335 WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
336 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000337 }
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
Paul Beesleye9754e62019-10-15 12:51:55 +0000359 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
360 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000361 /* SMC interfaces reserved for secure callers. */
Paul Beesleye9754e62019-10-15 12:51:55 +0000362 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000363
364 default:
365 break;
366 }
367 }
368
369 SMC_RET1(handle, SMC_UNK);
370}