blob: e156106a7e21b28eea26e28327a46e24f9d95f43 [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 /*
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000128 * Arrange for an entry into the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100129 */
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000130 sp_ctx.sp_init_in_progress = 1;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100131 rc = spm_synchronous_sp_entry(&sp_ctx);
132 assert(rc == 0);
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000133 sp_ctx.sp_init_in_progress = 0;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000134 VERBOSE("SP_MEMORY_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100135
136 return rc;
137}
138
139/*******************************************************************************
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000140 * Given a secure partition entrypoint info pointer, entry point PC & pointer to
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100141 * a context data structure, this function will initialize the SPM context and
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000142 * entry point info for the secure partition.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100143 ******************************************************************************/
144void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
145 uint64_t pc,
146 secure_partition_context_t *sp_ctx_ptr)
147{
148 uint32_t ep_attr;
149
150 assert(sp_ep_info);
151 assert(pc);
152 assert(sp_ctx_ptr);
153
154 cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
155
156 /* initialise an entrypoint to set up the CPU context */
157 ep_attr = SECURE | EP_ST_ENABLE;
158 if (read_sctlr_el3() & SCTLR_EE_BIT)
159 ep_attr |= EP_EE_BIG;
160 SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
161
162 sp_ep_info->pc = pc;
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000163 /* The secure partition runs in S-EL0. */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100164 sp_ep_info->spsr = SPSR_64(MODE_EL0,
165 MODE_SP_EL0,
166 DISABLE_ALL_EXCEPTIONS);
167
168 zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
169}
170
171/*******************************************************************************
172 * Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
173 * already known and initialises the context for entry into the SP for its
174 * initialisation.
175 ******************************************************************************/
176int32_t spm_setup(void)
177{
178 entry_point_info_t *secure_partition_ep_info;
179
180 VERBOSE("%s entry\n", __func__);
181
182 /*
183 * Get information about the Secure Partition (BL32) image. Its
184 * absence is a critical failure.
185 */
186 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
187 if (!secure_partition_ep_info) {
188 WARN("No SPM provided by BL2 boot loader, Booting device"
189 " without SPM initialization. SMCs destined for SPM"
190 " will return SMC_UNK\n");
191 return 1;
192 }
193
194 /*
195 * If there's no valid entry point for SP, we return a non-zero value
196 * signalling failure initializing the service. We bail out without
197 * registering any handlers
198 */
199 if (!secure_partition_ep_info->pc) {
200 return 1;
201 }
202
203 spm_init_sp_ep_state(secure_partition_ep_info,
204 secure_partition_ep_info->pc,
205 &sp_ctx);
206
207 /*
208 * All SPM initialization done. Now register our init function with
209 * BL31 for deferred invocation
210 */
211 bl31_register_bl32_init(&spm_init);
212
213 VERBOSE("%s exit\n", __func__);
214
215 return 0;
216}
217
218/*
219 * Attributes are encoded using a different format in the SMC interface than in
220 * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
221 * converts an attributes value from the SMC format to the mmap_attr_t format by
222 * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
223 * The other fields are left as 0 because they are ignored by the function
224 * change_mem_attributes().
225 */
226static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
227{
228 mmap_attr_t tf_attr = 0;
229
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000230 unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
231 >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100232
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000233 if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100234 tf_attr |= MT_RW | MT_USER;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000235 } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100236 tf_attr |= MT_RO | MT_USER;
237 } else {
238 /* Other values are reserved. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000239 assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100240 /* The only requirement is that there's no access from EL0 */
241 tf_attr |= MT_RO | MT_PRIVILEGED;
242 }
243
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000244 if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100245 tf_attr |= MT_EXECUTE;
246 } else {
247 tf_attr |= MT_EXECUTE_NEVER;
248 }
249
250 return tf_attr;
251}
252
253/*
254 * This function converts attributes from the Trusted Firmware format into the
255 * SMC interface format.
256 */
257static int smc_mmap_to_smc_attr(mmap_attr_t attr)
258{
259 int smc_attr = 0;
260
261 int data_access;
262
263 if ((attr & MT_USER) == 0) {
264 /* No access from EL0. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000265 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100266 } else {
267 if ((attr & MT_RW) != 0) {
268 assert(MT_TYPE(attr) != MT_DEVICE);
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000269 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100270 } else {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000271 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100272 }
273 }
274
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000275 smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
276 << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100277
278 if (attr & MT_EXECUTE_NEVER) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000279 smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100280 }
281
282 return smc_attr;
283}
284
285static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
286{
287 spin_lock(&mem_attr_smc_lock);
288
289 mmap_attr_t attributes;
290 int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
291 base_va, &attributes);
292
293 spin_unlock(&mem_attr_smc_lock);
294
295 /* Convert error codes of get_mem_attributes() into SPM ones. */
296 assert(rc == 0 || rc == -EINVAL);
297
298 if (rc == 0) {
299 return smc_mmap_to_smc_attr(attributes);
300 } else {
301 return SPM_INVALID_PARAMETER;
302 }
303}
304
305static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
306 u_register_t pages_count,
307 u_register_t smc_attributes)
308{
309 uintptr_t base_va = (uintptr_t) page_address;
310 size_t size = (size_t) (pages_count * PAGE_SIZE);
311 unsigned int attributes = (unsigned int) smc_attributes;
312
313 INFO(" Start address : 0x%lx\n", base_va);
314 INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
315 INFO(" Attributes : 0x%x\n", attributes);
316
317 spin_lock(&mem_attr_smc_lock);
318
319 int ret = change_mem_attributes(secure_partition_xlat_ctx_handle,
320 base_va, size, smc_attr_to_mmap_attr(attributes));
321
322 spin_unlock(&mem_attr_smc_lock);
323
324 /* Convert error codes of change_mem_attributes() into SPM ones. */
325 assert(ret == 0 || ret == -EINVAL);
326
327 return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
328}
329
330
331uint64_t spm_smc_handler(uint32_t smc_fid,
332 uint64_t x1,
333 uint64_t x2,
334 uint64_t x3,
335 uint64_t x4,
336 void *cookie,
337 void *handle,
338 uint64_t flags)
339{
340 cpu_context_t *ns_cpu_context;
341 unsigned int ns;
342
343 /* Determine which security state this SMC originated from */
344 ns = is_caller_non_secure(flags);
345
346 if (ns == SMC_FROM_SECURE) {
347
348 /* Handle SMCs from Secure world. */
349
350 switch (smc_fid) {
351
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000352 case SPM_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100353 SMC_RET1(handle, SPM_VERSION_COMPILED);
354
355 case SP_EVENT_COMPLETE_AARCH64:
356 assert(handle == cm_get_context(SECURE));
357 cm_el1_sysregs_context_save(SECURE);
358 spm_setup_next_eret_into_sel0(handle);
359
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000360 if (sp_ctx.sp_init_in_progress) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100361 /*
362 * SPM reports completion. The SPM must have
363 * initiated the original request through a
364 * synchronous entry into the secure
365 * partition. Jump back to the original C
366 * runtime context.
367 */
368 spm_synchronous_sp_exit(&sp_ctx, x1);
369 assert(0);
370 }
371
372 /*
373 * This is the result from the Secure partition of an
374 * earlier request. Copy the result into the non-secure
375 * context, save the secure state and return to the
376 * non-secure state.
377 */
378
379 /* Get a reference to the non-secure context */
380 ns_cpu_context = cm_get_context(NON_SECURE);
381 assert(ns_cpu_context);
382
383 /* Restore non-secure state */
384 cm_el1_sysregs_context_restore(NON_SECURE);
385 cm_set_next_eret_context(NON_SECURE);
386
387 /* Return to normal world */
388 SMC_RET1(ns_cpu_context, x1);
389
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000390 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
391 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100392
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000393 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000394 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100395 SMC_RET1(handle, SPM_NOT_SUPPORTED);
396 }
397 SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
398
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000399 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
400 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100401
Antonio Nino Diazc58cb872017-12-18 10:51:58 +0000402 if (!sp_ctx.sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000403 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100404 SMC_RET1(handle, SPM_NOT_SUPPORTED);
405 }
406 SMC_RET1(handle, spm_memory_attributes_set_smc_handler(x1, x2, x3));
407 default:
408 break;
409 }
410 } else {
411
412 /* Handle SMCs from Non-secure world. */
413
414 switch (smc_fid) {
415
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000416 case SP_VERSION_AARCH64:
417 case SP_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100418 SMC_RET1(handle, SP_VERSION_COMPILED);
419
Sandrine Bailleuxb31ee6b2017-12-01 09:44:21 +0000420 case MM_COMMUNICATE_AARCH32:
421 case MM_COMMUNICATE_AARCH64:
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000422 {
423 uint64_t mm_cookie = x1;
424 uint64_t comm_buffer_address = x2;
425 uint64_t comm_size_address = x3;
426
427 /* Cookie. Reserved for future use. It must be zero. */
428 if (mm_cookie != 0) {
429 ERROR("MM_COMMUNICATE: cookie is not zero\n");
430 SMC_RET1(handle, SPM_INVALID_PARAMETER);
431 }
432
433 if (comm_buffer_address == 0) {
434 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
435 SMC_RET1(handle, SPM_INVALID_PARAMETER);
436 }
437
438 if (comm_size_address != 0) {
439 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
440 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100441
442 /* Save the Normal world context */
443 cm_el1_sysregs_context_save(NON_SECURE);
444
445 /*
446 * Restore the secure world context and prepare for
447 * entry in S-EL0
448 */
449 assert(&sp_ctx.cpu_ctx == cm_get_context(SECURE));
450 cm_el1_sysregs_context_restore(SECURE);
451 cm_set_next_eret_context(SECURE);
452
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000453 SMC_RET4(&sp_ctx.cpu_ctx, smc_fid, comm_buffer_address,
454 comm_size_address, plat_my_core_pos());
455 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100456
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000457 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
458 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100459 /* SMC interfaces reserved for secure callers. */
460 SMC_RET1(handle, SPM_NOT_SUPPORTED);
461
462 default:
463 break;
464 }
465 }
466
467 SMC_RET1(handle, SMC_UNK);
468}