spm_main.c 10 KB
Newer Older
1
/*
2
 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3
4
5
6
7
8
9
10
11
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <assert.h>
#include <bl31.h>
#include <context_mgmt.h>
#include <debug.h>
12
#include <ehf.h>
13
14
15
#include <errno.h>
#include <platform.h>
#include <runtime_svc.h>
Antonio Nino Diaz's avatar
Antonio Nino Diaz committed
16
17
#include <smccc.h>
#include <smccc_helpers.h>
18
#include <spinlock.h>
19
#include <string.h>
20
#include <spm_svc.h>
21
#include <sprt_svc.h>
22
23
24
25
#include <utils.h>
#include <xlat_tables_v2.h>

#include "spm_private.h"
26

27
28
29
/*******************************************************************************
 * Secure Partition context information.
 ******************************************************************************/
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS];

/* Last Secure Partition last used by the CPU */
sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT];

void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx)
{
	assert(linear_id < PLATFORM_CORE_COUNT);

	cpu_sp_ctx[linear_id] = sp_ctx;
}

sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id)
{
	assert(linear_id < PLATFORM_CORE_COUNT);

	return cpu_sp_ctx[linear_id];
}
48

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*******************************************************************************
 * Functions to keep track of how many requests a Secure Partition has received
 * and hasn't finished.
 ******************************************************************************/
void spm_sp_request_increase(sp_context_t *sp_ctx)
{
	spin_lock(&(sp_ctx->request_count_lock));
	sp_ctx->request_count++;
	spin_unlock(&(sp_ctx->request_count_lock));
}

void spm_sp_request_decrease(sp_context_t *sp_ctx)
{
	spin_lock(&(sp_ctx->request_count_lock));
	sp_ctx->request_count--;
	spin_unlock(&(sp_ctx->request_count_lock));
}

/* Returns 0 if it was originally 0, -1 otherwise. */
int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx)
{
	int ret = -1;

	spin_lock(&(sp_ctx->request_count_lock));
	if (sp_ctx->request_count == 0U) {
		sp_ctx->request_count++;
		ret = 0U;
	}
	spin_unlock(&(sp_ctx->request_count_lock));

	return ret;
}

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*******************************************************************************
 * This function returns a pointer to the context of the Secure Partition that
 * handles the service specified by an UUID. It returns NULL if the UUID wasn't
 * found.
 ******************************************************************************/
sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4])
{
	unsigned int i;

	for (i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {

		sp_context_t *sp_ctx = &sp_ctx_array[i];

		if (sp_ctx->is_present == 0) {
			continue;
		}

		struct sp_rd_sect_service *rdsvc;

		for (rdsvc = sp_ctx->rd.service; rdsvc != NULL;
		     rdsvc = rdsvc->next) {
			uint32_t *rd_uuid = (uint32_t *)(rdsvc->uuid);

			if (memcmp(rd_uuid, svc_uuid, sizeof(rd_uuid)) == 0) {
				return sp_ctx;
			}
		}
	}

	return NULL;
}

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*******************************************************************************
 * Set state of a Secure Partition context.
 ******************************************************************************/
void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
{
	spin_lock(&(sp_ptr->state_lock));
	sp_ptr->state = state;
	spin_unlock(&(sp_ptr->state_lock));
}

/*******************************************************************************
 * Wait until the state of a Secure Partition is the specified one and change it
 * to the desired state.
 ******************************************************************************/
void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
{
	int success = 0;

	while (success == 0) {
		spin_lock(&(sp_ptr->state_lock));

		if (sp_ptr->state == from) {
			sp_ptr->state = to;

			success = 1;
		}

		spin_unlock(&(sp_ptr->state_lock));
	}
}

/*******************************************************************************
 * Check if the state of a Secure Partition is the specified one and, if so,
 * change it to the desired state. Returns 0 on success, -1 on error.
 ******************************************************************************/
int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
{
	int ret = -1;

	spin_lock(&(sp_ptr->state_lock));

	if (sp_ptr->state == from) {
		sp_ptr->state = to;

		ret = 0;
	}

	spin_unlock(&(sp_ptr->state_lock));

	return ret;
}

166
/*******************************************************************************
167
168
 * This function takes an SP context pointer and performs a synchronous entry
 * into it.
169
 ******************************************************************************/
170
uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
171
{
172
	uint64_t rc;
173
	unsigned int linear_id = plat_my_core_pos();
174

175
	assert(sp_ctx != NULL);
176

177
	/* Assign the context of the SP to this CPU */
178
	spm_cpu_set_sp_ctx(linear_id, sp_ctx);
179
	cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
180

181
	/* Restore the context assigned above */
182
183
184
	cm_el1_sysregs_context_restore(SECURE);
	cm_set_next_eret_context(SECURE);

185
186
187
	/* Invalidate TLBs at EL1. */
	tlbivmalle1();
	dsbish();
188
189
190
191
192
193
194
195

	/* Enter Secure Partition */
	rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);

	/* Save secure state */
	cm_el1_sysregs_context_save(SECURE);

	return rc;
196
197
198
}

/*******************************************************************************
199
200
 * This function returns to the place where spm_sp_synchronous_entry() was
 * called originally.
201
 ******************************************************************************/
