blob: d31fad67edd8f29281fa029c5ffa04f679d6aadf [file] [log] [blame]
Antonio Nino Diazc41f2062017-10-24 10:07:35 +01001/*
Antonio Nino Diaz35b37f02018-01-08 17:33:34 +00002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +01003 *
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 <errno.h>
Antonio Nino Diaz35b37f02018-01-08 17:33:34 +000013#include <mm_svc.h>
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010014#include <platform.h>
15#include <runtime_svc.h>
16#include <secure_partition.h>
17#include <smcc.h>
18#include <smcc_helpers.h>
19#include <spinlock.h>
20#include <spm_svc.h>
21#include <utils.h>
22#include <xlat_tables_v2.h>
23
24#include "spm_private.h"
25
26/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
27static spinlock_t mem_attr_smc_lock;
28
29/*******************************************************************************
30 * Secure Partition context information.
31 ******************************************************************************/
32static secure_partition_context_t sp_ctx;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010033
34/*******************************************************************************
35 * Replace the S-EL1 re-entry information with S-EL0 re-entry
36 * information
37 ******************************************************************************/
38void spm_setup_next_eret_into_sel0(cpu_context_t *secure_context)
39{
40 assert(secure_context == cm_get_context(SECURE));
41
42 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
43}
44
45/*******************************************************************************
46 * This function takes an SP context pointer and:
47 * 1. Applies the S-EL1 system register context from sp_ctx->cpu_ctx.
48 * 2. Saves the current C runtime state (callee-saved registers) on the stack
49 * frame and saves a reference to this state.
50 * 3. Calls el3_exit() so that the EL3 system and general purpose registers
Sandrine Bailleux843d3f02017-12-07 09:48:56 +000051 * from the sp_ctx->cpu_ctx are used to enter the secure partition image.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010052 ******************************************************************************/
53static uint64_t spm_synchronous_sp_entry(secure_partition_context_t *sp_ctx_ptr)
54{
55 uint64_t rc;
56
57 assert(sp_ctx_ptr != NULL);
58 assert(sp_ctx_ptr->c_rt_ctx == 0);
59 assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
60
61 /* Apply the Secure EL1 system register context and switch to it */
62 cm_el1_sysregs_context_restore(SECURE);
63 cm_set_next_eret_context(SECURE);
64
65 VERBOSE("%s: We're about to enter the Secure partition...\n", __func__);
66
67 rc = spm_secure_partition_enter(&sp_ctx_ptr->c_rt_ctx);
68#if ENABLE_ASSERTIONS
69 sp_ctx_ptr->c_rt_ctx = 0;
70#endif
71
72 return rc;
73}
74
75
76/*******************************************************************************
77 * This function takes a Secure partition context pointer and:
Sandrine Bailleux843d3f02017-12-07 09:48:56 +000078 * 1. Saves the S-EL1 system register context to sp_ctx->cpu_ctx.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010079 * 2. Restores the current C runtime state (callee saved registers) from the
80 * stack frame using the reference to this state saved in
81 * spm_secure_partition_enter().
82 * 3. It does not need to save any general purpose or EL3 system register state
83 * as the generic smc entry routine should have saved those.
84 ******************************************************************************/
85static void __dead2 spm_synchronous_sp_exit(
86 secure_partition_context_t *sp_ctx_ptr, uint64_t ret)
87{
88 assert(sp_ctx_ptr != NULL);
89 /* Save the Secure EL1 system register context */
90 assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
91 cm_el1_sysregs_context_save(SECURE);
92
93 assert(sp_ctx_ptr->c_rt_ctx != 0);
94 spm_secure_partition_exit(sp_ctx_ptr->c_rt_ctx, ret);
95
96 /* Should never reach here */
97 assert(0);
98}
99
100/*******************************************************************************
101 * This function passes control to the Secure Partition image (BL32) for the
102 * first time on the primary cpu after a cold boot. It assumes that a valid
103 * secure context has already been created by spm_setup() which can be directly
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000104 * used. This function performs a synchronous entry into the Secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100105 * The SP passes control back to this routine through a SMC.
106 ******************************************************************************/
107int32_t spm_init(void)
108{
109 entry_point_info_t *secure_partition_ep_info;
110 uint64_t rc;
111
112 VERBOSE("%s entry\n", __func__);
113
114 /*
115 * Get information about the Secure Partition (BL32) image. Its
116 * absence is a critical failure.
117 */
118 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
119 assert(secure_partition_ep_info);
120
121 /*
122 * Initialise the common context and then overlay the S-EL0 specific
123 * context on top of it.
124 */
125 cm_init_my_context(secure_partition_ep_info);
126 secure_partition_setup();
127
128 /*
Antonio Nino Diaz496f54d2018-01-08 09:59:33 +0000129 * Make all CPUs use the same secure context.
130 */
131 for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
132 cm_set_context_by_index(i, &sp_ctx.cpu_ctx, SECURE);
133 }
134
135 /*
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000136 * Arrange for an entry into the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100137 */
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000138 sp_ctx.sp_init_in_progress = 1;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100139 rc = spm_synchronous_sp_entry(&sp_ctx);
140 assert(rc == 0);
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000141 sp_ctx.sp_init_in_progress = 0;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000142 VERBOSE("SP_MEMORY_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100143
144 return rc;
145}
146
147/*******************************************************************************
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000148 * Given a secure partition entrypoint info pointer, entry point PC & pointer to
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100149 * a context data structure, this function will initialize the SPM context and
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000150 * entry point info for the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100151 ******************************************************************************/
152void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
153 uint64_t pc,
154 secure_partition_context_t *sp_ctx_ptr)
155{
156 uint32_t ep_attr;
157
158 assert(sp_ep_info);
159 assert(pc);
160 assert(sp_ctx_ptr);
161
162 cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
163
164 /* initialise an entrypoint to set up the CPU context */
165 ep_attr = SECURE | EP_ST_ENABLE;
166 if (read_sctlr_el3() & SCTLR_EE_BIT)
167 ep_attr |= EP_EE_BIG;
168 SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
169
170 sp_ep_info->pc = pc;
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000171 /* The secure partition runs in S-EL0. */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100172 sp_ep_info->spsr = SPSR_64(MODE_EL0,
173 MODE_SP_EL0,
174 DISABLE_ALL_EXCEPTIONS);
175
176 zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
177}
178
179/*******************************************************************************
180 * Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
181 * already known and initialises the context for entry into the SP for its
182 * initialisation.
183 ******************************************************************************/
184int32_t spm_setup(void)
185{
186 entry_point_info_t *secure_partition_ep_info;
187
188 VERBOSE("%s entry\n", __func__);
189
190 /*
191 * Get information about the Secure Partition (BL32) image. Its
192 * absence is a critical failure.
193 */
194 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
195 if (!secure_partition_ep_info) {
196 WARN("No SPM provided by BL2 boot loader, Booting device"
197 " without SPM initialization. SMCs destined for SPM"
198 " will return SMC_UNK\n");
199 return 1;
200 }
201
202 /*
203 * If there's no valid entry point for SP, we return a non-zero value
204 * signalling failure initializing the service. We bail out without
205 * registering any handlers
206 */
207 if (!secure_partition_ep_info->pc) {
208 return 1;
209 }
210
211 spm_init_sp_ep_state(secure_partition_ep_info,
212 secure_partition_ep_info->pc,
213 &sp_ctx);
214
215 /*
216 * All SPM initialization done. Now register our init function with
217 * BL31 for deferred invocation
218 */
219 bl31_register_bl32_init(&spm_init);
220
221 VERBOSE("%s exit\n", __func__);
222
223 return 0;
224}
225
226/*
227 * Attributes are encoded using a different format in the SMC interface than in
228 * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
229 * converts an attributes value from the SMC format to the mmap_attr_t format by
230 * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
231 * The other fields are left as 0 because they are ignored by the function
232 * change_mem_attributes().
233 */
234static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
235{
236 mmap_attr_t tf_attr = 0;
237
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000238 unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
239 >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100240
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000241 if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100242 tf_attr |= MT_RW | MT_USER;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000243 } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100244 tf_attr |= MT_RO | MT_USER;
245 } else {
246 /* Other values are reserved. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000247 assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100248 /* The only requirement is that there's no access from EL0 */
249 tf_attr |= MT_RO | MT_PRIVILEGED;
250 }
251
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000252 if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100253 tf_attr |= MT_EXECUTE;
254 } else {
255 tf_attr |= MT_EXECUTE_NEVER;
256 }
257
258 return tf_attr;
259}
260
261/*
262 * This function converts attributes from the Trusted Firmware format into the
263 * SMC interface format.
264 */
265static int smc_mmap_to_smc_attr(mmap_attr_t attr)
266{
267 int smc_attr = 0;
268
269 int data_access;
270
271 if ((attr & MT_USER) == 0) {
272 /* No access from EL0. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000273 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100274 } else {
275 if ((attr & MT_RW) != 0) {
276 assert(MT_TYPE(attr) != MT_DEVICE);
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000277 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100278 } else {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000279 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100280 }
281 }
282
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000283 smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
284 << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100285
286 if (attr & MT_EXECUTE_NEVER) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000287 smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100288 }
289
290 return smc_attr;
291}
292
293static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
294{
295 spin_lock(&mem_attr_smc_lock);
296
297 mmap_attr_t attributes;
298 int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
299 base_va, &attributes);
300
301 spin_unlock(&mem_attr_smc_lock);
302
303 /* Convert error codes of get_mem_attributes() into SPM ones. */
304 assert(rc == 0 || rc == -EINVAL);
305
306 if (rc == 0) {
307 return smc_mmap_to_smc_attr(attributes);
308 } else {
309 return SPM_INVALID_PARAMETER;
310 }
311}
312
313static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
314 u_register_t pages_count,
315 u_register_t smc_attributes)
316{
317 uintptr_t base_va = (uintptr_t) page_address;
318 size_t size = (size_t) (pages_count * PAGE_SIZE);
319 unsigned int attributes = (unsigned int) smc_attributes;
320
321 INFO(" Start address : 0x%lx\n", base_va);
322 INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
323 INFO(" Attributes : 0x%x\n", attributes);
324
325 spin_lock(&mem_attr_smc_lock);
326
327 int ret = change_mem_attributes(secure_partition_xlat_ctx_handle,
328 base_va, size, smc_attr_to_mmap_attr(attributes));
329
330 spin_unlock(&mem_attr_smc_lock);
331
332 /* Convert error codes of change_mem_attributes() into SPM ones. */
333 assert(ret == 0 || ret == -EINVAL);
334
335 return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
336}
337
338
339uint64_t spm_smc_handler(uint32_t smc_fid,
340 uint64_t x1,
341 uint64_t x2,
342 uint64_t x3,
343 uint64_t x4,
344 void *cookie,
345 void *handle,
346 uint64_t flags)
347{
348 cpu_context_t *ns_cpu_context;
349 unsigned int ns;
350
351 /* Determine which security state this SMC originated from */
352 ns = is_caller_non_secure(flags);
353
354 if (ns == SMC_FROM_SECURE) {
355
356 /* Handle SMCs from Secure world. */
357
358 switch (smc_fid) {
359
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000360 case SPM_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100361 SMC_RET1(handle, SPM_VERSION_COMPILED);
362
363 case SP_EVENT_COMPLETE_AARCH64:
364 assert(handle == cm_get_context(SECURE));
365 cm_el1_sysregs_context_save(SECURE);
366 spm_setup_next_eret_into_sel0(handle);
367
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000368 if (sp_ctx.sp_init_in_progress) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100369 /*
370 * SPM reports completion. The SPM must have
371 * initiated the original request through a
372 * synchronous entry into the secure
373 * partition. Jump back to the original C
374 * runtime context.
375 */
376 spm_synchronous_sp_exit(&sp_ctx, x1);
377 assert(0);
378 }
379
Antonio Nino Diaz496f54d2018-01-08 09:59:33 +0000380 /* Release the Secure Partition context */
381 spin_unlock(&sp_ctx.lock);
382
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100383 /*
384 * This is the result from the Secure partition of an
385 * earlier request. Copy the result into the non-secure
386 * context, save the secure state and return to the
387 * non-secure state.
388 */
389
390 /* Get a reference to the non-secure context */
391 ns_cpu_context = cm_get_context(NON_SECURE);
392 assert(ns_cpu_context);
393
394 /* Restore non-secure state */
395 cm_el1_sysregs_context_restore(NON_SECURE);
396 cm_set_next_eret_context(NON_SECURE);
397
398 /* Return to normal world */
399 SMC_RET1(ns_cpu_context, x1);
400
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000401 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
402 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100403
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000404 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000405 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100406 SMC_RET1(handle, SPM_NOT_SUPPORTED);
407 }
408 SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
409
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000410 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
411 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100412
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000413 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000414 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100415 SMC_RET1(handle, SPM_NOT_SUPPORTED);
416 }
417 SMC_RET1(handle, spm_memory_attributes_set_smc_handler(x1, x2, x3));
418 default:
419 break;
420 }
421 } else {
422
423 /* Handle SMCs from Non-secure world. */
424
425 switch (smc_fid) {
426
Antonio Nino Diaz35b37f02018-01-08 17:33:34 +0000427 case MM_VERSION_AARCH32:
428 SMC_RET1(handle, MM_VERSION_COMPILED);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100429
Sandrine Bailleuxb31ee6b2017-12-01 09:44:21 +0000430 case MM_COMMUNICATE_AARCH32:
431 case MM_COMMUNICATE_AARCH64:
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000432 {
433 uint64_t mm_cookie = x1;
434 uint64_t comm_buffer_address = x2;
435 uint64_t comm_size_address = x3;
436
437 /* Cookie. Reserved for future use. It must be zero. */
438 if (mm_cookie != 0) {
439 ERROR("MM_COMMUNICATE: cookie is not zero\n");
440 SMC_RET1(handle, SPM_INVALID_PARAMETER);
441 }
442
443 if (comm_buffer_address == 0) {
444 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
445 SMC_RET1(handle, SPM_INVALID_PARAMETER);
446 }
447
448 if (comm_size_address != 0) {
449 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
450 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100451
452 /* Save the Normal world context */
453 cm_el1_sysregs_context_save(NON_SECURE);
454
Antonio Nino Diaz496f54d2018-01-08 09:59:33 +0000455 /* Lock the Secure Partition context. */
456 spin_lock(&sp_ctx.lock);
457
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100458 /*
459 * Restore the secure world context and prepare for
460 * entry in S-EL0
461 */
462 assert(&sp_ctx.cpu_ctx == cm_get_context(SECURE));
463 cm_el1_sysregs_context_restore(SECURE);
464 cm_set_next_eret_context(SECURE);
465
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000466 SMC_RET4(&sp_ctx.cpu_ctx, smc_fid, comm_buffer_address,
467 comm_size_address, plat_my_core_pos());
468 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100469
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000470 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
471 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100472 /* SMC interfaces reserved for secure callers. */
473 SMC_RET1(handle, SPM_NOT_SUPPORTED);
474
475 default:
476 break;
477 }
478 }
479
480 SMC_RET1(handle, SMC_UNK);
481}