blob: ed188d48a42f97caafb353bcea1a7b5dd537780f [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>
21#include <utils.h>
22#include <xlat_tables_v2.h>
23
24#include "spm_private.h"
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +010025
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010026/*******************************************************************************
27 * Secure Partition context information.
28 ******************************************************************************/
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +000029sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS];
30
31/* Last Secure Partition last used by the CPU */
32sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT];
33
34void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx)
35{
36 assert(linear_id < PLATFORM_CORE_COUNT);
37
38 cpu_sp_ctx[linear_id] = sp_ctx;
39}
40
41sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id)
42{
43 assert(linear_id < PLATFORM_CORE_COUNT);
44
45 return cpu_sp_ctx[linear_id];
46}
Antonio Nino Diazc41f2062017-10-24 10:07:35 +010047
48/*******************************************************************************
Antonio Nino Diazb5b585a2018-11-08 14:20:07 +000049 * This function returns a pointer to the context of the Secure Partition that
50 * handles the service specified by an UUID. It returns NULL if the UUID wasn't
51 * found.
52 ******************************************************************************/
53sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4])
54{
55 unsigned int i;
56
57 for (i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
58
59 sp_context_t *sp_ctx = &sp_ctx_array[i];
60
61 if (sp_ctx->is_present == 0) {
62 continue;
63 }
64
65 struct sp_rd_sect_service *rdsvc;
66
67 for (rdsvc = sp_ctx->rd.service; rdsvc != NULL;
68 rdsvc = rdsvc->next) {
69 uint32_t *rd_uuid = (uint32_t *)(rdsvc->uuid);
70
71 if (memcmp(rd_uuid, svc_uuid, sizeof(rd_uuid)) == 0) {
72 return sp_ctx;
73 }
74 }
75 }
76
77 return NULL;
78}
79
80/*******************************************************************************
Antonio Nino Diazc4f27522018-05-23 09:09:41 +010081 * Set state of a Secure Partition context.
82 ******************************************************************************/
83void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
84{
85 spin_lock(&(sp_ptr->state_lock));
86 sp_ptr->state = state;
87 spin_unlock(&(sp_ptr->state_lock));
88}
89
90/*******************************************************************************
91 * Wait until the state of a Secure Partition is the specified one and change it
92 * to the desired state.
93 ******************************************************************************/
94void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
95{
96 int success = 0;
97
98 while (success == 0) {
99 spin_lock(&(sp_ptr->state_lock));
100
101 if (sp_ptr->state == from) {
102 sp_ptr->state = to;
103
104 success = 1;
105 }
106
107 spin_unlock(&(sp_ptr->state_lock));
108 }
109}
110
111/*******************************************************************************
112 * Check if the state of a Secure Partition is the specified one and, if so,
113 * change it to the desired state. Returns 0 on success, -1 on error.
114 ******************************************************************************/
115int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
116{
117 int ret = -1;
118
119 spin_lock(&(sp_ptr->state_lock));
120
121 if (sp_ptr->state == from) {
122 sp_ptr->state = to;
123
124 ret = 0;
125 }
126
127 spin_unlock(&(sp_ptr->state_lock));
128
129 return ret;
130}
131
132/*******************************************************************************
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100133 * This function takes an SP context pointer and performs a synchronous entry
134 * into it.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100135 ******************************************************************************/
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100136static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100137{
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100138 uint64_t rc;
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000139 unsigned int linear_id = plat_my_core_pos();
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100140
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100141 assert(sp_ctx != NULL);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100142
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100143 /* Assign the context of the SP to this CPU */
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000144 spm_cpu_set_sp_ctx(linear_id, sp_ctx);
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100145 cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100146
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100147 /* Restore the context assigned above */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100148 cm_el1_sysregs_context_restore(SECURE);
149 cm_set_next_eret_context(SECURE);
150
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100151 /* Invalidate TLBs at EL1. */
152 tlbivmalle1();
153 dsbish();
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100154
155 /* Enter Secure Partition */
156 rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
157
158 /* Save secure state */
159 cm_el1_sysregs_context_save(SECURE);
160
161 return rc;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100162}
163
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100164/*******************************************************************************
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100165 * This function returns to the place where spm_sp_synchronous_entry() was
166 * called originally.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100167 ******************************************************************************/
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100168__dead2 static void spm_sp_synchronous_exit(uint64_t rc)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100169{
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000170 /* Get context of the SP in use by this CPU. */
171 unsigned int linear_id = plat_my_core_pos();
172 sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100173
174 /*
175 * The SPM must have initiated the original request through a
176 * synchronous entry into the secure partition. Jump back to the
177 * original C runtime context with the value of rc in x0;
178 */
179 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
180
181 panic();
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100182}
183
184/*******************************************************************************
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100185 * Jump to each Secure Partition for the first time.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100186 ******************************************************************************/
Antonio Nino Diaze8811472018-04-17 15:10:18 +0100187static int32_t spm_init(void)
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100188{
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000189 uint64_t rc = 0;
Antonio Nino Diaz28759312018-05-22 16:26:48 +0100190 sp_context_t *ctx;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100191
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000192 for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100193
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000194 ctx = &sp_ctx_array[i];
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100195
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000196 if (ctx->is_present == 0) {
197 continue;
198 }
199
200 INFO("Secure Partition %u init...\n", i);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100201
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000202 ctx->state = SP_STATE_RESET;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100203
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000204 rc = spm_sp_synchronous_entry(ctx);
205 assert(rc == 0);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100206
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000207 ctx->state = SP_STATE_IDLE;
208
209 INFO("Secure Partition %u initialized.\n", i);
210 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100211
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100212 return rc;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100213}
214
215/*******************************************************************************
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100216 * Initialize contexts of all Secure Partitions.
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100217 ******************************************************************************/
218int32_t spm_setup(void)
219{
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000220 int rc;
Antonio Nino Diaz28759312018-05-22 16:26:48 +0100221 sp_context_t *ctx;
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000222 void *sp_base, *rd_base;
223 size_t sp_size, rd_size;
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100224
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100225 /* Disable MMU at EL1 (initialized by BL2) */
226 disable_mmu_icache_el1();
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100227
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000228 unsigned int i = 0U;
229
230 while (1) {
231 rc = plat_spm_sp_get_next_address(&sp_base, &sp_size,
232 &rd_base, &rd_size);
233 if (rc < 0) {
234 /* Reached the end of the package. */
235 break;
236 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100237
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000238 if (i >= PLAT_SPM_MAX_PARTITIONS) {
239 ERROR("Too many partitions in the package.\n");
240 panic();
241 }
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100242
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000243 ctx = &sp_ctx_array[i];
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000244
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000245 assert(ctx->is_present == 0);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100246
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000247 /* Initialize context of the SP */
248 INFO("Secure Partition %u context setup start...\n", i);
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000249
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000250 /* Assign translation tables context. */
251 ctx->xlat_ctx_handle = spm_sp_xlat_context_alloc();
252
253 /* Save location of the image in physical memory */
254 ctx->image_base = (uintptr_t)sp_base;
255 ctx->image_size = sp_size;
256
257 rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size);
258 if (rc < 0) {
259 ERROR("Error while loading RD blob.\n");
260 panic();
261 }
262
263 spm_sp_setup(ctx);
264
265 ctx->is_present = 1;
266
267 INFO("Secure Partition %u setup done.\n", i);
268
269 i++;
Antonio Nino Diaz840627f2018-11-27 08:36:02 +0000270 }
271
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000272 if (i == 0U) {
273 ERROR("No present partitions in the package.\n");
274 panic();
275 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100276
277 /* Register init function for deferred init. */
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100278 bl31_register_bl32_init(&spm_init);
279
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100280 return 0;
281}
282
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100283/*******************************************************************************
284 * Secure Partition Manager SMC handler.
285 ******************************************************************************/
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100286uint64_t spm_smc_handler(uint32_t smc_fid,
287 uint64_t x1,
288 uint64_t x2,
289 uint64_t x3,
290 uint64_t x4,
291 void *cookie,
292 void *handle,
293 uint64_t flags)
294{
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100295 unsigned int ns;
296
297 /* Determine which security state this SMC originated from */
298 ns = is_caller_non_secure(flags);
299
300 if (ns == SMC_FROM_SECURE) {
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000301 unsigned int linear_id = plat_my_core_pos();
302 sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100303
304 /* Handle SMCs from Secure world. */
305
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100306 assert(handle == cm_get_context(SECURE));
307
308 /* Make next ERET jump to S-EL0 instead of S-EL1. */
309 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
310
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100311 switch (smc_fid) {
312
Sandrine Bailleux843d3f02017-12-07 09:48:56 +0000313 case SPM_VERSION_AARCH32:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100314 SMC_RET1(handle, SPM_VERSION_COMPILED);
315
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000316 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
317 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100318
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000319 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000320 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100321 SMC_RET1(handle, SPM_NOT_SUPPORTED);
322 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100323 SMC_RET1(handle,
324 spm_memory_attributes_get_smc_handler(
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000325 sp_ctx, x1));
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100326
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000327 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
328 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100329
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000330 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000331 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100332 SMC_RET1(handle, SPM_NOT_SUPPORTED);
333 }
Antonio Nino Diaz2ac9a442018-05-23 11:40:46 +0100334 SMC_RET1(handle,
335 spm_memory_attributes_set_smc_handler(
Antonio Nino Diaz8cc23f92018-10-30 11:35:30 +0000336 sp_ctx, x1, x2, x3));
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100337 default:
338 break;
339 }
340 } else {
341
342 /* Handle SMCs from Non-secure world. */
343
Antonio Nino Diazda50cd02018-06-15 16:21:01 +0100344 assert(handle == cm_get_context(NON_SECURE));
345
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100346 switch (smc_fid) {
347
Antonio Nino Diaz837173f2017-12-01 14:12:43 +0000348 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
349 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diazc41f2062017-10-24 10:07:35 +0100350 /* SMC interfaces reserved for secure callers. */
351 SMC_RET1(handle, SPM_NOT_SUPPORTED);
352
353 default:
354 break;
355 }
356 }
357
358 SMC_RET1(handle, SMC_UNK);
359}