blob: 880e86e49603c23666ddafcb1b07ab7035c85826 [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>
9#include <bl31.h>
10#include <context_mgmt.h>
11#include <debug.h>
12#include <ehf.h>
13#include <errno.h>
14#include <mm_svc.h>
15#include <platform.h>
16#include <runtime_svc.h>
17#include <secure_partition.h>
18#include <smccc.h>
19#include <smccc_helpers.h>
20#include <spinlock.h>
21#include <spm_svc.h>
22#include <utils.h>
23#include <xlat_tables_v2.h>
24
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 ******************************************************************************/
88static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
89{
90 uint64_t rc;
91
92 assert(sp_ctx != NULL);
93
94 /* Assign the context of the SP to this CPU */
95 cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
96
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 */
106 rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
107
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
153 return rc;
154}
155
156/*******************************************************************************
157 * Initialize contexts of all Secure Partitions.
158 ******************************************************************************/
159int32_t spm_setup(void)
160{
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 ******************************************************************************/
187uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
188{
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");
225 SMC_RET1(handle, SPM_INVALID_PARAMETER);
226 }
227
228 if (comm_buffer_address == 0U) {
229 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
230 SMC_RET1(handle, SPM_INVALID_PARAMETER);
231 }
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
253 rc = spm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
254 plat_my_core_pos());
255
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 ******************************************************************************/
272uint64_t spm_smc_handler(uint32_t smc_fid,
273 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
297 case SPM_VERSION_AARCH32:
298 SMC_RET1(handle, SPM_VERSION_COMPILED);
299
300 case SP_EVENT_COMPLETE_AARCH64:
301 spm_sp_synchronous_exit(x1);
302
303 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
304 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
305
306 if (sp_ctx.state != SP_STATE_RESET) {
307 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
308 SMC_RET1(handle, SPM_NOT_SUPPORTED);
309 }
310 SMC_RET1(handle,
311 spm_memory_attributes_get_smc_handler(
312 &sp_ctx, x1));
313
314 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
315 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
316
317 if (sp_ctx.state != SP_STATE_RESET) {
318 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
319 SMC_RET1(handle, SPM_NOT_SUPPORTED);
320 }
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
342 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
343 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
344 /* SMC interfaces reserved for secure callers. */
345 SMC_RET1(handle, SPM_NOT_SUPPORTED);
346
347 default:
348 break;
349 }
350 }
351
352 SMC_RET1(handle, SMC_UNK);
353}