blob: 979b9a8f04c828b7720b910c9b1b4ce2a0314289 [file] [log] [blame]
Antonio Nino Diazc41f2062017-10-24 10:07:35 +01001/*
2 * Copyright (c) 2017, 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 <errno.h>
13#include <platform.h>
14#include <runtime_svc.h>
15#include <secure_partition.h>
16#include <smcc.h>
17#include <smcc_helpers.h>
18#include <spinlock.h>
19#include <spm_svc.h>
20#include <utils.h>
21#include <xlat_tables_v2.h>
22
23#include "spm_private.h"
24
25/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
26static spinlock_t mem_attr_smc_lock;
27
28/*******************************************************************************
29 * Secure Partition context information.
30 ******************************************************************************/
31static secure_partition_context_t sp_ctx;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010032
33/*******************************************************************************
34 * Replace the S-EL1 re-entry information with S-EL0 re-entry
35 * information
36 ******************************************************************************/
37void spm_setup_next_eret_into_sel0(cpu_context_t *secure_context)
38{
39 assert(secure_context == cm_get_context(SECURE));
40
41 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
42}
43
44/*******************************************************************************
45 * This function takes an SP context pointer and:
46 * 1. Applies the S-EL1 system register context from sp_ctx->cpu_ctx.
47 * 2. Saves the current C runtime state (callee-saved registers) on the stack
48 * frame and saves a reference to this state.
49 * 3. Calls el3_exit() so that the EL3 system and general purpose registers
Sandrine Bailleux843d3f02017-12-07 09:48:56 +000050 * from the sp_ctx->cpu_ctx are used to enter the secure partition image.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010051 ******************************************************************************/
52static uint64_t spm_synchronous_sp_entry(secure_partition_context_t *sp_ctx_ptr)
53{
54 uint64_t rc;
55
56 assert(sp_ctx_ptr != NULL);
57 assert(sp_ctx_ptr->c_rt_ctx == 0);
58 assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
59
60 /* Apply the Secure EL1 system register context and switch to it */
61 cm_el1_sysregs_context_restore(SECURE);
62 cm_set_next_eret_context(SECURE);
63
64 VERBOSE("%s: We're about to enter the Secure partition...\n", __func__);
65
66 rc = spm_secure_partition_enter(&sp_ctx_ptr->c_rt_ctx);
67#if ENABLE_ASSERTIONS
68 sp_ctx_ptr->c_rt_ctx = 0;
69#endif
70
71 return rc;
72}
73
74
75/*******************************************************************************
76 * This function takes a Secure partition context pointer and:
Sandrine Bailleux843d3f02017-12-07 09:48:56 +000077 * 1. Saves the S-EL1 system register context to sp_ctx->cpu_ctx.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010078 * 2. Restores the current C runtime state (callee saved registers) from the
79 * stack frame using the reference to this state saved in
80 * spm_secure_partition_enter().
81 * 3. It does not need to save any general purpose or EL3 system register state
82 * as the generic smc entry routine should have saved those.
83 ******************************************************************************/
84static void __dead2 spm_synchronous_sp_exit(
85 secure_partition_context_t *sp_ctx_ptr, uint64_t ret)
86{
87 assert(sp_ctx_ptr != NULL);
88 /* Save the Secure EL1 system register context */
89 assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
90 cm_el1_sysregs_context_save(SECURE);
91
92 assert(sp_ctx_ptr->c_rt_ctx != 0);
93 spm_secure_partition_exit(sp_ctx_ptr->c_rt_ctx, ret);
94
95 /* Should never reach here */
96 assert(0);
97}
98
99/*******************************************************************************
100 * This function passes control to the Secure Partition image (BL32) for the
101 * first time on the primary cpu after a cold boot. It assumes that a valid
102 * secure context has already been created by spm_setup() which can be directly
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000103 * used. This function performs a synchronous entry into the Secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100104 * The SP passes control back to this routine through a SMC.
105 ******************************************************************************/
106int32_t spm_init(void)
107{
108 entry_point_info_t *secure_partition_ep_info;
109 uint64_t rc;
110
111 VERBOSE("%s entry\n", __func__);
112
113 /*
114 * Get information about the Secure Partition (BL32) image. Its
115 * absence is a critical failure.
116 */
117 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
118 assert(secure_partition_ep_info);
119
120 /*
121 * Initialise the common context and then overlay the S-EL0 specific
122 * context on top of it.
123 */
124 cm_init_my_context(secure_partition_ep_info);
125 secure_partition_setup();
126
127 /*
Antonio Nino Diaz496f54d2018-01-08 09:59:33 +0000128 * Make all CPUs use the same secure context.
129 */
130 for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
131 cm_set_context_by_index(i, &sp_ctx.cpu_ctx, SECURE);
132 }
133
134 /*
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000135 * Arrange for an entry into the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100136 */
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000137 sp_ctx.sp_init_in_progress = 1;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100138 rc = spm_synchronous_sp_entry(&sp_ctx);
139 assert(rc == 0);
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000140 sp_ctx.sp_init_in_progress = 0;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000141 VERBOSE("SP_MEMORY_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100142
143 return rc;
144}
145
146/*******************************************************************************
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000147 * Given a secure partition entrypoint info pointer, entry point PC & pointer to
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100148 * a context data structure, this function will initialize the SPM context and
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000149 * entry point info for the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100150 ******************************************************************************/
151void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
152 uint64_t pc,
153 secure_partition_context_t *sp_ctx_ptr)
154{
155 uint32_t ep_attr;
156
157 assert(sp_ep_info);
158 assert(pc);
159 assert(sp_ctx_ptr);
160
161 cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
162
163 /* initialise an entrypoint to set up the CPU context */
164 ep_attr = SECURE | EP_ST_ENABLE;
165 if (read_sctlr_el3() & SCTLR_EE_BIT)
166 ep_attr |= EP_EE_BIG;
167 SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
168
169 sp_ep_info->pc = pc;
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000170 /* The secure partition runs in S-EL0. */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100171 sp_ep_info->spsr = SPSR_64(MODE_EL0,
172 MODE_SP_EL0,
173 DISABLE_ALL_EXCEPTIONS);
174
175 zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
176}
177
178/*******************************************************************************
179 * Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
180 * already known and initialises the context for entry into the SP for its
181 * initialisation.
182 ******************************************************************************/
183int32_t spm_setup(void)
184{
185 entry_point_info_t *secure_partition_ep_info;
186
187 VERBOSE("%s entry\n", __func__);
188
189 /*
190 * Get information about the Secure Partition (BL32) image. Its
191 * absence is a critical failure.
192 */
193 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
194 if (!secure_partition_ep_info) {
195 WARN("No SPM provided by BL2 boot loader, Booting device"
196 " without SPM initialization. SMCs destined for SPM"
197 " will return SMC_UNK\n");
198 return 1;
199 }
200
201 /*
202 * If there's no valid entry point for SP, we return a non-zero value
203 * signalling failure initializing the service. We bail out without
204 * registering any handlers
205 */
206 if (!secure_partition_ep_info->pc) {
207 return 1;
208 }
209
210 spm_init_sp_ep_state(secure_partition_ep_info,
211 secure_partition_ep_info->pc,
212 &sp_ctx);
213
214 /*
215 * All SPM initialization done. Now register our init function with
216 * BL31 for deferred invocation
217 */
218 bl31_register_bl32_init(&spm_init);
219
220 VERBOSE("%s exit\n", __func__);
221
222 return 0;
223}
224
225/*
226 * Attributes are encoded using a different format in the SMC interface than in
227 * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
228 * converts an attributes value from the SMC format to the mmap_attr_t format by
229 * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
230 * The other fields are left as 0 because they are ignored by the function
231 * change_mem_attributes().
232 */
233static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
234{
235 mmap_attr_t tf_attr = 0;
236
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000237 unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
238 >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100239
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000240 if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100241 tf_attr |= MT_RW | MT_USER;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000242 } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100243 tf_attr |= MT_RO | MT_USER;
244 } else {
245 /* Other values are reserved. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000246 assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100247 /* The only requirement is that there's no access from EL0 */
248 tf_attr |= MT_RO | MT_PRIVILEGED;
249 }
250
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000251 if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100252 tf_attr |= MT_EXECUTE;
253 } else {
254 tf_attr |= MT_EXECUTE_NEVER;
255 }
256
257 return tf_attr;
258}
259
260/*
261 * This function converts attributes from the Trusted Firmware format into the
262 * SMC interface format.
263 */
264static int smc_mmap_to_smc_attr(mmap_attr_t attr)
265{
266 int smc_attr = 0;
267
268 int data_access;
269
270 if ((attr & MT_USER) == 0) {
271 /* No access from EL0. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000272 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100273 } else {
274 if ((attr & MT_RW) != 0) {
275 assert(MT_TYPE(attr) != MT_DEVICE);
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000276 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100277 } else {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000278 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100279 }
280 }
281
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000282 smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
283 << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100284
285 if (attr & MT_EXECUTE_NEVER) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000286 smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100287 }
288
289 return smc_attr;
290}
291
292static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
293{
294 spin_lock(&mem_attr_smc_lock);
295
296 mmap_attr_t attributes;
297 int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
298 base_va, &attributes);
299
300 spin_unlock(&mem_attr_smc_lock);
301
302 /* Convert error codes of get_mem_attributes() into SPM ones. */
303 assert(rc == 0 || rc == -EINVAL);
304
305 if (rc == 0) {
306 return smc_mmap_to_smc_attr(attributes);
307 } else {
308 return SPM_INVALID_PARAMETER;
309 }
310}
311
312static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
313 u_register_t pages_count,
314 u_register_t smc_attributes)
315{
316 uintptr_t base_va = (uintptr_t) page_address;
317 size_t size = (size_t) (pages_count * PAGE_SIZE);
318 unsigned int attributes = (unsigned int) smc_attributes;
319
320 INFO(" Start address : 0x%lx\n", base_va);
321 INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
322 INFO(" Attributes : 0x%x\n", attributes);
323
324 spin_lock(&mem_attr_smc_lock);
325
326 int ret = change_mem_attributes(secure_partition_xlat_ctx_handle,
327 base_va, size, smc_attr_to_mmap_attr(attributes));
328
329 spin_unlock(&mem_attr_smc_lock);
330
331 /* Convert error codes of change_mem_attributes() into SPM ones. */
332 assert(ret == 0 || ret == -EINVAL);
333
334 return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
335}
336
337
338uint64_t spm_smc_handler(uint32_t smc_fid,
339 uint64_t x1,
340 uint64_t x2,
341 uint64_t x3,
342 uint64_t x4,
343 void *cookie,
344 void *handle,
345 uint64_t flags)
346{
347 cpu_context_t *ns_cpu_context;
348 unsigned int ns;
349
350 /* Determine which security state this SMC originated from */
351 ns = is_caller_non_secure(flags);
352
353 if (ns == SMC_FROM_SECURE) {
354
355 /* Handle SMCs from Secure world. */
356
357 switch (smc_fid) {
358
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000359 case SPM_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100360 SMC_RET1(handle, SPM_VERSION_COMPILED);
361
362 case SP_EVENT_COMPLETE_AARCH64:
363 assert(handle == cm_get_context(SECURE));
364 cm_el1_sysregs_context_save(SECURE);
365 spm_setup_next_eret_into_sel0(handle);
366
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000367 if (sp_ctx.sp_init_in_progress) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100368 /*
369 * SPM reports completion. The SPM must have
370 * initiated the original request through a
371 * synchronous entry into the secure
372 * partition. Jump back to the original C
373 * runtime context.
374 */
375 spm_synchronous_sp_exit(&sp_ctx, x1);
376 assert(0);
377 }
378
Antonio Nino Diaz496f54d2018-01-08 09:59:33 +0000379 /* Release the Secure Partition context */
380 spin_unlock(&sp_ctx.lock);
381
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100382 /*
383 * This is the result from the Secure partition of an
384 * earlier request. Copy the result into the non-secure
385 * context, save the secure state and return to the
386 * non-secure state.
387 */
388
389 /* Get a reference to the non-secure context */
390 ns_cpu_context = cm_get_context(NON_SECURE);
391 assert(ns_cpu_context);
392
393 /* Restore non-secure state */
394 cm_el1_sysregs_context_restore(NON_SECURE);
395 cm_set_next_eret_context(NON_SECURE);
396
397 /* Return to normal world */
398 SMC_RET1(ns_cpu_context, x1);
399
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000400 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
401 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100402
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000403 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000404 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100405 SMC_RET1(handle, SPM_NOT_SUPPORTED);
406 }
407 SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
408
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000409 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
410 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100411
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000412 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000413 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100414 SMC_RET1(handle, SPM_NOT_SUPPORTED);
415 }
416 SMC_RET1(handle, spm_memory_attributes_set_smc_handler(x1, x2, x3));
417 default:
418 break;
419 }
420 } else {
421
422 /* Handle SMCs from Non-secure world. */
423
424 switch (smc_fid) {
425
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000426 case SP_VERSION_AARCH64:
427 case SP_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100428 SMC_RET1(handle, SP_VERSION_COMPILED);
429
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}