blob: e8dda0f82956982bed5dbc992b04c34c38ca3b21 [file] [log] [blame]
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +01001/*
Antonio Nino Diaza5b4c402018-01-08 17:33:34 +00002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Antonio Nino Diaz2fccb222017-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 Ganu6e3bad32018-11-14 11:06:24 +053012#include <ehf.h>
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +010013#include <errno.h>
14#include <platform.h>
15#include <runtime_svc.h>
Antonio Nino Diaz085e80e2018-03-21 10:49:27 +000016#include <smccc.h>
17#include <smccc_helpers.h>
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +010018#include <spinlock.h>
19#include <spm_svc.h>
20#include <utils.h>
21#include <xlat_tables_v2.h>
22
23#include "spm_private.h"
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +010024
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +010025/*******************************************************************************
26 * Secure Partition context information.
27 ******************************************************************************/
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +000028sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS];
29
30/* Last Secure Partition last used by the CPU */
31sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT];
32
33void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx)
34{
35 assert(linear_id < PLATFORM_CORE_COUNT);
36
37 cpu_sp_ctx[linear_id] = sp_ctx;
38}
39
40sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id)
41{
42 assert(linear_id < PLATFORM_CORE_COUNT);
43
44 return cpu_sp_ctx[linear_id];
45}
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +010046
47/*******************************************************************************
Antonio Nino Diaz46f996d2018-05-23 09:09:41 +010048 * Set state of a Secure Partition context.
49 ******************************************************************************/
50void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
51{
52 spin_lock(&(sp_ptr->state_lock));
53 sp_ptr->state = state;
54 spin_unlock(&(sp_ptr->state_lock));
55}
56
57/*******************************************************************************
58 * Wait until the state of a Secure Partition is the specified one and change it
59 * to the desired state.
60 ******************************************************************************/
61void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
62{
63 int success = 0;
64
65 while (success == 0) {
66 spin_lock(&(sp_ptr->state_lock));
67
68 if (sp_ptr->state == from) {
69 sp_ptr->state = to;
70
71 success = 1;
72 }
73
74 spin_unlock(&(sp_ptr->state_lock));
75 }
76}
77
78/*******************************************************************************
79 * Check if the state of a Secure Partition is the specified one and, if so,
80 * change it to the desired state. Returns 0 on success, -1 on error.
81 ******************************************************************************/
82int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
83{
84 int ret = -1;
85
86 spin_lock(&(sp_ptr->state_lock));
87
88 if (sp_ptr->state == from) {
89 sp_ptr->state = to;
90
91 ret = 0;
92 }
93
94 spin_unlock(&(sp_ptr->state_lock));
95
96 return ret;
97}
98
99/*******************************************************************************
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100100 * This function takes an SP context pointer and performs a synchronous entry
101 * into it.
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100102 ******************************************************************************/
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100103static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100104{
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100105 uint64_t rc;
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000106 unsigned int linear_id = plat_my_core_pos();
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100107
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100108 assert(sp_ctx != NULL);
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100109
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100110 /* Assign the context of the SP to this CPU */
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000111 spm_cpu_set_sp_ctx(linear_id, sp_ctx);
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100112 cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100113
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100114 /* Restore the context assigned above */
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100115 cm_el1_sysregs_context_restore(SECURE);
116 cm_set_next_eret_context(SECURE);
117
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100118 /* Invalidate TLBs at EL1. */
119 tlbivmalle1();
120 dsbish();
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100121
122 /* Enter Secure Partition */
123 rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
124
125 /* Save secure state */
126 cm_el1_sysregs_context_save(SECURE);
127
128 return rc;
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100129}
130
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100131/*******************************************************************************
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100132 * This function returns to the place where spm_sp_synchronous_entry() was
133 * called originally.
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100134 ******************************************************************************/
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100135__dead2 static void spm_sp_synchronous_exit(uint64_t rc)
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100136{
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000137 /* Get context of the SP in use by this CPU. */
138 unsigned int linear_id = plat_my_core_pos();
139 sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100140
141 /*
142 * The SPM must have initiated the original request through a
143 * synchronous entry into the secure partition. Jump back to the
144 * original C runtime context with the value of rc in x0;
145 */
146 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
147
148 panic();
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100149}
150
151/*******************************************************************************
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100152 * Jump to each Secure Partition for the first time.
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100153 ******************************************************************************/
Antonio Nino Diazb3323cd2018-04-17 15:10:18 +0100154static int32_t spm_init(void)
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100155{
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000156 uint64_t rc = 0;
Antonio Nino Diaz07f3f632018-05-22 16:26:48 +0100157 sp_context_t *ctx;
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100158
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000159 for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100160
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000161 ctx = &sp_ctx_array[i];
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100162
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000163 if (ctx->is_present == 0) {
164 continue;
165 }
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100166
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000167 INFO("Secure Partition %u init...\n", i);
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100168
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000169 ctx->state = SP_STATE_RESET;
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100170
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000171 rc = spm_sp_synchronous_entry(ctx);
172 assert(rc == 0);
173
174 ctx->state = SP_STATE_IDLE;
175
176 INFO("Secure Partition %u initialized.\n", i);
177 }
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100178
179 return rc;
180}
181
182/*******************************************************************************
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100183 * Initialize contexts of all Secure Partitions.
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100184 ******************************************************************************/
185int32_t spm_setup(void)
186{
Antonio Nino Diaz680389a2018-11-27 08:36:02 +0000187 int rc;
Antonio Nino Diaz07f3f632018-05-22 16:26:48 +0100188 sp_context_t *ctx;
Antonio Nino Diaz680389a2018-11-27 08:36:02 +0000189 void *sp_base, *rd_base;
190 size_t sp_size, rd_size;
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100191
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100192 /* Disable MMU at EL1 (initialized by BL2) */
193 disable_mmu_icache_el1();
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100194
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000195 unsigned int i = 0U;
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100196
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000197 while (1) {
198 rc = plat_spm_sp_get_next_address(&sp_base, &sp_size,
199 &rd_base, &rd_size);
200 if (rc < 0) {
201 /* Reached the end of the package. */
202 break;
203 }
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100204
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000205 if (i >= PLAT_SPM_MAX_PARTITIONS) {
206 ERROR("Too many partitions in the package.\n");
207 panic();
208 }
209
210 ctx = &sp_ctx_array[i];
211
212 assert(ctx->is_present == 0);
213
214 /* Initialize context of the SP */
215 INFO("Secure Partition %u context setup start...\n", i);
216
217 /* Assign translation tables context. */
218 ctx->xlat_ctx_handle = spm_sp_xlat_context_alloc();
219
220 /* Save location of the image in physical memory */
221 ctx->image_base = (uintptr_t)sp_base;
222 ctx->image_size = sp_size;
223
224 rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size);
225 if (rc < 0) {
226 ERROR("Error while loading RD blob.\n");
227 panic();
228 }
229
230 spm_sp_setup(ctx);
231
232 ctx->is_present = 1;
233
234 INFO("Secure Partition %u setup done.\n", i);
235
236 i++;
Antonio Nino Diaz680389a2018-11-27 08:36:02 +0000237 }
238
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000239 if (i == 0U) {
240 ERROR("No present partitions in the package.\n");
Antonio Nino Diaz680389a2018-11-27 08:36:02 +0000241 panic();
242 }
243
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100244 /* Register init function for deferred init. */
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100245 bl31_register_bl32_init(&spm_init);
246
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100247 return 0;
248}
249
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100250/*******************************************************************************
251 * Secure Partition Manager SMC handler.
252 ******************************************************************************/
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100253uint64_t spm_smc_handler(uint32_t smc_fid,
254 uint64_t x1,
255 uint64_t x2,
256 uint64_t x3,
257 uint64_t x4,
258 void *cookie,
259 void *handle,
260 uint64_t flags)
261{
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100262 unsigned int ns;
263
264 /* Determine which security state this SMC originated from */
265 ns = is_caller_non_secure(flags);
266
267 if (ns == SMC_FROM_SECURE) {
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000268 unsigned int linear_id = plat_my_core_pos();
269 sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100270
271 /* Handle SMCs from Secure world. */
272
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100273 assert(handle == cm_get_context(SECURE));
274
275 /* Make next ERET jump to S-EL0 instead of S-EL1. */
276 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
277
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100278 switch (smc_fid) {
279
Sandrine Bailleux4d2787c2017-12-07 09:48:56 +0000280 case SPM_VERSION_AARCH32:
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100281 SMC_RET1(handle, SPM_VERSION_COMPILED);
282
Antonio Nino Diazfa0ed2b2017-12-01 14:12:43 +0000283 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
284 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100285
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000286 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diazfa0ed2b2017-12-01 14:12:43 +0000287 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100288 SMC_RET1(handle, SPM_NOT_SUPPORTED);
289 }
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100290 SMC_RET1(handle,
291 spm_memory_attributes_get_smc_handler(
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000292 sp_ctx, x1));
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100293
Antonio Nino Diazfa0ed2b2017-12-01 14:12:43 +0000294 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
295 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100296
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000297 if (sp_ctx->state != SP_STATE_RESET) {
Antonio Nino Diazfa0ed2b2017-12-01 14:12:43 +0000298 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100299 SMC_RET1(handle, SPM_NOT_SUPPORTED);
300 }
Antonio Nino Diaz22282bb2018-05-23 11:40:46 +0100301 SMC_RET1(handle,
302 spm_memory_attributes_set_smc_handler(
Antonio Nino Diaz0fa1a022018-10-30 11:35:30 +0000303 sp_ctx, x1, x2, x3));
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100304 default:
305 break;
306 }
307 } else {
308
309 /* Handle SMCs from Non-secure world. */
310
Antonio Nino Diaz14fcc6e2018-06-15 16:21:01 +0100311 assert(handle == cm_get_context(NON_SECURE));
312
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100313 switch (smc_fid) {
314
Antonio Nino Diazfa0ed2b2017-12-01 14:12:43 +0000315 case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
316 case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
Antonio Nino Diaz2fccb222017-10-24 10:07:35 +0100317 /* SMC interfaces reserved for secure callers. */
318 SMC_RET1(handle, SPM_NOT_SUPPORTED);
319
320 default:
321 break;
322 }
323 }
324
325 SMC_RET1(handle, SMC_UNK);
326}