202
__dead2 void spm_sp_synchronous_exit(uint64_t rc)
203
{
204
205
206
	/* Get context of the SP in use by this CPU. */
	unsigned int linear_id = plat_my_core_pos();
	sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id);
207
208
209
210
211
212
213
214
215

	/*
	 * The SPM must have initiated the original request through a
	 * synchronous entry into the secure partition. Jump back to the
	 * original C runtime context with the value of rc in x0;
	 */
	spm_secure_partition_exit(ctx->c_rt_ctx, rc);

	panic();
216
217
218
}

/*******************************************************************************
219
 * Jump to each Secure Partition for the first time.
220
 ******************************************************************************/
221
static int32_t spm_init(void)
222
{
223
	uint64_t rc = 0;
224
	sp_context_t *ctx;
225

226
227
228
229
230
231
232
	for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {

		ctx = &sp_ctx_array[i];

		if (ctx->is_present == 0) {
			continue;
		}
233

234
		INFO("Secure Partition %u init...\n", i);
235

236
		ctx->state = SP_STATE_RESET;
237

238
		rc = spm_sp_synchronous_entry(ctx);
239
240
241
242
		if (rc != SPRT_YIELD_AARCH64) {
			ERROR("Unexpected return value 0x%llx\n", rc);
			panic();
		}
243

244
		ctx->state = SP_STATE_IDLE;
245

246
247
		INFO("Secure Partition %u initialized.\n", i);
	}
248

249
	return rc;
250
251
252
}

/*******************************************************************************
253
 * Initialize contexts of all Secure Partitions.
254
255
256
 ******************************************************************************/
int32_t spm_setup(void)
{
257
	int rc;
258
	sp_context_t *ctx;
259
260
	void *sp_base, *rd_base;
	size_t sp_size, rd_size;
261

262
263
264
	/* Disable MMU at EL1 (initialized by BL2) */
	disable_mmu_icache_el1();

265
	unsigned int i = 0U;
266

267
268
269
270
271
272
273
	while (1) {
		rc = plat_spm_sp_get_next_address(&sp_base, &sp_size,
						&rd_base, &rd_size);
		if (rc < 0) {
			/* Reached the end of the package. */
			break;
		}
274

275
276
277
278
		if (i >= PLAT_SPM_MAX_PARTITIONS) {
			ERROR("Too many partitions in the package.\n");
			panic();
		}
279

280
		ctx = &sp_ctx_array[i];
281

282
		assert(ctx->is_present == 0);
283

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
		/* Initialize context of the SP */
		INFO("Secure Partition %u context setup start...\n", i);

		/* Assign translation tables context. */
		ctx->xlat_ctx_handle = spm_sp_xlat_context_alloc();

		/* Save location of the image in physical memory */
		ctx->image_base = (uintptr_t)sp_base;
		ctx->image_size = sp_size;

		rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size);
		if (rc < 0) {
			ERROR("Error while loading RD blob.\n");
			panic();
		}

		spm_sp_setup(ctx);

		ctx->is_present = 1;

		INFO("Secure Partition %u setup done.\n", i);

		i++;
307
308
	}

309
310
311
312
	if (i == 0U) {
		ERROR("No present partitions in the package.\n");
		panic();
	}
313
314

	/* Register init function for deferred init.  */
315
316
317
318
319
	bl31_register_bl32_init(&spm_init);

	return 0;
}

320
321
322
/*******************************************************************************
 * Secure Partition Manager SMC handler.
 ******************************************************************************/
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
uint64_t spm_smc_handler(uint32_t smc_fid,
			 uint64_t x1,
			 uint64_t x2,
			 uint64_t x3,
			 uint64_t x4,
			 void *cookie,
			 void *handle,
			 uint64_t flags)
{
	unsigned int ns;

	/* Determine which security state this SMC originated from */
	ns = is_caller_non_secure(flags);

	if (ns == SMC_FROM_SECURE) {
338
339
		unsigned int linear_id = plat_my_core_pos();
		sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
340
341
342

		/* Handle SMCs from Secure world. */

343
344
345
346
347
		assert(handle == cm_get_context(SECURE));

		/* Make next ERET jump to S-EL0 instead of S-EL1. */
		cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());

348
349
		switch (smc_fid) {

350
		case SPM_VERSION_AARCH32:
351
352
			SMC_RET1(handle, SPM_VERSION_COMPILED);

353
354
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
355

356
			if (sp_ctx->state != SP_STATE_RESET) {
357
				WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
358
359
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
360
361
			SMC_RET1(handle,
				 spm_memory_attributes_get_smc_handler(
362
					sp_ctx, x1));
363

364
365
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
366

367
			if (sp_ctx->state != SP_STATE_RESET) {
368
				WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
369
370
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
371
372
			SMC_RET1(handle,
				 spm_memory_attributes_set_smc_handler(
373
					sp_ctx, x1, x2, x3));
374
375
376
377
378
379
380
		default:
			break;
		}
	} else {

		/* Handle SMCs from Non-secure world. */

381
382
		assert(handle == cm_get_context(NON_SECURE));

383
384
		switch (smc_fid) {

385
386
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
387
388
389
390
391
392
393
394
395
396
			/* SMC interfaces reserved for secure callers. */
			SMC_RET1(handle, SPM_NOT_SUPPORTED);

		default:
			break;
		}
	}

	SMC_RET1(handle, SMC_UNK);
}