blob: 433e3351f31c4ff8fe849ccb286b9a28cdc74cef [file] [log] [blame]
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +00001/*
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +01002 * Copyright (c) 2017-2019, 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
25#include "spm_private.h"
26
27/*******************************************************************************
28 * Secure Partition context information.
29 ******************************************************************************/
30static sp_context_t sp_ctx;
31
32/*******************************************************************************
33 * Set state of a Secure Partition context.
34 ******************************************************************************/
35void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
36{
37 spin_lock(&(sp_ptr->state_lock));
38 sp_ptr->state = state;
39 spin_unlock(&(sp_ptr->state_lock));
40}
41
42/*******************************************************************************
43 * Wait until the state of a Secure Partition is the specified one and change it
44 * to the desired state.
45 ******************************************************************************/
46void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
47{
48 int success = 0;
49
50 while (success == 0) {
51 spin_lock(&(sp_ptr->state_lock));
52
53 if (sp_ptr->state == from) {
54 sp_ptr->state = to;
55
56 success = 1;
57 }
58
59 spin_unlock(&(sp_ptr->state_lock));
60 }
61}
62
63/*******************************************************************************
64 * Check if the state of a Secure Partition is the specified one and, if so,
65 * change it to the desired state. Returns 0 on success, -1 on error.
66 ******************************************************************************/
67int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
68{
69 int ret = -1;
70
71 spin_lock(&(sp_ptr->state_lock));
72
73 if (sp_ptr->state == from) {
74 sp_ptr->state = to;
75
76 ret = 0;
77 }
78
79 spin_unlock(&(sp_ptr->state_lock));
80
81 return ret;
82}
83
84/*******************************************************************************
85 * This function takes an SP context pointer and performs a synchronous entry
86 * into it.
87 ******************************************************************************/
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010088static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000089{
90 uint64_t rc;
91
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010092 assert(ctx != NULL);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000093
94 /* Assign the context of the SP to this CPU */
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +010095 cm_set_context(&(ctx->cpu_ctx), SECURE);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000096
97 /* Restore the context assigned above */
98 cm_el1_sysregs_context_restore(SECURE);
99 cm_set_next_eret_context(SECURE);
100
101 /* Invalidate TLBs at EL1. */
102 tlbivmalle1();
103 dsbish();
104
105 /* Enter Secure Partition */
Justin Chadwell7d0e3ba2019-09-17 15:21:50 +0100106 rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000107
108 /* Save secure state */
109 cm_el1_sysregs_context_save(SECURE);
110
111 return rc;
112}
113
114/*******************************************************************************
115 * This function returns to the place where spm_sp_synchronous_entry() was
116 * called originally.
117 ******************************************************************************/
118__dead2 static void spm_sp_synchronous_exit(uint64_t rc)
119{
120 sp_context_t *ctx = &sp_ctx;
121
122 /*
123 * The SPM must have initiated the original request through a
124 * synchronous entry into the secure partition. Jump back to the
125 * original C runtime context with the value of rc in x0;
126 */
127 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
128
129 panic();
130}
131
132/*******************************************************************************
133 * Jump to each Secure Partition for the first time.
134 ******************************************************************************/
135static int32_t spm_init(void)
136{
137 uint64_t rc;
138 sp_context_t *ctx;
139
140 INFO("Secure Partition init...\n");
141
142 ctx = &sp_ctx;
143
144 ctx->state = SP_STATE_RESET;
145
146 rc = spm_sp_synchronous_entry(ctx);
147 assert(rc == 0);
148
149 ctx->state = SP_STATE_IDLE;
150
151 INFO("Secure Partition initialized.\n");
152
Ard Biesheuvel0b429162019-01-01 11:03:08 +0100153 return !rc;
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000154}
155
156/*******************************************************************************
157 * Initialize contexts of all Secure Partitions.
158 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000159int32_t spm_mm_setup(void)
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000160{
161 sp_context_t *ctx;
162
163 /* Disable MMU at EL1 (initialized by BL2) */
164 disable_mmu_icache_el1();
165
166 /* Initialize context of the SP */
167 INFO("Secure Partition context setup start...\n");
168
169 ctx = &sp_ctx;
170
171 /* Assign translation tables context. */
172 ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
173
174 spm_sp_setup(ctx);
175
176 /* Register init function for deferred init. */
177 bl31_register_bl32_init(&spm_init);
178
179 INFO("Secure Partition setup done.\n");
180
181 return 0;
182}
183
184/*******************************************************************************
185 * Function to perform a call to a Secure Partition.
186 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000187uint64_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 +0000188{
189 uint64_t rc;
190 sp_context_t *sp_ptr = &sp_ctx;
191
192 /* Wait until the Secure Partition is idle and set it to busy. */
193 sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
194
195 /* Set values for registers on SP entry */
196 cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
197
198 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
199 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
200 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
201 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
202
203 /* Jump to the Secure Partition. */
204 rc = spm_sp_synchronous_entry(sp_ptr);
205
206 /* Flag Secure Partition as idle. */
207 assert(sp_ptr->state == SP_STATE_BUSY);
208 sp_state_set(sp_ptr, SP_STATE_IDLE);
209
210 return rc;
211}
212
213/*******************************************************************************
214 * MM_COMMUNICATE handler
215 ******************************************************************************/
216static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
217 uint64_t comm_buffer_address,
218 uint64_t comm_size_address, void *handle)
219{
220 uint64_t rc;
221
222 /* Cookie. Reserved for future use. It must be zero. */
223 if (mm_cookie != 0U) {
224 ERROR("MM_COMMUNICATE: cookie is not zero\n");
Paul Beesleye9754e62019-10-15 12:51:55 +0000225 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000226 }
227
228 if (comm_buffer_address == 0U) {
229 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
Paul Beesleye9754e62019-10-15 12:51:55 +0000230 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000231 }
232
233 if (comm_size_address != 0U) {
234 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
235 }
236
237 /*
238 * The current secure partition design mandates
239 * - at any point, only a single core can be
240 * executing in the secure partiton.
241 * - a core cannot be preempted by an interrupt
242 * while executing in secure partition.
243 * Raise the running priority of the core to the
244 * interrupt level configured for secure partition
245 * so as to block any interrupt from preempting this
246 * core.
247 */
248 ehf_activate_priority(PLAT_SP_PRI);
249
250 /* Save the Normal world context */
251 cm_el1_sysregs_context_save(NON_SECURE);
252
Paul Beesleye9754e62019-10-15 12:51:55 +0000253 rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
254 plat_my_core_pos());
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000255
256 /* Restore non-secure state */
257 cm_el1_sysregs_context_restore(NON_SECURE);
258 cm_set_next_eret_context(NON_SECURE);
259
260 /*
261 * Exited from secure partition. This core can take
262 * interrupts now.
263 */
264 ehf_deactivate_priority(PLAT_SP_PRI);
265
266 SMC_RET1(handle, rc);
267}
268
269/*******************************************************************************
270 * Secure Partition Manager SMC handler.
271 ******************************************************************************/
Paul Beesleye9754e62019-10-15 12:51:55 +0000272uint64_t spm_mm_smc_handler(uint32_t smc_fid,
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000273 uint64_t x1,
274 uint64_t x2,
275 uint64_t x3,
276 uint64_t x4,
277 void *cookie,
278 void *handle,
279 uint64_t flags)
280{
281 unsigned int ns;
282
283 /* Determine which security state this SMC originated from */
284 ns = is_caller_non_secure(flags);
285
286 if (ns == SMC_FROM_SECURE) {
287
288 /* Handle SMCs from Secure world. */
289
290 assert(handle == cm_get_context(SECURE));
291
292 /* Make next ERET jump to S-EL0 instead of S-EL1. */
293 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
294
295 switch (smc_fid) {
296
Paul Beesleye9754e62019-10-15 12:51:55 +0000297 case SPM_MM_VERSION_AARCH32:
298 SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000299
Paul Beesleye9754e62019-10-15 12:51:55 +0000300 case MM_SP_EVENT_COMPLETE_AARCH64:
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000301 spm_sp_synchronous_exit(x1);
302
Paul Beesleye9754e62019-10-15 12:51:55 +0000303 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
304 INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000305
306 if (sp_ctx.state != SP_STATE_RESET) {
Paul Beesleye9754e62019-10-15 12:51:55 +0000307 WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
308 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000309 }
310 SMC_RET1(handle,
311 spm_memory_attributes_get_smc_handler(
312 &sp_ctx, x1));
313
Paul Beesleye9754e62019-10-15 12:51:55 +0000314 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
315 INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000316
317 if (sp_ctx.state != SP_STATE_RESET) {
Paul Beesleye9754e62019-10-15 12:51:55 +0000318 WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
319 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000320 }
321 SMC_RET1(handle,
322 spm_memory_attributes_set_smc_handler(
323 &sp_ctx, x1, x2, x3));
324 default:
325 break;
326 }
327 } else {
328
329 /* Handle SMCs from Non-secure world. */
330
331 assert(handle == cm_get_context(NON_SECURE));
332
333 switch (smc_fid) {
334
335 case MM_VERSION_AARCH32:
336 SMC_RET1(handle, MM_VERSION_COMPILED);
337
338 case MM_COMMUNICATE_AARCH32:
339 case MM_COMMUNICATE_AARCH64:
340 return mm_communicate(smc_fid, x1, x2, x3, handle);
341
Paul Beesleye9754e62019-10-15 12:51:55 +0000342 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
343 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000344 /* SMC interfaces reserved for secure callers. */
Paul Beesleye9754e62019-10-15 12:51:55 +0000345 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +0000346
347 default:
348 break;
349 }
350 }
351
352 SMC_RET1(handle, SMC_UNK);
353}