blob: b1d5dd86d7acb94cd7f62cf2a69a06ece858c2d6 [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>
Sughosh Ganue77f9e82018-11-14 11:06:24 +053012#include <ehf.h>
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010013#include <errno.h>
14#include <platform.h>
15#include <runtime_svc.h>
Antonio Nino Diaz3c817f42018-03-21 10:49:27 +000016#include <smccc.h>
17#include <smccc_helpers.h>
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010018#include <spinlock.h>
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +000019#include <string.h>
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010020#include <spm_svc.h>
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +000021#include <sprt_svc.h>
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010022#include <utils.h>
23#include <xlat_tables_v2.h>
24
25#include "spm_private.h"
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +010026
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010027/*******************************************************************************
28 * Secure Partition context information.
29 ******************************************************************************/
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +000030sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS];
31
32/* Last Secure Partition last used by the CPU */
33sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT];
34
35void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx)
36{
37 assert(linear_id < PLATFORM_CORE_COUNT);
38
39 cpu_sp_ctx[linear_id] = sp_ctx;
40}
41
42sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id)
43{
44 assert(linear_id < PLATFORM_CORE_COUNT);
45
46 return cpu_sp_ctx[linear_id];
47}
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010048
49/*******************************************************************************
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +000050 * This function returns a pointer to the context of the Secure Partition that
51 * handles the service specified by an UUID. It returns NULL if the UUID wasn't
52 * found.
53 ******************************************************************************/
54sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4])
55{
56 unsigned int i;
57
58 for (i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
59
60 sp_context_t *sp_ctx = &sp_ctx_array[i];
61
62 if (sp_ctx->is_present == 0) {
63 continue;
64 }
65
66 struct sp_rd_sect_service *rdsvc;
67
68 for (rdsvc = sp_ctx->rd.service; rdsvc != NULL;
69 rdsvc = rdsvc->next) {
70 uint32_t *rd_uuid = (uint32_t *)(rdsvc->uuid);
71
72 if (memcmp(rd_uuid, svc_uuid, sizeof(rd_uuid)) == 0) {
73 return sp_ctx;
74 }
75 }
76 }
77
78 return NULL;
79}
80
81/*******************************************************************************
Antonio Nino Diazc4f27522018-05-23 09:09:41 +010082 * Set state of a Secure Partition context.
83 ******************************************************************************/
84void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
85{
86 spin_lock(&(sp_ptr->state_lock));
87 sp_ptr->state = state;
88 spin_unlock(&(sp_ptr->state_lock));
89}
90
91/*******************************************************************************
92 * Wait until the state of a Secure Partition is the specified one and change it
93 * to the desired state.
94 ******************************************************************************/
95void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
96{
97 int success = 0;
98
99 while (success == 0) {
100 spin_lock(&(sp_ptr->state_lock));
101
102 if (sp_ptr->state == from) {
103 sp_ptr->state = to;
104
105 success = 1;
106 }
107
108 spin_unlock(&(sp_ptr->state_lock));
109 }
110}
111
112/*******************************************************************************
113 * Check if the state of a Secure Partition is the specified one and, if so,
114 * change it to the desired state. Returns 0 on success, -1 on error.
115 ******************************************************************************/
116int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
117{
118 int ret = -1;
119
120 spin_lock(&(sp_ptr->state_lock));
121
122 if (sp_ptr->state == from) {
123 sp_ptr->state = to;
124
125 ret = 0;
126 }
127
128 spin_unlock(&(sp_ptr->state_lock));
129
130 return ret;
131}
132
133/*******************************************************************************
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100134 * This function takes an SP context pointer and performs a synchronous entry
135 * into it.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100136 ******************************************************************************/
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000137uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100138{
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100139 uint64_t rc;
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000140 unsigned int linear_id = plat_my_core_pos();
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100141
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100142 assert(sp_ctx != NULL);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100143
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100144 /* Assign the context of the SP to this CPU */
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000145 spm_cpu_set_sp_ctx(linear_id, sp_ctx);
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100146 cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100147
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100148 /* Restore the context assigned above */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100149 cm_el1_sysregs_context_restore(SECURE);
150 cm_set_next_eret_context(SECURE);
151
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100152 /* Invalidate TLBs at EL1. */
153 tlbivmalle1();
154 dsbish();
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100155
156 /* Enter Secure Partition */
157 rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
158
159 /* Save secure state */
160 cm_el1_sysregs_context_save(SECURE);
161
162 return rc;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100163}
164
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100165/*******************************************************************************
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100166 * This function returns to the place where spm_sp_synchronous_entry() was
167 * called originally.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100168 ******************************************************************************/
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000169__dead2 void spm_sp_synchronous_exit(uint64_t rc)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100170{
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000171 /* Get context of the SP in use by this CPU. */
172 unsigned int linear_id = plat_my_core_pos();
173 sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100174
175 /*
176 * The SPM must have initiated the original request through a
177 * synchronous entry into the secure partition. Jump back to the
178 * original C runtime context with the value of rc in x0;
179 */
180 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
181
182 panic();
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100183}
184
185/*******************************************************************************
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100186 * Jump to each Secure Partition for the first time.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100187 ******************************************************************************/
Antonio Nino Diaze8811472018-04-17 15:10:18 +0100188static int32_t spm_init(void)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100189{
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000190 uint64_t rc = 0;
Antonio Nino Diaz28759312018-05-22 16:26:48 +0100191 sp_context_t *ctx;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100192
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000193 for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100194
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000195 ctx = &sp_ctx_array[i];
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100196
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000197 if (ctx->is_present == 0) {
198 continue;
199 }
200
201 INFO("Secure Partition %u init...\n", i);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100202
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000203 ctx->state = SP_STATE_RESET;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100204
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000205 rc = spm_sp_synchronous_entry(ctx);
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000206 if (rc != SPRT_YIELD_AARCH64) {
207 ERROR("Unexpected return value 0x%llx\n", rc);
208 panic();
209 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100210
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000211 ctx->state = SP_STATE_IDLE;
212
213 INFO("Secure Partition %u initialized.\n", i);
214 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100215
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100216 return rc;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100217}
218
219/*******************************************************************************
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100220 * Initialize contexts of all Secure Partitions.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100221 ******************************************************************************/
222int32_t spm_setup(void)
223{
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000224 int rc;
Antonio Nino Diaz28759312018-05-22 16:26:48 +0100225 sp_context_t *ctx;
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000226 void *sp_base, *rd_base;
227 size_t sp_size, rd_size;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100228
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100229 /* Disable MMU at EL1 (initialized by BL2) */
230 disable_mmu_icache_el1();
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100231
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000232 unsigned int i = 0U;
233
234 while (1) {
235 rc = plat_spm_sp_get_next_address(&sp_base, &sp_size,
236 &rd_base, &rd_size);
237 if (rc < 0) {
238 /* Reached the end of the package. */
239 break;
240 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100241
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000242 if (i >= PLAT_SPM_MAX_PARTITIONS) {
243 ERROR("Too many partitions in the package.\n");
244 panic();
245 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100246
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000247 ctx = &sp_ctx_array[i];
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000248
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000249 assert(ctx->is_present == 0);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100250
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000251 /* Initialize context of the SP */
252 INFO("Secure Partition %u context setup start...\n", i);
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000253
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000254 /* Assign translation tables context. */
255 ctx->xlat_ctx_handle = spm_sp_xlat_context_alloc();
256
257 /* Save location of the image in physical memory */
258 ctx->image_base = (uintptr_t)sp_base;
259 ctx->image_size = sp_size;
260
261 rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size);
262 if (rc < 0) {
263 ERROR("Error while loading RD blob.\n");
264 panic();
265 }
266
267 spm_sp_setup(ctx);
268
269 ctx->is_present = 1;
270
271 INFO("Secure Partition %u setup done.\n", i);
272
273 i++;
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000274 }
275
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000276 if (i == 0U) {
277 ERROR("No present partitions in the package.\n");
278 panic();
279 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100280
281 /* Register init function for deferred init. */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100282 bl31_register_bl32_init(&spm_init);
283
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100284 return 0;
285}
286
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100287/*******************************************************************************
288 * Secure Partition Manager SMC handler.
289 ******************************************************************************/
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100290uint64_t spm_smc_handler(uint32_t smc_fid,
291 uint64_t x1,
292 uint64_t x2,
293 uint64_t x3,
294 uint64_t x4,
295 void *cookie,
296 void *handle,
297 uint64_t flags)
298{
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100299 unsigned int ns;
300
301 /* Determine which security state this SMC originated from */
302 ns = is_caller_non_secure(flags);
303
304 if (ns == SMC_FROM_SECURE) {
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000305 unsigned int linear_id = plat_my_core_pos();
306 sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100307
308 /* Handle SMCs from Secure world. */
309
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100310 assert(handle == cm_get_context(SECURE));
311
312 /* Make next ERET jump to S-EL0 instead of S-EL1. */
313 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
314
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100315 switch (smc_fid) {
316
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000317 case SPM_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100318 SMC_RET1(handle, SPM_VERSION_COMPILED);
319
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000320 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
321 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100322
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000323 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000324 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100325 SMC_RET1(handle, SPM_NOT_SUPPORTED);
326 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100327 SMC_RET1(handle,
328 spm_memory_attributes_get_smc_handler(
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000329 sp_ctx, x1));
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100330
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000331 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
332 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100333
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000334 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000335 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100336 SMC_RET1(handle, SPM_NOT_SUPPORTED);
337 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100338 SMC_RET1(handle,
339 spm_memory_attributes_set_smc_handler(
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000340 sp_ctx, x1, x2, x3));
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100341 default:
342 break;
343 }
344 } else {
345
346 /* Handle SMCs from Non-secure world. */
347
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100348 assert(handle == cm_get_context(NON_SECURE));
349
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100350 switch (smc_fid) {
351
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000352 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
353 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100354 /* SMC interfaces reserved for secure callers. */
355 SMC_RET1(handle, SPM_NOT_SUPPORTED);
356
357 default:
358 break;
359 }
360 }
361
362 SMC_RET1(handle, SMC_UNK);
363}