xref: /arm-trusted-firmware/services/std_svc/spm/spm_mm/spm_mm_main.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <arch_helpers.h>
8*91f16700Schasinglulu #include <assert.h>
9*91f16700Schasinglulu #include <errno.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <bl31/bl31.h>
12*91f16700Schasinglulu #include <bl31/ehf.h>
13*91f16700Schasinglulu #include <common/debug.h>
14*91f16700Schasinglulu #include <common/runtime_svc.h>
15*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h>
16*91f16700Schasinglulu #include <lib/smccc.h>
17*91f16700Schasinglulu #include <lib/spinlock.h>
18*91f16700Schasinglulu #include <lib/utils.h>
19*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
20*91f16700Schasinglulu #include <plat/common/platform.h>
21*91f16700Schasinglulu #include <services/spm_mm_partition.h>
22*91f16700Schasinglulu #include <services/spm_mm_svc.h>
23*91f16700Schasinglulu #include <smccc_helpers.h>
24*91f16700Schasinglulu 
25*91f16700Schasinglulu #include "spm_common.h"
26*91f16700Schasinglulu #include "spm_mm_private.h"
27*91f16700Schasinglulu 
28*91f16700Schasinglulu /*******************************************************************************
29*91f16700Schasinglulu  * Secure Partition context information.
30*91f16700Schasinglulu  ******************************************************************************/
31*91f16700Schasinglulu static sp_context_t sp_ctx;
32*91f16700Schasinglulu 
33*91f16700Schasinglulu /*******************************************************************************
34*91f16700Schasinglulu  * Set state of a Secure Partition context.
35*91f16700Schasinglulu  ******************************************************************************/
36*91f16700Schasinglulu void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
37*91f16700Schasinglulu {
38*91f16700Schasinglulu 	spin_lock(&(sp_ptr->state_lock));
39*91f16700Schasinglulu 	sp_ptr->state = state;
40*91f16700Schasinglulu 	spin_unlock(&(sp_ptr->state_lock));
41*91f16700Schasinglulu }
42*91f16700Schasinglulu 
43*91f16700Schasinglulu /*******************************************************************************
44*91f16700Schasinglulu  * Wait until the state of a Secure Partition is the specified one and change it
45*91f16700Schasinglulu  * to the desired state.
46*91f16700Schasinglulu  ******************************************************************************/
47*91f16700Schasinglulu void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
48*91f16700Schasinglulu {
49*91f16700Schasinglulu 	int success = 0;
50*91f16700Schasinglulu 
51*91f16700Schasinglulu 	while (success == 0) {
52*91f16700Schasinglulu 		spin_lock(&(sp_ptr->state_lock));
53*91f16700Schasinglulu 
54*91f16700Schasinglulu 		if (sp_ptr->state == from) {
55*91f16700Schasinglulu 			sp_ptr->state = to;
56*91f16700Schasinglulu 
57*91f16700Schasinglulu 			success = 1;
58*91f16700Schasinglulu 		}
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 		spin_unlock(&(sp_ptr->state_lock));
61*91f16700Schasinglulu 	}
62*91f16700Schasinglulu }
63*91f16700Schasinglulu 
64*91f16700Schasinglulu /*******************************************************************************
65*91f16700Schasinglulu  * Check if the state of a Secure Partition is the specified one and, if so,
66*91f16700Schasinglulu  * change it to the desired state. Returns 0 on success, -1 on error.
67*91f16700Schasinglulu  ******************************************************************************/
68*91f16700Schasinglulu int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	int ret = -1;
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	spin_lock(&(sp_ptr->state_lock));
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	if (sp_ptr->state == from) {
75*91f16700Schasinglulu 		sp_ptr->state = to;
76*91f16700Schasinglulu 
77*91f16700Schasinglulu 		ret = 0;
78*91f16700Schasinglulu 	}
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	spin_unlock(&(sp_ptr->state_lock));
81*91f16700Schasinglulu 
82*91f16700Schasinglulu 	return ret;
83*91f16700Schasinglulu }
84*91f16700Schasinglulu 
85*91f16700Schasinglulu /*******************************************************************************
86*91f16700Schasinglulu  * This function takes an SP context pointer and performs a synchronous entry
87*91f16700Schasinglulu  * into it.
88*91f16700Schasinglulu  ******************************************************************************/
89*91f16700Schasinglulu static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
90*91f16700Schasinglulu {
91*91f16700Schasinglulu 	uint64_t rc;
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	assert(ctx != NULL);
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	/* Assign the context of the SP to this CPU */
96*91f16700Schasinglulu 	cm_set_context(&(ctx->cpu_ctx), SECURE);
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	/* Restore the context assigned above */
99*91f16700Schasinglulu 	cm_el1_sysregs_context_restore(SECURE);
100*91f16700Schasinglulu 	cm_set_next_eret_context(SECURE);
101*91f16700Schasinglulu 
102*91f16700Schasinglulu 	/* Invalidate TLBs at EL1. */
103*91f16700Schasinglulu 	tlbivmalle1();
104*91f16700Schasinglulu 	dsbish();
105*91f16700Schasinglulu 
106*91f16700Schasinglulu 	/* Enter Secure Partition */
107*91f16700Schasinglulu 	rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	/* Save secure state */
110*91f16700Schasinglulu 	cm_el1_sysregs_context_save(SECURE);
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	return rc;
113*91f16700Schasinglulu }
114*91f16700Schasinglulu 
115*91f16700Schasinglulu /*******************************************************************************
116*91f16700Schasinglulu  * This function returns to the place where spm_sp_synchronous_entry() was
117*91f16700Schasinglulu  * called originally.
118*91f16700Schasinglulu  ******************************************************************************/
119*91f16700Schasinglulu __dead2 static void spm_sp_synchronous_exit(uint64_t rc)
120*91f16700Schasinglulu {
121*91f16700Schasinglulu 	sp_context_t *ctx = &sp_ctx;
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	/*
124*91f16700Schasinglulu 	 * The SPM must have initiated the original request through a
125*91f16700Schasinglulu 	 * synchronous entry into the secure partition. Jump back to the
126*91f16700Schasinglulu 	 * original C runtime context with the value of rc in x0;
127*91f16700Schasinglulu 	 */
128*91f16700Schasinglulu 	spm_secure_partition_exit(ctx->c_rt_ctx, rc);
129*91f16700Schasinglulu 
130*91f16700Schasinglulu 	panic();
131*91f16700Schasinglulu }
132*91f16700Schasinglulu 
133*91f16700Schasinglulu /*******************************************************************************
134*91f16700Schasinglulu  * Jump to each Secure Partition for the first time.
135*91f16700Schasinglulu  ******************************************************************************/
136*91f16700Schasinglulu static int32_t spm_init(void)
137*91f16700Schasinglulu {
138*91f16700Schasinglulu 	uint64_t rc;
139*91f16700Schasinglulu 	sp_context_t *ctx;
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 	INFO("Secure Partition init...\n");
142*91f16700Schasinglulu 
143*91f16700Schasinglulu 	ctx = &sp_ctx;
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	ctx->state = SP_STATE_RESET;
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 	rc = spm_sp_synchronous_entry(ctx);
148*91f16700Schasinglulu 	assert(rc == 0);
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 	ctx->state = SP_STATE_IDLE;
151*91f16700Schasinglulu 
152*91f16700Schasinglulu 	INFO("Secure Partition initialized.\n");
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	return !rc;
155*91f16700Schasinglulu }
156*91f16700Schasinglulu 
157*91f16700Schasinglulu /*******************************************************************************
158*91f16700Schasinglulu  * Initialize contexts of all Secure Partitions.
159*91f16700Schasinglulu  ******************************************************************************/
160*91f16700Schasinglulu int32_t spm_mm_setup(void)
161*91f16700Schasinglulu {
162*91f16700Schasinglulu 	sp_context_t *ctx;
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/* Disable MMU at EL1 (initialized by BL2) */
165*91f16700Schasinglulu 	disable_mmu_icache_el1();
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 	/* Initialize context of the SP */
168*91f16700Schasinglulu 	INFO("Secure Partition context setup start...\n");
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 	ctx = &sp_ctx;
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	/* Assign translation tables context. */
173*91f16700Schasinglulu 	ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	spm_sp_setup(ctx);
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	/* Register init function for deferred init.  */
178*91f16700Schasinglulu 	bl31_register_bl32_init(&spm_init);
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	INFO("Secure Partition setup done.\n");
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	return 0;
183*91f16700Schasinglulu }
184*91f16700Schasinglulu 
185*91f16700Schasinglulu /*******************************************************************************
186*91f16700Schasinglulu  * Function to perform a call to a Secure Partition.
187*91f16700Schasinglulu  ******************************************************************************/
188*91f16700Schasinglulu uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
189*91f16700Schasinglulu {
190*91f16700Schasinglulu 	uint64_t rc;
191*91f16700Schasinglulu 	sp_context_t *sp_ptr = &sp_ctx;
192*91f16700Schasinglulu 
193*91f16700Schasinglulu #if CTX_INCLUDE_FPREGS
194*91f16700Schasinglulu 	/*
195*91f16700Schasinglulu 	 * SP runs to completion, no need to restore FP registers of secure context.
196*91f16700Schasinglulu 	 * Save FP registers only for non secure context.
197*91f16700Schasinglulu 	 */
198*91f16700Schasinglulu 	fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
199*91f16700Schasinglulu #endif
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	/* Wait until the Secure Partition is idle and set it to busy. */
202*91f16700Schasinglulu 	sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	/* Set values for registers on SP entry */
205*91f16700Schasinglulu 	cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
208*91f16700Schasinglulu 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
209*91f16700Schasinglulu 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
210*91f16700Schasinglulu 	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 	/* Jump to the Secure Partition. */
213*91f16700Schasinglulu 	rc = spm_sp_synchronous_entry(sp_ptr);
214*91f16700Schasinglulu 
215*91f16700Schasinglulu 	/* Flag Secure Partition as idle. */
216*91f16700Schasinglulu 	assert(sp_ptr->state == SP_STATE_BUSY);
217*91f16700Schasinglulu 	sp_state_set(sp_ptr, SP_STATE_IDLE);
218*91f16700Schasinglulu 
219*91f16700Schasinglulu #if CTX_INCLUDE_FPREGS
220*91f16700Schasinglulu 	/*
221*91f16700Schasinglulu 	 * SP runs to completion, no need to save FP registers of secure context.
222*91f16700Schasinglulu 	 * Restore only non secure world FP registers.
223*91f16700Schasinglulu 	 */
224*91f16700Schasinglulu 	fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
225*91f16700Schasinglulu #endif
226*91f16700Schasinglulu 
227*91f16700Schasinglulu 	return rc;
228*91f16700Schasinglulu }
229*91f16700Schasinglulu 
230*91f16700Schasinglulu /*******************************************************************************
231*91f16700Schasinglulu  * MM_COMMUNICATE handler
232*91f16700Schasinglulu  ******************************************************************************/
233*91f16700Schasinglulu static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
234*91f16700Schasinglulu 			       uint64_t comm_buffer_address,
235*91f16700Schasinglulu 			       uint64_t comm_size_address, void *handle)
236*91f16700Schasinglulu {
237*91f16700Schasinglulu 	uint64_t rc;
238*91f16700Schasinglulu 
239*91f16700Schasinglulu 	/* Cookie. Reserved for future use. It must be zero. */
240*91f16700Schasinglulu 	if (mm_cookie != 0U) {
241*91f16700Schasinglulu 		ERROR("MM_COMMUNICATE: cookie is not zero\n");
242*91f16700Schasinglulu 		SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
243*91f16700Schasinglulu 	}
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	if (comm_buffer_address == 0U) {
246*91f16700Schasinglulu 		ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
247*91f16700Schasinglulu 		SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
248*91f16700Schasinglulu 	}
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	if (comm_size_address != 0U) {
251*91f16700Schasinglulu 		VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
252*91f16700Schasinglulu 	}
253*91f16700Schasinglulu 
254*91f16700Schasinglulu 	/*
255*91f16700Schasinglulu 	 * The current secure partition design mandates
256*91f16700Schasinglulu 	 * - at any point, only a single core can be
257*91f16700Schasinglulu 	 *   executing in the secure partition.
258*91f16700Schasinglulu 	 * - a core cannot be preempted by an interrupt
259*91f16700Schasinglulu 	 *   while executing in secure partition.
260*91f16700Schasinglulu 	 * Raise the running priority of the core to the
261*91f16700Schasinglulu 	 * interrupt level configured for secure partition
262*91f16700Schasinglulu 	 * so as to block any interrupt from preempting this
263*91f16700Schasinglulu 	 * core.
264*91f16700Schasinglulu 	 */
265*91f16700Schasinglulu 	ehf_activate_priority(PLAT_SP_PRI);
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	/* Save the Normal world context */
268*91f16700Schasinglulu 	cm_el1_sysregs_context_save(NON_SECURE);
269*91f16700Schasinglulu 
270*91f16700Schasinglulu 	rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
271*91f16700Schasinglulu 			    plat_my_core_pos());
272*91f16700Schasinglulu 
273*91f16700Schasinglulu 	/* Restore non-secure state */
274*91f16700Schasinglulu 	cm_el1_sysregs_context_restore(NON_SECURE);
275*91f16700Schasinglulu 	cm_set_next_eret_context(NON_SECURE);
276*91f16700Schasinglulu 
277*91f16700Schasinglulu 	/*
278*91f16700Schasinglulu 	 * Exited from secure partition. This core can take
279*91f16700Schasinglulu 	 * interrupts now.
280*91f16700Schasinglulu 	 */
281*91f16700Schasinglulu 	ehf_deactivate_priority(PLAT_SP_PRI);
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	SMC_RET1(handle, rc);
284*91f16700Schasinglulu }
285*91f16700Schasinglulu 
286*91f16700Schasinglulu /*******************************************************************************
287*91f16700Schasinglulu  * Secure Partition Manager SMC handler.
288*91f16700Schasinglulu  ******************************************************************************/
289*91f16700Schasinglulu uint64_t spm_mm_smc_handler(uint32_t smc_fid,
290*91f16700Schasinglulu 			 uint64_t x1,
291*91f16700Schasinglulu 			 uint64_t x2,
292*91f16700Schasinglulu 			 uint64_t x3,
293*91f16700Schasinglulu 			 uint64_t x4,
294*91f16700Schasinglulu 			 void *cookie,
295*91f16700Schasinglulu 			 void *handle,
296*91f16700Schasinglulu 			 uint64_t flags)
297*91f16700Schasinglulu {
298*91f16700Schasinglulu 	unsigned int ns;
299*91f16700Schasinglulu 
300*91f16700Schasinglulu 	/* Determine which security state this SMC originated from */
301*91f16700Schasinglulu 	ns = is_caller_non_secure(flags);
302*91f16700Schasinglulu 
303*91f16700Schasinglulu 	if (ns == SMC_FROM_SECURE) {
304*91f16700Schasinglulu 
305*91f16700Schasinglulu 		/* Handle SMCs from Secure world. */
306*91f16700Schasinglulu 
307*91f16700Schasinglulu 		assert(handle == cm_get_context(SECURE));
308*91f16700Schasinglulu 
309*91f16700Schasinglulu 		/* Make next ERET jump to S-EL0 instead of S-EL1. */
310*91f16700Schasinglulu 		cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
311*91f16700Schasinglulu 
312*91f16700Schasinglulu 		switch (smc_fid) {
313*91f16700Schasinglulu 
314*91f16700Schasinglulu 		case SPM_MM_VERSION_AARCH32:
315*91f16700Schasinglulu 			SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 		case MM_SP_EVENT_COMPLETE_AARCH64:
318*91f16700Schasinglulu 			spm_sp_synchronous_exit(x1);
319*91f16700Schasinglulu 
320*91f16700Schasinglulu 		case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
321*91f16700Schasinglulu 			INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
322*91f16700Schasinglulu 
323*91f16700Schasinglulu 			if (sp_ctx.state != SP_STATE_RESET) {
324*91f16700Schasinglulu 				WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
325*91f16700Schasinglulu 				SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
326*91f16700Schasinglulu 			}
327*91f16700Schasinglulu 			SMC_RET1(handle,
328*91f16700Schasinglulu 				 spm_memory_attributes_get_smc_handler(
329*91f16700Schasinglulu 					 &sp_ctx, x1));
330*91f16700Schasinglulu 
331*91f16700Schasinglulu 		case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
332*91f16700Schasinglulu 			INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
333*91f16700Schasinglulu 
334*91f16700Schasinglulu 			if (sp_ctx.state != SP_STATE_RESET) {
335*91f16700Schasinglulu 				WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
336*91f16700Schasinglulu 				SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
337*91f16700Schasinglulu 			}
338*91f16700Schasinglulu 			SMC_RET1(handle,
339*91f16700Schasinglulu 				 spm_memory_attributes_set_smc_handler(
340*91f16700Schasinglulu 					&sp_ctx, x1, x2, x3));
341*91f16700Schasinglulu 		default:
342*91f16700Schasinglulu 			break;
343*91f16700Schasinglulu 		}
344*91f16700Schasinglulu 	} else {
345*91f16700Schasinglulu 
346*91f16700Schasinglulu 		/* Handle SMCs from Non-secure world. */
347*91f16700Schasinglulu 
348*91f16700Schasinglulu 		assert(handle == cm_get_context(NON_SECURE));
349*91f16700Schasinglulu 
350*91f16700Schasinglulu 		switch (smc_fid) {
351*91f16700Schasinglulu 
352*91f16700Schasinglulu 		case MM_VERSION_AARCH32:
353*91f16700Schasinglulu 			SMC_RET1(handle, MM_VERSION_COMPILED);
354*91f16700Schasinglulu 
355*91f16700Schasinglulu 		case MM_COMMUNICATE_AARCH32:
356*91f16700Schasinglulu 		case MM_COMMUNICATE_AARCH64:
357*91f16700Schasinglulu 			return mm_communicate(smc_fid, x1, x2, x3, handle);
358*91f16700Schasinglulu 
359*91f16700Schasinglulu 		case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
360*91f16700Schasinglulu 		case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
361*91f16700Schasinglulu 			/* SMC interfaces reserved for secure callers. */
362*91f16700Schasinglulu 			SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
363*91f16700Schasinglulu 
364*91f16700Schasinglulu 		default:
365*91f16700Schasinglulu 			break;
366*91f16700Schasinglulu 		}
367*91f16700Schasinglulu 	}
368*91f16700Schasinglulu 
369*91f16700Schasinglulu 	SMC_RET1(handle, SMC_UNK);
370*91f16700Schasinglulu }
371