blob: 7525763b181c00355e63d633b0689b2ec74ab45c [file] [log] [blame]
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +00001/*
2 * Copyright (c) 2017-2018, 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>
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>
21#include <services/mm_svc.h>
22#include <services/secure_partition.h>
23#include <services/spm_svc.h>
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000024#include <smccc_helpers.h>
Antonio Nino Diaz8cd7ea32018-10-30 11:08:08 +000025
26#include "spm_private.h"
27
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 ******************************************************************************/
89static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
90{
91 uint64_t rc;
92
93 assert(sp_ctx != NULL);
94
95 /* Assign the context of the SP to this CPU */
96 cm_set_context(&(sp_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(&sp_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 ******************************************************************************/
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 ******************************************************************************/
160int32_t spm_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 ******************************************************************************/
188uint64_t spm_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 /* Wait until the Secure Partition is idle and set it to busy. */
194 sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
195
196 /* Set values for registers on SP entry */
197 cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
198
199 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
200 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
201 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
202 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
203
204 /* Jump to the Secure Partition. */
205 rc = spm_sp_synchronous_entry(sp_ptr);
206
207 /* Flag Secure Partition as idle. */
208 assert(sp_ptr->state == SP_STATE_BUSY);
209 sp_state_set(sp_ptr, SP_STATE_IDLE);
210
211 return rc;
212}
213
214/*******************************************************************************
215 * MM_COMMUNICATE handler
216 ******************************************************************************/
217static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
218 uint64_t comm_buffer_address,
219 uint64_t comm_size_address, void *handle)
220{
221 uint64_t rc;
222
223 /* Cookie. Reserved for future use. It must be zero. */
224 if (mm_cookie != 0U) {
225 ERROR("MM_COMMUNICATE: cookie is not zero\n");
226 SMC_RET1(handle, SPM_INVALID_PARAMETER);
227 }
228
229 if (comm_buffer_address == 0U) {
230 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
231 SMC_RET1(handle, SPM_INVALID_PARAMETER);
232 }
233
234 if (comm_size_address != 0U) {
235 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
236 }
237
238 /*
239 * The current secure partition design mandates
240 * - at any point, only a single core can be
241 * executing in the secure partiton.
242 * - a core cannot be preempted by an interrupt
243 * while executing in secure partition.
244 * Raise the running priority of the core to the
245 * interrupt level configured for secure partition
246 * so as to block any interrupt from preempting this
247 * core.
248 */
249 ehf_activate_priority(PLAT_SP_PRI);
250
251 /* Save the Normal world context */
252 cm_el1_sysregs_context_save(NON_SECURE);
253
254 rc = spm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
255 plat_my_core_pos());
256
257 /* Restore non-secure state */
258 cm_el1_sysregs_context_restore(NON_SECURE);
259 cm_set_next_eret_context(NON_SECURE);
260
261 /*
262 * Exited from secure partition. This core can take
263 * interrupts now.
264 */
265 ehf_deactivate_priority(PLAT_SP_PRI);
266
267 SMC_RET1(handle, rc);
268}
269
270/*******************************************************************************
271 * Secure Partition Manager SMC handler.
272 ******************************************************************************/
273uint64_t spm_smc_handler(uint32_t smc_fid,
274 uint64_t x1,
275 uint64_t x2,
276 uint64_t x3,
277 uint64_t x4,
278 void *cookie,
279 void *handle,
280 uint64_t flags)
281{
282 unsigned int ns;
283
284 /* Determine which security state this SMC originated from */
285 ns = is_caller_non_secure(flags);
286
287 if (ns == SMC_FROM_SECURE) {
288
289 /* Handle SMCs from Secure world. */
290
291 assert(handle == cm_get_context(SECURE));
292
293 /* Make next ERET jump to S-EL0 instead of S-EL1. */
294 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
295
296 switch (smc_fid) {
297
298 case SPM_VERSION_AARCH32:
299 SMC_RET1(handle, SPM_VERSION_COMPILED);
300
301 case SP_EVENT_COMPLETE_AARCH64:
302 spm_sp_synchronous_exit(x1);
303
304 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
305 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
306
307 if (sp_ctx.state != SP_STATE_RESET) {
308 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
309 SMC_RET1(handle, SPM_NOT_SUPPORTED);
310 }
311 SMC_RET1(handle,
312 spm_memory_attributes_get_smc_handler(
313 &sp_ctx, x1));
314
315 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
316 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
317
318 if (sp_ctx.state != SP_STATE_RESET) {
319 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
320 SMC_RET1(handle, SPM_NOT_SUPPORTED);
321 }
322 SMC_RET1(handle,
323 spm_memory_attributes_set_smc_handler(
324 &sp_ctx, x1, x2, x3));
325 default:
326 break;
327 }
328 } else {
329
330 /* Handle SMCs from Non-secure world. */
331
332 assert(handle == cm_get_context(NON_SECURE));
333
334 switch (smc_fid) {
335
336 case MM_VERSION_AARCH32:
337 SMC_RET1(handle, MM_VERSION_COMPILED);
338
339 case MM_COMMUNICATE_AARCH32:
340 case MM_COMMUNICATE_AARCH64:
341 return mm_communicate(smc_fid, x1, x2, x3, handle);
342
343 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
344 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
345 /* SMC interfaces reserved for secure callers. */
346 SMC_RET1(handle, SPM_NOT_SUPPORTED);
347
348 default:
349 break;
350 }
351 }
352
353 SMC_RET1(handle, SMC_UNK);
354}