spm_main.c 9.11 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
/*******************************************************************************
 * 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;
}

81
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*******************************************************************************
 * 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;
}

133
/*******************************************************************************
134
135
 * This function takes an SP context pointer and performs a synchronous entry
 * into it.
136
 ******************************************************************************/
137
uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
138
{
139
	uint64_t rc;
140
	unsigned int linear_id = plat_my_core_pos();
141

142
	assert(sp_ctx != NULL);
143

144
	/* Assign the context of the SP to this CPU */
145
	spm_cpu_set_sp_ctx(linear_id, sp_ctx);
146
	cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
147

148
	/* Restore the context assigned above */
149
150
151
	cm_el1_sysregs_context_restore(SECURE);
	cm_set_next_eret_context(SECURE);

152
153
154
	/* Invalidate TLBs at EL1. */
	tlbivmalle1();
	dsbish();
155
156
157
158
159
160
161
162

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

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

	return rc;
163
164
165
}

/*******************************************************************************
166
167
 * This function returns to the place where spm_sp_synchronous_entry() was
 * called originally.
168
 ******************************************************************************/
169
__dead2 void spm_sp_synchronous_exit(uint64_t rc)
170
{
171
172
173
	/* 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);
174
175
176
177
178
179
180
181
182

	/*
	 * 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();
183
184
185
}

/*******************************************************************************
186
 * Jump to each Secure Partition for the first time.
187
 ******************************************************************************/
188
static int32_t spm_init(void)
189
{
190
	uint64_t rc = 0;
191
	sp_context_t *ctx;
192

193
194
195
196
197
198
199
	for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {

		ctx = &sp_ctx_array[i];

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

201
		INFO("Secure Partition %u init...\n", i);
202

203
		ctx->state = SP_STATE_RESET;
204

205
		rc = spm_sp_synchronous_entry(ctx);
206
207
208
209
		if (rc != SPRT_YIELD_AARCH64) {
			ERROR("Unexpected return value 0x%llx\n", rc);
			panic();
		}
210

211
		ctx->state = SP_STATE_IDLE;
212

213
214
		INFO("Secure Partition %u initialized.\n", i);
	}
215

216
	return rc;
217
218
219
}

/*******************************************************************************
220
 * Initialize contexts of all Secure Partitions.
221
222
223
 ******************************************************************************/
int32_t spm_setup(void)
{
224
	int rc;
225
	sp_context_t *ctx;
226
227
	void *sp_base, *rd_base;
	size_t sp_size, rd_size;
228

229
230
231
	/* Disable MMU at EL1 (initialized by BL2) */
	disable_mmu_icache_el1();

232
	unsigned int i = 0U;
233

234
235
236
237
238
239
240
	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;
		}
241

242
243
244
245
		if (i >= PLAT_SPM_MAX_PARTITIONS) {
			ERROR("Too many partitions in the package.\n");
			panic();
		}
246

247
		ctx = &sp_ctx_array[i];
248

249
		assert(ctx->is_present == 0);
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
		/* 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++;
274
275
	}

276
277
278
279
	if (i == 0U) {
		ERROR("No present partitions in the package.\n");
		panic();
	}
280
281

	/* Register init function for deferred init.  */
282
283
284
285
286
	bl31_register_bl32_init(&spm_init);

	return 0;
}

287
288
289
/*******************************************************************************
 * Secure Partition Manager SMC handler.
 ******************************************************************************/
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
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) {
305
306
		unsigned int linear_id = plat_my_core_pos();
		sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
307
308
309

		/* Handle SMCs from Secure world. */

310
311
312
313
314
		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());

315
316
		switch (smc_fid) {

317
		case SPM_VERSION_AARCH32:
318
319
			SMC_RET1(handle, SPM_VERSION_COMPILED);

320
321
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
322

323
			if (sp_ctx->state != SP_STATE_RESET) {
324
				WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
325
326
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
327
328
			SMC_RET1(handle,
				 spm_memory_attributes_get_smc_handler(
329
					sp_ctx, x1));
330

331
332
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
333

334
			if (sp_ctx->state != SP_STATE_RESET) {
335
				WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
336
337
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
338
339
			SMC_RET1(handle,
				 spm_memory_attributes_set_smc_handler(
340
					sp_ctx, x1, x2, x3));
341
342
343
344
345
346
347
		default:
			break;
		}
	} else {

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

348
349
		assert(handle == cm_get_context(NON_SECURE));

350
351
		switch (smc_fid) {

352
353
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
354
355
356
357
358
359
360
361
362
363
			/* SMC interfaces reserved for secure callers. */
			SMC_RET1(handle, SPM_NOT_SUPPORTED);

		default:
			break;
		}
	}

	SMC_RET1(handle, SMC_UNK);
}