spm_main.c 6.78 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
12
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

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

#include "spm_private.h"
25

26
27
28
/*******************************************************************************
 * Secure Partition context information.
 ******************************************************************************/
29
static sp_context_t sp_ctx;
30
31

/*******************************************************************************
32
 * This function takes an SP context pointer and prepares the CPU to enter.
33
 ******************************************************************************/
34
static void spm_sp_prepare_enter(sp_context_t *sp_ctx)
35
{
36
	assert(sp_ctx != NULL);
37

38
39
	/* Assign the context of the SP to this CPU */
	cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
40

41
	/* Restore the context assigned above */
42
43
44
	cm_el1_sysregs_context_restore(SECURE);
	cm_set_next_eret_context(SECURE);

45
46
47
	/* Invalidate TLBs at EL1. */
	tlbivmalle1();
	dsbish();
48
49
50
}

/*******************************************************************************
51
 * Enter SP after preparing it with spm_sp_prepare_enter().
52
 ******************************************************************************/
53
static uint64_t spm_sp_enter(sp_context_t *sp_ctx)
54
{
55
56
	/* Enter Secure Partition */
	return spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
57
58
59
}

/*******************************************************************************
60
 * Jump to each Secure Partition for the first time.
61
 ******************************************************************************/
62
static int32_t spm_init(void)
63
{
64
	uint64_t rc = 0;
65
	sp_context_t *ctx;
66

67
	INFO("Secure Partition init...\n");
68

69
	ctx = &sp_ctx;
70

71
	ctx->sp_init_in_progress = 1;
72

73
74
75
	spm_sp_prepare_enter(ctx);
	rc |= spm_sp_enter(ctx);
	assert(rc == 0);
76

77
	ctx->sp_init_in_progress = 0;
78

79
	INFO("Secure Partition initialized.\n");
80

81
	return rc;
82
83
84
}

/*******************************************************************************
85
 * Initialize contexts of all Secure Partitions.
86
87
88
 ******************************************************************************/
int32_t spm_setup(void)
{
89
	sp_context_t *ctx;
90

91
92
93
94
95
96
97
	/* Disable MMU at EL1 (initialized by BL2) */
	disable_mmu_icache_el1();

	/* Initialize context of the SP */
	INFO("Secure Partition context setup start...\n");

	ctx = &sp_ctx;
98

99
100
	/* Assign translation tables context. */
	ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
101

102
	spm_sp_setup(ctx);
103
104

	/* Register init function for deferred init.  */
105
106
	bl31_register_bl32_init(&spm_init);

107
	INFO("Secure Partition setup done.\n");
108
109
110
111

	return 0;
}

112
113
114
/*******************************************************************************
 * Secure Partition Manager SMC handler.
 ******************************************************************************/
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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)
{
	cpu_context_t *ns_cpu_context;
	unsigned int ns;

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

	if (ns == SMC_FROM_SECURE) {

		/* Handle SMCs from Secure world. */

134
135
136
137
138
		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());

139
140
		switch (smc_fid) {

141
		case SPM_VERSION_AARCH32:
142
143
144
			SMC_RET1(handle, SPM_VERSION_COMPILED);

		case SP_EVENT_COMPLETE_AARCH64:
145
			/* Save secure state */
146
147
			cm_el1_sysregs_context_save(SECURE);

148
			if (sp_ctx.sp_init_in_progress == 1) {
149
150
151
152
153
154
155
				/*
				 * SPM reports completion. The SPM must have
				 * initiated the original request through a
				 * synchronous entry into the secure
				 * partition. Jump back to the original C
				 * runtime context.
				 */
156
157
158
				spm_secure_partition_exit(sp_ctx.c_rt_ctx, x1);

				/* spm_secure_partition_exit doesn't return */
159
160
			}

161
			/* Release the Secure Partition context */
162
			spin_unlock(&(sp_ctx.lock));
163

164
165
166
			/*
			 * This is the result from the Secure partition of an
			 * earlier request. Copy the result into the non-secure
167
			 * context and return to the non-secure state.
168
169
170
171
			 */

			/* Get a reference to the non-secure context */
			ns_cpu_context = cm_get_context(NON_SECURE);
172
			assert(ns_cpu_context != NULL);
173
174
175
176
177
178
179
180

			/* Restore non-secure state */
			cm_el1_sysregs_context_restore(NON_SECURE);
			cm_set_next_eret_context(NON_SECURE);

			/* Return to normal world */
			SMC_RET1(ns_cpu_context, x1);

181
182
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
183

184
			if (sp_ctx.sp_init_in_progress == 0) {
185
				WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
186
187
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
188
189
190
			SMC_RET1(handle,
				 spm_memory_attributes_get_smc_handler(
					 &sp_ctx, x1));
191

192
193
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
			INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
194

195
			if (sp_ctx.sp_init_in_progress == 0) {
196
				WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
197
198
				SMC_RET1(handle, SPM_NOT_SUPPORTED);
			}
199
200
201
			SMC_RET1(handle,
				 spm_memory_attributes_set_smc_handler(
					&sp_ctx, x1, x2, x3));
202
203
204
205
206
207
208
209
210
		default:
			break;
		}
	} else {

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

		switch (smc_fid) {

211
212
		case MM_VERSION_AARCH32:
			SMC_RET1(handle, MM_VERSION_COMPILED);
213

214
215
		case MM_COMMUNICATE_AARCH32:
		case MM_COMMUNICATE_AARCH64:
216
217
218
219
220
221
		{
			uint64_t mm_cookie = x1;
			uint64_t comm_buffer_address = x2;
			uint64_t comm_size_address = x3;

			/* Cookie. Reserved for future use. It must be zero. */
222
			if (mm_cookie != 0U) {
223
224
225
226
				ERROR("MM_COMMUNICATE: cookie is not zero\n");
				SMC_RET1(handle, SPM_INVALID_PARAMETER);
			}

227
			if (comm_buffer_address == 0U) {
228
229
230
231
				ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
				SMC_RET1(handle, SPM_INVALID_PARAMETER);
			}

232
			if (comm_size_address != 0U) {
233
234
				VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
			}
235
236
237
238

			/* Save the Normal world context */
			cm_el1_sysregs_context_save(NON_SECURE);

239
240
241
			/* Lock the Secure Partition context. */
			spin_lock(&sp_ctx.lock);

242
243
244
			/* Jump to the Secure Partition. */

			spm_sp_prepare_enter(&sp_ctx);
245

246
247
248
			SMC_RET4(&(sp_ctx.cpu_ctx), smc_fid,
				 comm_buffer_address, comm_size_address,
				 plat_my_core_pos());
249
		}
250

251
252
		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
253
254
255
256
257
258
259
260
261
262
			/* SMC interfaces reserved for secure callers. */
			SMC_RET1(handle, SPM_NOT_SUPPORTED);

		default:
			break;
		}
	}

	SMC_RET1(handle, SMC_UNK);
}