blob: 00f3a30c37b3c7b9231394d45ff14e58fe1d4dc5 [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;
32unsigned int sp_init_in_progress;
33
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
51 * from the sp_ctx->cpu_ctx are used to enter the secure payload image.
52 ******************************************************************************/
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:
78 * 1. Saves the S-EL1 system register context tp sp_ctx->cpu_ctx.
79 * 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
104 * used. This function performs a synchronous entry into the Secure payload.
105 * 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 /*
129 * Arrange for an entry into the secure payload.
130 */
131 sp_init_in_progress = 1;
132 rc = spm_synchronous_sp_entry(&sp_ctx);
133 assert(rc == 0);
134 sp_init_in_progress = 0;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000135 VERBOSE("SP_MEMORY_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100136
137 return rc;
138}
139
140/*******************************************************************************
141 * Given a secure payload entrypoint info pointer, entry point PC & pointer to
142 * a context data structure, this function will initialize the SPM context and
143 * entry point info for the secure payload
144 ******************************************************************************/
145void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
146 uint64_t pc,
147 secure_partition_context_t *sp_ctx_ptr)
148{
149 uint32_t ep_attr;
150
151 assert(sp_ep_info);
152 assert(pc);
153 assert(sp_ctx_ptr);
154
155 cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
156
157 /* initialise an entrypoint to set up the CPU context */
158 ep_attr = SECURE | EP_ST_ENABLE;
159 if (read_sctlr_el3() & SCTLR_EE_BIT)
160 ep_attr |= EP_EE_BIG;
161 SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
162
163 sp_ep_info->pc = pc;
164 /* The SPM payload runs in S-EL0 */
165 sp_ep_info->spsr = SPSR_64(MODE_EL0,
166 MODE_SP_EL0,
167 DISABLE_ALL_EXCEPTIONS);
168
169 zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
170}
171
172/*******************************************************************************
173 * Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
174 * already known and initialises the context for entry into the SP for its
175 * initialisation.
176 ******************************************************************************/
177int32_t spm_setup(void)
178{
179 entry_point_info_t *secure_partition_ep_info;
180
181 VERBOSE("%s entry\n", __func__);
182
183 /*
184 * Get information about the Secure Partition (BL32) image. Its
185 * absence is a critical failure.
186 */
187 secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
188 if (!secure_partition_ep_info) {
189 WARN("No SPM provided by BL2 boot loader, Booting device"
190 " without SPM initialization. SMCs destined for SPM"
191 " will return SMC_UNK\n");
192 return 1;
193 }
194
195 /*
196 * If there's no valid entry point for SP, we return a non-zero value
197 * signalling failure initializing the service. We bail out without
198 * registering any handlers
199 */
200 if (!secure_partition_ep_info->pc) {
201 return 1;
202 }
203
204 spm_init_sp_ep_state(secure_partition_ep_info,
205 secure_partition_ep_info->pc,
206 &sp_ctx);
207
208 /*
209 * All SPM initialization done. Now register our init function with
210 * BL31 for deferred invocation
211 */
212 bl31_register_bl32_init(&spm_init);
213
214 VERBOSE("%s exit\n", __func__);
215
216 return 0;
217}
218
219/*
220 * Attributes are encoded using a different format in the SMC interface than in
221 * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
222 * converts an attributes value from the SMC format to the mmap_attr_t format by
223 * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
224 * The other fields are left as 0 because they are ignored by the function
225 * change_mem_attributes().
226 */
227static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
228{
229 mmap_attr_t tf_attr = 0;
230
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000231 unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
232 >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100233
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000234 if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100235 tf_attr |= MT_RW | MT_USER;
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000236 } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100237 tf_attr |= MT_RO | MT_USER;
238 } else {
239 /* Other values are reserved. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000240 assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100241 /* The only requirement is that there's no access from EL0 */
242 tf_attr |= MT_RO | MT_PRIVILEGED;
243 }
244
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000245 if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100246 tf_attr |= MT_EXECUTE;
247 } else {
248 tf_attr |= MT_EXECUTE_NEVER;
249 }
250
251 return tf_attr;
252}
253
254/*
255 * This function converts attributes from the Trusted Firmware format into the
256 * SMC interface format.
257 */
258static int smc_mmap_to_smc_attr(mmap_attr_t attr)
259{
260 int smc_attr = 0;
261
262 int data_access;
263
264 if ((attr & MT_USER) == 0) {
265 /* No access from EL0. */
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000266 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100267 } else {
268 if ((attr & MT_RW) != 0) {
269 assert(MT_TYPE(attr) != MT_DEVICE);
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000270 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100271 } else {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000272 data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100273 }
274 }
275
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000276 smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
277 << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100278
279 if (attr & MT_EXECUTE_NEVER) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000280 smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100281 }
282
283 return smc_attr;
284}
285
286static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
287{
288 spin_lock(&mem_attr_smc_lock);
289
290 mmap_attr_t attributes;
291 int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
292 base_va, &attributes);
293
294 spin_unlock(&mem_attr_smc_lock);
295
296 /* Convert error codes of get_mem_attributes() into SPM ones. */
297 assert(rc == 0 || rc == -EINVAL);
298
299 if (rc == 0) {
300 return smc_mmap_to_smc_attr(attributes);
301 } else {
302 return SPM_INVALID_PARAMETER;
303 }
304}
305
306static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
307 u_register_t pages_count,
308 u_register_t smc_attributes)
309{
310 uintptr_t base_va = (uintptr_t) page_address;
311 size_t size = (size_t) (pages_count * PAGE_SIZE);
312 unsigned int attributes = (unsigned int) smc_attributes;
313
314 INFO(" Start address : 0x%lx\n", base_va);
315 INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
316 INFO(" Attributes : 0x%x\n", attributes);
317
318 spin_lock(&mem_attr_smc_lock);
319
320 int ret = change_mem_attributes(secure_partition_xlat_ctx_handle,
321 base_va, size, smc_attr_to_mmap_attr(attributes));
322
323 spin_unlock(&mem_attr_smc_lock);
324
325 /* Convert error codes of change_mem_attributes() into SPM ones. */
326 assert(ret == 0 || ret == -EINVAL);
327
328 return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
329}
330
331
332uint64_t spm_smc_handler(uint32_t smc_fid,
333 uint64_t x1,
334 uint64_t x2,
335 uint64_t x3,
336 uint64_t x4,
337 void *cookie,
338 void *handle,
339 uint64_t flags)
340{
341 cpu_context_t *ns_cpu_context;
342 unsigned int ns;
343
344 /* Determine which security state this SMC originated from */
345 ns = is_caller_non_secure(flags);
346
347 if (ns == SMC_FROM_SECURE) {
348
349 /* Handle SMCs from Secure world. */
350
351 switch (smc_fid) {
352
353 case SPM_VERSION_AARCH32:
354 SMC_RET1(handle, SPM_VERSION_COMPILED);
355
356 case SP_EVENT_COMPLETE_AARCH64:
357 assert(handle == cm_get_context(SECURE));
358 cm_el1_sysregs_context_save(SECURE);
359 spm_setup_next_eret_into_sel0(handle);
360
361 if (sp_init_in_progress) {
362 /*
363 * SPM reports completion. The SPM must have
364 * initiated the original request through a
365 * synchronous entry into the secure
366 * partition. Jump back to the original C
367 * runtime context.
368 */
369 spm_synchronous_sp_exit(&sp_ctx, x1);
370 assert(0);
371 }
372
373 /*
374 * This is the result from the Secure partition of an
375 * earlier request. Copy the result into the non-secure
376 * context, save the secure state and return to the
377 * non-secure state.
378 */
379
380 /* Get a reference to the non-secure context */
381 ns_cpu_context = cm_get_context(NON_SECURE);
382 assert(ns_cpu_context);
383
384 /* Restore non-secure state */
385 cm_el1_sysregs_context_restore(NON_SECURE);
386 cm_set_next_eret_context(NON_SECURE);
387
388 /* Return to normal world */
389 SMC_RET1(ns_cpu_context, x1);
390
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000391 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
392 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100393
394 if (!sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000395 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100396 SMC_RET1(handle, SPM_NOT_SUPPORTED);
397 }
398 SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
399
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000400 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
401 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100402
403 if (!sp_init_in_progress) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000404 WARN("SP_MEMORY_ATTRIBUTES_SET_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_set_smc_handler(x1, x2, x3));
408 default:
409 break;
410 }
411 } else {
412
413 /* Handle SMCs from Non-secure world. */
414
415 switch (smc_fid) {
416
417 case SP_VERSION_AARCH64:
418 case SP_VERSION_AARCH32:
419 SMC_RET1(handle, SP_VERSION_COMPILED);
420
Sandrine Bailleuxb31ee6b2017-12-01 09:44:21 +0000421 case MM_COMMUNICATE_AARCH32:
422 case MM_COMMUNICATE_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100423
424 /* Save the Normal world context */
425 cm_el1_sysregs_context_save(NON_SECURE);
426
427 /*
428 * Restore the secure world context and prepare for
429 * entry in S-EL0
430 */
431 assert(&sp_ctx.cpu_ctx == cm_get_context(SECURE));
432 cm_el1_sysregs_context_restore(SECURE);
433 cm_set_next_eret_context(SECURE);
434
Antonio Nino Diaz1adbf562017-11-15 10:36:21 +0000435 /* Cookie. Reserved for future use. It must be zero. */
436 assert(x1 == 0);
437
438 if (x3 != 0) {
Sandrine Bailleuxb31ee6b2017-12-01 09:44:21 +0000439 VERBOSE("MM_COMMUNICATE_AARCH32/64: X3 is not 0 as recommended.\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100440 }
441
Antonio Nino Diaz1adbf562017-11-15 10:36:21 +0000442 SMC_RET4(&sp_ctx.cpu_ctx, smc_fid, x1, x2, x3);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100443
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000444 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
445 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100446 /* SMC interfaces reserved for secure callers. */
447 SMC_RET1(handle, SPM_NOT_SUPPORTED);
448
449 default:
450 break;
451 }
452 }
453
454 SMC_RET1(handle, SMC_UNK);
455}