1 /*
2  * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <errno.h>
10 
11 #include <bl31/bl31.h>
12 #include <bl31/ehf.h>
13 #include <common/debug.h>
14 #include <common/runtime_svc.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/smccc.h>
17 #include <lib/spinlock.h>
18 #include <lib/utils.h>
19 #include <lib/xlat_tables/xlat_tables_v2.h>
20 #include <plat/common/platform.h>
21 #include <services/spm_mm_svc.h>
22 #include <smccc_helpers.h>
23 
24 #include "spm_common.h"
25 #include "spm_partition.h"
26 #include "spm_shim_private.h"
27 
28 /*******************************************************************************
29  * Secure Partition context information.
30  ******************************************************************************/
31 static sp_context_t sp_ctx;
32 
33 /*******************************************************************************
34  * Jump to each MM Secure Partition for the first time.
35  ******************************************************************************/
spm_init(void)36 static int32_t spm_init(void)
37 {
38 	uint64_t rc;
39 	sp_context_t *ctx;
40 
41 	INFO("Secure Partition init...\n");
42 
43 	ctx = &sp_ctx;
44 
45 	ctx->state = SP_STATE_RESET;
46 
47 	rc = spm_sp_synchronous_entry(ctx);
48 	assert(rc == 0);
49 
50 	ctx->state = SP_STATE_IDLE;
51 
52 	INFO("Secure Partition initialized.\n");
53 
54 	return !rc;
55 }
56 
57 /*******************************************************************************
58  * Initialize contexts of all MM Secure Partitions.
59  ******************************************************************************/
spm_mm_setup(void)60 int32_t spm_mm_setup(void)
61 {
62 	sp_context_t *ctx;
63 	cpu_context_t *cpu_ctx;
64 
65 	/* Disable MMU at EL1 (initialized by BL2) */
66 	disable_mmu_icache_el1();
67 
68 	/* Initialize context of the SP */
69 	INFO("Secure Partition context setup start...\n");
70 
71 	ctx = &sp_ctx;
72 	cpu_ctx = &(ctx->cpu_ctx);
73 
74 	/* Assign translation tables context. */
75 	ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
76 
77 	/* Pointer to the MP information from the platform port. */
78 	const spm_boot_info_t *sp_boot_info =
79 			plat_get_secure_partition_boot_info(NULL);
80 
81 	/*
82 	 * Initialize CPU context
83 	 * ----------------------
84 	 */
85 
86 	entry_point_info_t ep_info = {0};
87 
88 	SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE);
89 
90 	/* Setup entrypoint and SPSR */
91 	ep_info.pc = sp_boot_info->sp_image_base;
92 	ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS);
93 
94 	/*
95 	 * X0: Virtual address of a buffer shared between EL3 and Secure EL0.
96 	 *     The buffer will be mapped in the Secure EL1 translation regime
97 	 *     with Normal IS WBWA attributes and RO data and Execute Never
98 	 *     instruction access permissions.
99 	 *
100 	 * X1: Size of the buffer in bytes
101 	 *
102 	 * X2: cookie value (Implementation Defined)
103 	 *
104 	 * X3: cookie value (Implementation Defined)
105 	 *
106 	 * X4 to X7 = 0
107 	 */
108 	ep_info.args.arg0 = sp_boot_info->sp_shared_buf_base;
109 	ep_info.args.arg1 = sp_boot_info->sp_shared_buf_size;
110 	ep_info.args.arg2 = PLAT_SPM_COOKIE_0;
111 	ep_info.args.arg3 = PLAT_SPM_COOKIE_1;
112 
113 	cm_setup_context(cpu_ctx, &ep_info);
114 
115 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_SP_EL0,
116 			sp_boot_info->sp_stack_base + sp_boot_info->sp_pcpu_stack_size);
117 
118 #if ENABLE_ASSERTIONS
119 
120 	/* Get max granularity supported by the platform. */
121 	unsigned int max_granule = xlat_arch_get_max_supported_granule_size();
122 
123 	VERBOSE("Max translation granule size supported: %u KiB\n",
124 		max_granule / 1024U);
125 
126 	unsigned int max_granule_mask = max_granule - 1U;
127 
128 	/* Base must be aligned to the max granularity */
129 	assert((sp_boot_info->sp_ns_comm_buf_base & max_granule_mask) == 0);
130 
131 	/* Size must be a multiple of the max granularity */
132 	assert((sp_boot_info->sp_ns_comm_buf_size & max_granule_mask) == 0);
133 
134 #endif /* ENABLE_ASSERTIONS */
135 
136 	/* This region contains the exception vectors used at S-EL1. */
137 	const mmap_region_t sel1_exception_vectors =
138 		MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
139 				SPM_SHIM_EXCEPTIONS_SIZE,
140 				MT_CODE | MT_SECURE | MT_PRIVILEGED);
141 	mmap_add_region_ctx(ctx->xlat_ctx_handle,
142 			    &sel1_exception_vectors);
143 
144 	mmap_add_ctx(ctx->xlat_ctx_handle,
145 		     plat_get_secure_partition_mmap(NULL));
146 
147 	spm_el0_sp_setup(ctx);
148 
149 	/*
150 	 * Prepare information in buffer shared between EL3 and S-EL0
151 	 * ----------------------------------------------------------
152 	 */
153 
154 	void *shared_buf_ptr = (void *) sp_boot_info->sp_shared_buf_base;
155 
156 	/* Copy the boot information into the shared buffer with the SP. */
157 	assert((uintptr_t)shared_buf_ptr + sizeof(spm_boot_info_t)
158 	       <= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_buf_size));
159 
160 	assert(sp_boot_info->sp_shared_buf_base <=
161 				(UINTPTR_MAX - sp_boot_info->sp_shared_buf_size + 1));
162 
163 	assert(sp_boot_info != NULL);
164 
165 	memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
166 	       sizeof(spm_boot_info_t));
167 
168 	/* Pointer to the MP information from the platform port. */
169 	spm_mp_info_t *sp_mp_info =
170 		((spm_boot_info_t *) shared_buf_ptr)->mp_info;
171 
172 	assert(sp_mp_info != NULL);
173 
174 	/*
175 	 * Point the shared buffer MP information pointer to where the info will
176 	 * be populated, just after the boot info.
177 	 */
178 	((spm_boot_info_t *) shared_buf_ptr)->mp_info =
179 		(spm_mp_info_t *) ((uintptr_t)shared_buf_ptr
180 				+ sizeof(spm_boot_info_t));
181 
182 	/*
183 	 * Update the shared buffer pointer to where the MP information for the
184 	 * payload will be populated
185 	 */
186 	shared_buf_ptr = ((spm_boot_info_t *) shared_buf_ptr)->mp_info;
187 
188 	/*
189 	 * Copy the cpu information into the shared buffer area after the boot
190 	 * information.
191 	 */
192 	assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT);
193 
194 	assert((uintptr_t)shared_buf_ptr
195 	       <= (sp_boot_info->sp_shared_buf_base + sp_boot_info->sp_shared_buf_size -
196 		       (sp_boot_info->num_cpus * sizeof(*sp_mp_info))));
197 
198 	memcpy(shared_buf_ptr, (const void *) sp_mp_info,
199 		sp_boot_info->num_cpus * sizeof(*sp_mp_info));
200 
201 	/*
202 	 * Calculate the linear indices of cores in boot information for the
203 	 * secure partition and flag the primary CPU
204 	 */
205 	sp_mp_info = (spm_mp_info_t *) shared_buf_ptr;
206 
207 	for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) {
208 		u_register_t mpidr = sp_mp_info[index].mpidr;
209 
210 		sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr);
211 		if (plat_my_core_pos() == sp_mp_info[index].linear_id)
212 			sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
213 	}
214 
215 	/* Register init function for deferred init.  */
216 	bl31_register_bl32_init(&spm_init);
217 
218 	INFO("Secure Partition setup done.\n");
219 
220 	return 0;
221 }
222 
223 /*******************************************************************************
224  * Function to perform a call to a MM Secure Partition.
225  ******************************************************************************/
spm_mm_sp_call(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3)226 uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
227 {
228 	uint64_t rc;
229 	sp_context_t *sp_ptr = &sp_ctx;
230 
231 	/* Wait until the Secure Partition is idle and set it to busy. */
232 	sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
233 
234 	/* Set values for registers on SP entry */
235 	cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
236 
237 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
238 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
239 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
240 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
241 
242 	/* Jump to the Secure Partition. */
243 	rc = spm_sp_synchronous_entry(sp_ptr);
244 
245 	/* Flag Secure Partition as idle. */
246 	assert(sp_ptr->state == SP_STATE_BUSY);
247 	sp_state_set(sp_ptr, SP_STATE_IDLE);
248 
249 	return rc;
250 }
251 
252 /*******************************************************************************
253  * MM_COMMUNICATE handler
254  ******************************************************************************/
mm_communicate(uint32_t smc_fid,uint64_t mm_cookie,uint64_t comm_buffer_address,uint64_t comm_size_address,void * handle)255 static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
256 			       uint64_t comm_buffer_address,
257 			       uint64_t comm_size_address, void *handle)
258 {
259 	uint64_t rc;
260 
261 	/* Cookie. Reserved for future use. It must be zero. */
262 	if (mm_cookie != 0U) {
263 		ERROR("MM_COMMUNICATE: cookie is not zero\n");
264 		SMC_RET1(handle, SPM_INVALID_PARAMETER);
265 	}
266 
267 	if (comm_buffer_address == 0U) {
268 		ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
269 		SMC_RET1(handle, SPM_INVALID_PARAMETER);
270 	}
271 
272 	if (comm_size_address != 0U) {
273 		VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
274 	}
275 
276 	/*
277 	 * The current secure partition design mandates
278 	 * - at any point, only a single core can be
279 	 *   executing in the secure partiton.
280 	 * - a core cannot be preempted by an interrupt
281 	 *   while executing in secure partition.
282 	 * Raise the running priority of the core to the
283 	 * interrupt level configured for secure partition
284 	 * so as to block any interrupt from preempting this
285 	 * core.
286 	 */
287 	ehf_activate_priority(PLAT_SP_PRI);
288 
289 	/* Save the Normal world context */
290 	cm_el1_sysregs_context_save(NON_SECURE);
291 
292 	rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
293 			    plat_my_core_pos());
294 
295 	/* Restore non-secure state */
296 	cm_el1_sysregs_context_restore(NON_SECURE);
297 	cm_set_next_eret_context(NON_SECURE);
298 
299 	/*
300 	 * Exited from secure partition. This core can take
301 	 * interrupts now.
302 	 */
303 	ehf_deactivate_priority(PLAT_SP_PRI);
304 
305 	SMC_RET1(handle, rc);
306 }
307 
308 /*******************************************************************************
309  * MM Secure Partition Manager SMC handler.
310  ******************************************************************************/
spm_mm_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)311 uint64_t spm_mm_smc_handler(uint32_t smc_fid,
312 			 uint64_t x1,
313 			 uint64_t x2,
314 			 uint64_t x3,
315 			 uint64_t x4,
316 			 void *cookie,
317 			 void *handle,
318 			 uint64_t flags)
319 {
320 	unsigned int ns;
321 
322 	/* Determine which security state this SMC originated from */
323 	ns = is_caller_non_secure(flags);
324 
325 	if (ns == SMC_FROM_SECURE) {
326 
327 		/* Handle SMCs from Secure world. */
328 
329 		assert(handle == cm_get_context(SECURE));
330 
331 		/* Make next ERET jump to S-EL0 instead of S-EL1. */
332 		cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
333 
334 		switch (smc_fid) {
335 
336 		case SPM_MM_VERSION_AARCH32:
337 			SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
338 
339 		case MM_SP_EVENT_COMPLETE_AARCH64:
340 			spm_sp_synchronous_exit(&sp_ctx, x1);
341 
342 		case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
343 			INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
344 
345 			if (sp_ctx.state != SP_STATE_RESET) {
346 				WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
347 				SMC_RET1(handle, SPM_NOT_SUPPORTED);
348 			}
349 			SMC_RET1(handle,
350 				 spm_memory_attributes_get_smc_handler(
351 					 &sp_ctx, x1));
352 
353 		case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
354 			INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
355 
356 			if (sp_ctx.state != SP_STATE_RESET) {
357 				WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
358 				SMC_RET1(handle, SPM_NOT_SUPPORTED);
359 			}
360 			SMC_RET1(handle,
361 				 spm_memory_attributes_set_smc_handler(
362 					&sp_ctx, x1, x2, x3));
363 		default:
364 			break;
365 		}
366 	} else {
367 
368 		/* Handle SMCs from Non-secure world. */
369 
370 		assert(handle == cm_get_context(NON_SECURE));
371 
372 		switch (smc_fid) {
373 
374 		case MM_VERSION_AARCH32:
375 			SMC_RET1(handle, MM_VERSION_COMPILED);
376 
377 		case MM_COMMUNICATE_AARCH32:
378 		case MM_COMMUNICATE_AARCH64:
379 			return mm_communicate(smc_fid, x1, x2, x3, handle);
380 
381 		case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
382 		case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
383 			/* SMC interfaces reserved for secure callers. */
384 			SMC_RET1(handle, SPM_NOT_SUPPORTED);
385 
386 		default:
387 			break;
388 		}
389 	}
390 
391 	SMC_RET1(handle, SMC_UNK);
392 }
393