1 /*
2 * Copyright (c) 2017-2019, 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_mm_private.h"
26
27 /*******************************************************************************
28 * Secure Partition context information.
29 ******************************************************************************/
30 static sp_context_t sp_ctx;
31
32 /*******************************************************************************
33 * Set state of a Secure Partition context.
34 ******************************************************************************/
sp_state_set(sp_context_t * sp_ptr,sp_state_t state)35 void 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 ******************************************************************************/
sp_state_wait_switch(sp_context_t * sp_ptr,sp_state_t from,sp_state_t to)46 void 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 ******************************************************************************/
sp_state_try_switch(sp_context_t * sp_ptr,sp_state_t from,sp_state_t to)67 int 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 ******************************************************************************/
spm_sp_synchronous_entry(sp_context_t * ctx)88 static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
89 {
90 uint64_t rc;
91
92 assert(ctx != NULL);
93
94 /* Assign the context of the SP to this CPU */
95 cm_set_context(&(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(&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 ******************************************************************************/
spm_sp_synchronous_exit(uint64_t rc)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 ******************************************************************************/
spm_init(void)135 static 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 ******************************************************************************/
spm_mm_setup(void)159 int32_t spm_mm_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 ******************************************************************************/
spm_mm_sp_call(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3)187 uint64_t spm_mm_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 ******************************************************************************/
mm_communicate(uint32_t smc_fid,uint64_t mm_cookie,uint64_t comm_buffer_address,uint64_t comm_size_address,void * handle)216 static 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_MM_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_MM_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_mm_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 ******************************************************************************/
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)272 uint64_t spm_mm_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_MM_VERSION_AARCH32:
298 SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
299
300 case MM_SP_EVENT_COMPLETE_AARCH64:
301 spm_sp_synchronous_exit(x1);
302
303 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
304 INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
305
306 if (sp_ctx.state != SP_STATE_RESET) {
307 WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
308 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
309 }
310 SMC_RET1(handle,
311 spm_memory_attributes_get_smc_handler(
312 &sp_ctx, x1));
313
314 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
315 INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
316
317 if (sp_ctx.state != SP_STATE_RESET) {
318 WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
319 SMC_RET1(handle, SPM_MM_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 MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
343 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
344 /* SMC interfaces reserved for secure callers. */
345 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
346
347 default:
348 break;
349 }
350 }
351
352 SMC_RET1(handle, SMC_UNK);
353 }
354