xref: /arm-trusted-firmware/services/std_svc/rmmd/rmmd_main.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <inttypes.h>
10*91f16700Schasinglulu #include <stdint.h>
11*91f16700Schasinglulu #include <string.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <arch_helpers.h>
14*91f16700Schasinglulu #include <arch_features.h>
15*91f16700Schasinglulu #include <bl31/bl31.h>
16*91f16700Schasinglulu #include <common/debug.h>
17*91f16700Schasinglulu #include <common/runtime_svc.h>
18*91f16700Schasinglulu #include <context.h>
19*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h>
20*91f16700Schasinglulu #include <lib/el3_runtime/cpu_data.h>
21*91f16700Schasinglulu #include <lib/el3_runtime/pubsub.h>
22*91f16700Schasinglulu #include <lib/extensions/pmuv3.h>
23*91f16700Schasinglulu #include <lib/extensions/sys_reg_trace.h>
24*91f16700Schasinglulu #include <lib/gpt_rme/gpt_rme.h>
25*91f16700Schasinglulu 
26*91f16700Schasinglulu #include <lib/spinlock.h>
27*91f16700Schasinglulu #include <lib/utils.h>
28*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
29*91f16700Schasinglulu #include <plat/common/common_def.h>
30*91f16700Schasinglulu #include <plat/common/platform.h>
31*91f16700Schasinglulu #include <platform_def.h>
32*91f16700Schasinglulu #include <services/rmmd_svc.h>
33*91f16700Schasinglulu #include <smccc_helpers.h>
34*91f16700Schasinglulu #include <lib/extensions/sme.h>
35*91f16700Schasinglulu #include <lib/extensions/sve.h>
36*91f16700Schasinglulu #include "rmmd_initial_context.h"
37*91f16700Schasinglulu #include "rmmd_private.h"
38*91f16700Schasinglulu 
39*91f16700Schasinglulu /*******************************************************************************
40*91f16700Schasinglulu  * RMM boot failure flag
41*91f16700Schasinglulu  ******************************************************************************/
42*91f16700Schasinglulu static bool rmm_boot_failed;
43*91f16700Schasinglulu 
44*91f16700Schasinglulu /*******************************************************************************
45*91f16700Schasinglulu  * RMM context information.
46*91f16700Schasinglulu  ******************************************************************************/
47*91f16700Schasinglulu rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT];
48*91f16700Schasinglulu 
49*91f16700Schasinglulu /*******************************************************************************
50*91f16700Schasinglulu  * RMM entry point information. Discovered on the primary core and reused
51*91f16700Schasinglulu  * on secondary cores.
52*91f16700Schasinglulu  ******************************************************************************/
53*91f16700Schasinglulu static entry_point_info_t *rmm_ep_info;
54*91f16700Schasinglulu 
55*91f16700Schasinglulu /*******************************************************************************
56*91f16700Schasinglulu  * Static function declaration.
57*91f16700Schasinglulu  ******************************************************************************/
58*91f16700Schasinglulu static int32_t rmm_init(void);
59*91f16700Schasinglulu 
60*91f16700Schasinglulu /*******************************************************************************
61*91f16700Schasinglulu  * This function takes an RMM context pointer and performs a synchronous entry
62*91f16700Schasinglulu  * into it.
63*91f16700Schasinglulu  ******************************************************************************/
64*91f16700Schasinglulu uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx)
65*91f16700Schasinglulu {
66*91f16700Schasinglulu 	uint64_t rc;
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	assert(rmm_ctx != NULL);
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 	cm_set_context(&(rmm_ctx->cpu_ctx), REALM);
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	/* Restore the realm context assigned above */
73*91f16700Schasinglulu 	cm_el1_sysregs_context_restore(REALM);
74*91f16700Schasinglulu 	cm_el2_sysregs_context_restore(REALM);
75*91f16700Schasinglulu 	cm_set_next_eret_context(REALM);
76*91f16700Schasinglulu 
77*91f16700Schasinglulu 	/* Enter RMM */
78*91f16700Schasinglulu 	rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx);
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	/*
81*91f16700Schasinglulu 	 * Save realm context. EL1 and EL2 Non-secure
82*91f16700Schasinglulu 	 * contexts will be restored before exiting to
83*91f16700Schasinglulu 	 * Non-secure world, therefore there is no need
84*91f16700Schasinglulu 	 * to clear EL1 and EL2 context registers.
85*91f16700Schasinglulu 	 */
86*91f16700Schasinglulu 	cm_el1_sysregs_context_save(REALM);
87*91f16700Schasinglulu 	cm_el2_sysregs_context_save(REALM);
88*91f16700Schasinglulu 
89*91f16700Schasinglulu 	return rc;
90*91f16700Schasinglulu }
91*91f16700Schasinglulu 
92*91f16700Schasinglulu /*******************************************************************************
93*91f16700Schasinglulu  * This function returns to the place where rmmd_rmm_sync_entry() was
94*91f16700Schasinglulu  * called originally.
95*91f16700Schasinglulu  ******************************************************************************/
96*91f16700Schasinglulu __dead2 void rmmd_rmm_sync_exit(uint64_t rc)
97*91f16700Schasinglulu {
98*91f16700Schasinglulu 	rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	/* Get context of the RMM in use by this CPU. */
101*91f16700Schasinglulu 	assert(cm_get_context(REALM) == &(ctx->cpu_ctx));
102*91f16700Schasinglulu 
103*91f16700Schasinglulu 	/*
104*91f16700Schasinglulu 	 * The RMMD must have initiated the original request through a
105*91f16700Schasinglulu 	 * synchronous entry into RMM. Jump back to the original C runtime
106*91f16700Schasinglulu 	 * context with the value of rc in x0;
107*91f16700Schasinglulu 	 */
108*91f16700Schasinglulu 	rmmd_rmm_exit(ctx->c_rt_ctx, rc);
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	panic();
111*91f16700Schasinglulu }
112*91f16700Schasinglulu 
113*91f16700Schasinglulu static void rmm_el2_context_init(el2_sysregs_t *regs)
114*91f16700Schasinglulu {
115*91f16700Schasinglulu 	regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2;
116*91f16700Schasinglulu 	regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1;
117*91f16700Schasinglulu }
118*91f16700Schasinglulu 
119*91f16700Schasinglulu /*******************************************************************************
120*91f16700Schasinglulu  * Enable architecture extensions on first entry to Realm world.
121*91f16700Schasinglulu  ******************************************************************************/
122*91f16700Schasinglulu 
123*91f16700Schasinglulu static void manage_extensions_realm(cpu_context_t *ctx)
124*91f16700Schasinglulu {
125*91f16700Schasinglulu 	pmuv3_enable(ctx);
126*91f16700Schasinglulu 
127*91f16700Schasinglulu 	/*
128*91f16700Schasinglulu 	 * Enable access to TPIDR2_EL0 if SME/SME2 is enabled for Non Secure world.
129*91f16700Schasinglulu 	 */
130*91f16700Schasinglulu 	if (is_feat_sme_supported()) {
131*91f16700Schasinglulu 		sme_enable(ctx);
132*91f16700Schasinglulu 	}
133*91f16700Schasinglulu }
134*91f16700Schasinglulu 
135*91f16700Schasinglulu static void manage_extensions_realm_per_world(void)
136*91f16700Schasinglulu {
137*91f16700Schasinglulu 	if (is_feat_sve_supported()) {
138*91f16700Schasinglulu 	/*
139*91f16700Schasinglulu 	 * Enable SVE and FPU in realm context when it is enabled for NS.
140*91f16700Schasinglulu 	 * Realm manager must ensure that the SVE and FPU register
141*91f16700Schasinglulu 	 * contexts are properly managed.
142*91f16700Schasinglulu 	 */
143*91f16700Schasinglulu 		sve_enable_per_world(&per_world_context[CPU_CONTEXT_REALM]);
144*91f16700Schasinglulu 	}
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 	/* NS can access this but Realm shouldn't */
147*91f16700Schasinglulu 	if (is_feat_sys_reg_trace_supported()) {
148*91f16700Schasinglulu 		sys_reg_trace_disable_per_world(&per_world_context[CPU_CONTEXT_REALM]);
149*91f16700Schasinglulu 	}
150*91f16700Schasinglulu 
151*91f16700Schasinglulu 	/*
152*91f16700Schasinglulu 	 * If SME/SME2 is supported and enabled for NS world, then disable trapping
153*91f16700Schasinglulu 	 * of SME instructions for Realm world. RMM will save/restore required
154*91f16700Schasinglulu 	 * registers that are shared with SVE/FPU so that Realm can use FPU or SVE.
155*91f16700Schasinglulu 	 */
156*91f16700Schasinglulu 	if (is_feat_sme_supported()) {
157*91f16700Schasinglulu 		sme_enable_per_world(&per_world_context[CPU_CONTEXT_REALM]);
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu }
160*91f16700Schasinglulu 
161*91f16700Schasinglulu /*******************************************************************************
162*91f16700Schasinglulu  * Jump to the RMM for the first time.
163*91f16700Schasinglulu  ******************************************************************************/
164*91f16700Schasinglulu static int32_t rmm_init(void)
165*91f16700Schasinglulu {
166*91f16700Schasinglulu 	long rc;
167*91f16700Schasinglulu 	rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
168*91f16700Schasinglulu 
169*91f16700Schasinglulu 	INFO("RMM init start.\n");
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	/* Enable architecture extensions */
172*91f16700Schasinglulu 	manage_extensions_realm(&ctx->cpu_ctx);
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	manage_extensions_realm_per_world();
175*91f16700Schasinglulu 
176*91f16700Schasinglulu 	/* Initialize RMM EL2 context. */
177*91f16700Schasinglulu 	rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
178*91f16700Schasinglulu 
179*91f16700Schasinglulu 	rc = rmmd_rmm_sync_entry(ctx);
180*91f16700Schasinglulu 	if (rc != E_RMM_BOOT_SUCCESS) {
181*91f16700Schasinglulu 		ERROR("RMM init failed: %ld\n", rc);
182*91f16700Schasinglulu 		/* Mark the boot as failed for all the CPUs */
183*91f16700Schasinglulu 		rmm_boot_failed = true;
184*91f16700Schasinglulu 		return 0;
185*91f16700Schasinglulu 	}
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	INFO("RMM init end.\n");
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	return 1;
190*91f16700Schasinglulu }
191*91f16700Schasinglulu 
192*91f16700Schasinglulu /*******************************************************************************
193*91f16700Schasinglulu  * Load and read RMM manifest, setup RMM.
194*91f16700Schasinglulu  ******************************************************************************/
195*91f16700Schasinglulu int rmmd_setup(void)
196*91f16700Schasinglulu {
197*91f16700Schasinglulu 	size_t shared_buf_size __unused;
198*91f16700Schasinglulu 	uintptr_t shared_buf_base;
199*91f16700Schasinglulu 	uint32_t ep_attr;
200*91f16700Schasinglulu 	unsigned int linear_id = plat_my_core_pos();
201*91f16700Schasinglulu 	rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id];
202*91f16700Schasinglulu 	struct rmm_manifest *manifest;
203*91f16700Schasinglulu 	int rc;
204*91f16700Schasinglulu 
205*91f16700Schasinglulu 	/* Make sure RME is supported. */
206*91f16700Schasinglulu 	assert(get_armv9_2_feat_rme_support() != 0U);
207*91f16700Schasinglulu 
208*91f16700Schasinglulu 	rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM);
209*91f16700Schasinglulu 	if (rmm_ep_info == NULL) {
210*91f16700Schasinglulu 		WARN("No RMM image provided by BL2 boot loader, Booting "
211*91f16700Schasinglulu 		     "device without RMM initialization. SMCs destined for "
212*91f16700Schasinglulu 		     "RMM will return SMC_UNK\n");
213*91f16700Schasinglulu 		return -ENOENT;
214*91f16700Schasinglulu 	}
215*91f16700Schasinglulu 
216*91f16700Schasinglulu 	/* Under no circumstances will this parameter be 0 */
217*91f16700Schasinglulu 	assert(rmm_ep_info->pc == RMM_BASE);
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 	/* Initialise an entrypoint to set up the CPU context */
220*91f16700Schasinglulu 	ep_attr = EP_REALM;
221*91f16700Schasinglulu 	if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) {
222*91f16700Schasinglulu 		ep_attr |= EP_EE_BIG;
223*91f16700Schasinglulu 	}
224*91f16700Schasinglulu 
225*91f16700Schasinglulu 	SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr);
226*91f16700Schasinglulu 	rmm_ep_info->spsr = SPSR_64(MODE_EL2,
227*91f16700Schasinglulu 					MODE_SP_ELX,
228*91f16700Schasinglulu 					DISABLE_ALL_EXCEPTIONS);
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	shared_buf_size =
231*91f16700Schasinglulu 			plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base);
232*91f16700Schasinglulu 
233*91f16700Schasinglulu 	assert((shared_buf_size == SZ_4K) &&
234*91f16700Schasinglulu 					((void *)shared_buf_base != NULL));
235*91f16700Schasinglulu 
236*91f16700Schasinglulu 	/* Load the boot manifest at the beginning of the shared area */
237*91f16700Schasinglulu 	manifest = (struct rmm_manifest *)shared_buf_base;
238*91f16700Schasinglulu 	rc = plat_rmmd_load_manifest(manifest);
239*91f16700Schasinglulu 	if (rc != 0) {
240*91f16700Schasinglulu 		ERROR("Error loading RMM Boot Manifest (%i)\n", rc);
241*91f16700Schasinglulu 		return rc;
242*91f16700Schasinglulu 	}
243*91f16700Schasinglulu 	flush_dcache_range((uintptr_t)shared_buf_base, shared_buf_size);
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	/*
246*91f16700Schasinglulu 	 * Prepare coldboot arguments for RMM:
247*91f16700Schasinglulu 	 * arg0: This CPUID (primary processor).
248*91f16700Schasinglulu 	 * arg1: Version for this Boot Interface.
249*91f16700Schasinglulu 	 * arg2: PLATFORM_CORE_COUNT.
250*91f16700Schasinglulu 	 * arg3: Base address for the EL3 <-> RMM shared area. The boot
251*91f16700Schasinglulu 	 *       manifest will be stored at the beginning of this area.
252*91f16700Schasinglulu 	 */
253*91f16700Schasinglulu 	rmm_ep_info->args.arg0 = linear_id;
254*91f16700Schasinglulu 	rmm_ep_info->args.arg1 = RMM_EL3_INTERFACE_VERSION;
255*91f16700Schasinglulu 	rmm_ep_info->args.arg2 = PLATFORM_CORE_COUNT;
256*91f16700Schasinglulu 	rmm_ep_info->args.arg3 = shared_buf_base;
257*91f16700Schasinglulu 
258*91f16700Schasinglulu 	/* Initialise RMM context with this entry point information */
259*91f16700Schasinglulu 	cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info);
260*91f16700Schasinglulu 
261*91f16700Schasinglulu 	INFO("RMM setup done.\n");
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	/* Register init function for deferred init.  */
264*91f16700Schasinglulu 	bl31_register_rmm_init(&rmm_init);
265*91f16700Schasinglulu 
266*91f16700Schasinglulu 	return 0;
267*91f16700Schasinglulu }
268*91f16700Schasinglulu 
269*91f16700Schasinglulu /*******************************************************************************
270*91f16700Schasinglulu  * Forward SMC to the other security state
271*91f16700Schasinglulu  ******************************************************************************/
272*91f16700Schasinglulu static uint64_t	rmmd_smc_forward(uint32_t src_sec_state,
273*91f16700Schasinglulu 				 uint32_t dst_sec_state, uint64_t x0,
274*91f16700Schasinglulu 				 uint64_t x1, uint64_t x2, uint64_t x3,
275*91f16700Schasinglulu 				 uint64_t x4, void *handle)
276*91f16700Schasinglulu {
277*91f16700Schasinglulu 	cpu_context_t *ctx = cm_get_context(dst_sec_state);
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	/* Save incoming security state */
280*91f16700Schasinglulu 	cm_el1_sysregs_context_save(src_sec_state);
281*91f16700Schasinglulu 	cm_el2_sysregs_context_save(src_sec_state);
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	/* Restore outgoing security state */
284*91f16700Schasinglulu 	cm_el1_sysregs_context_restore(dst_sec_state);
285*91f16700Schasinglulu 	cm_el2_sysregs_context_restore(dst_sec_state);
286*91f16700Schasinglulu 	cm_set_next_eret_context(dst_sec_state);
287*91f16700Schasinglulu 
288*91f16700Schasinglulu 	/*
289*91f16700Schasinglulu 	 * As per SMCCCv1.2, we need to preserve x4 to x7 unless
290*91f16700Schasinglulu 	 * being used as return args. Hence we differentiate the
291*91f16700Schasinglulu 	 * onward and backward path. Support upto 8 args in the
292*91f16700Schasinglulu 	 * onward path and 4 args in return path.
293*91f16700Schasinglulu 	 * Register x4 will be preserved by RMM in case it is not
294*91f16700Schasinglulu 	 * used in return path.
295*91f16700Schasinglulu 	 */
296*91f16700Schasinglulu 	if (src_sec_state == NON_SECURE) {
297*91f16700Schasinglulu 		SMC_RET8(ctx, x0, x1, x2, x3, x4,
298*91f16700Schasinglulu 			 SMC_GET_GP(handle, CTX_GPREG_X5),
299*91f16700Schasinglulu 			 SMC_GET_GP(handle, CTX_GPREG_X6),
300*91f16700Schasinglulu 			 SMC_GET_GP(handle, CTX_GPREG_X7));
301*91f16700Schasinglulu 	}
302*91f16700Schasinglulu 
303*91f16700Schasinglulu 	SMC_RET5(ctx, x0, x1, x2, x3, x4);
304*91f16700Schasinglulu }
305*91f16700Schasinglulu 
306*91f16700Schasinglulu /*******************************************************************************
307*91f16700Schasinglulu  * This function handles all SMCs in the range reserved for RMI. Each call is
308*91f16700Schasinglulu  * either forwarded to the other security state or handled by the RMM dispatcher
309*91f16700Schasinglulu  ******************************************************************************/
310*91f16700Schasinglulu uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
311*91f16700Schasinglulu 			  uint64_t x3, uint64_t x4, void *cookie,
312*91f16700Schasinglulu 			  void *handle, uint64_t flags)
313*91f16700Schasinglulu {
314*91f16700Schasinglulu 	uint32_t src_sec_state;
315*91f16700Schasinglulu 
316*91f16700Schasinglulu 	/* If RMM failed to boot, treat any RMI SMC as unknown */
317*91f16700Schasinglulu 	if (rmm_boot_failed) {
318*91f16700Schasinglulu 		WARN("RMMD: Failed to boot up RMM. Ignoring RMI call\n");
319*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
320*91f16700Schasinglulu 	}
321*91f16700Schasinglulu 
322*91f16700Schasinglulu 	/* Determine which security state this SMC originated from */
323*91f16700Schasinglulu 	src_sec_state = caller_sec_state(flags);
324*91f16700Schasinglulu 
325*91f16700Schasinglulu 	/* RMI must not be invoked by the Secure world */
326*91f16700Schasinglulu 	if (src_sec_state == SMC_FROM_SECURE) {
327*91f16700Schasinglulu 		WARN("RMMD: RMI invoked by secure world.\n");
328*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
329*91f16700Schasinglulu 	}
330*91f16700Schasinglulu 
331*91f16700Schasinglulu 	/*
332*91f16700Schasinglulu 	 * Forward an RMI call from the Normal world to the Realm world as it
333*91f16700Schasinglulu 	 * is.
334*91f16700Schasinglulu 	 */
335*91f16700Schasinglulu 	if (src_sec_state == SMC_FROM_NON_SECURE) {
336*91f16700Schasinglulu 		/*
337*91f16700Schasinglulu 		 * If SVE hint bit is set in the flags then update the SMC
338*91f16700Schasinglulu 		 * function id and pass it on to the lower EL.
339*91f16700Schasinglulu 		 */
340*91f16700Schasinglulu 		if (is_sve_hint_set(flags)) {
341*91f16700Schasinglulu 			smc_fid |= (FUNCID_SVE_HINT_MASK <<
342*91f16700Schasinglulu 				    FUNCID_SVE_HINT_SHIFT);
343*91f16700Schasinglulu 		}
344*91f16700Schasinglulu 		VERBOSE("RMMD: RMI call from non-secure world.\n");
345*91f16700Schasinglulu 		return rmmd_smc_forward(NON_SECURE, REALM, smc_fid,
346*91f16700Schasinglulu 					x1, x2, x3, x4, handle);
347*91f16700Schasinglulu 	}
348*91f16700Schasinglulu 
349*91f16700Schasinglulu 	if (src_sec_state != SMC_FROM_REALM) {
350*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
351*91f16700Schasinglulu 	}
352*91f16700Schasinglulu 
353*91f16700Schasinglulu 	switch (smc_fid) {
354*91f16700Schasinglulu 	case RMM_RMI_REQ_COMPLETE: {
355*91f16700Schasinglulu 		uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
356*91f16700Schasinglulu 
357*91f16700Schasinglulu 		return rmmd_smc_forward(REALM, NON_SECURE, x1,
358*91f16700Schasinglulu 					x2, x3, x4, x5, handle);
359*91f16700Schasinglulu 	}
360*91f16700Schasinglulu 	default:
361*91f16700Schasinglulu 		WARN("RMMD: Unsupported RMM call 0x%08x\n", smc_fid);
362*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
363*91f16700Schasinglulu 	}
364*91f16700Schasinglulu }
365*91f16700Schasinglulu 
366*91f16700Schasinglulu /*******************************************************************************
367*91f16700Schasinglulu  * This cpu has been turned on. Enter RMM to initialise R-EL2.  Entry into RMM
368*91f16700Schasinglulu  * is done after initialising minimal architectural state that guarantees safe
369*91f16700Schasinglulu  * execution.
370*91f16700Schasinglulu  ******************************************************************************/
371*91f16700Schasinglulu static void *rmmd_cpu_on_finish_handler(const void *arg)
372*91f16700Schasinglulu {
373*91f16700Schasinglulu 	long rc;
374*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
375*91f16700Schasinglulu 	rmmd_rmm_context_t *ctx = &rmm_context[linear_id];
376*91f16700Schasinglulu 
377*91f16700Schasinglulu 	if (rmm_boot_failed) {
378*91f16700Schasinglulu 		/* RMM Boot failed on a previous CPU. Abort. */
379*91f16700Schasinglulu 		ERROR("RMM Failed to initialize. Ignoring for CPU%d\n",
380*91f16700Schasinglulu 								linear_id);
381*91f16700Schasinglulu 		return NULL;
382*91f16700Schasinglulu 	}
383*91f16700Schasinglulu 
384*91f16700Schasinglulu 	/*
385*91f16700Schasinglulu 	 * Prepare warmboot arguments for RMM:
386*91f16700Schasinglulu 	 * arg0: This CPUID.
387*91f16700Schasinglulu 	 * arg1 to arg3: Not used.
388*91f16700Schasinglulu 	 */
389*91f16700Schasinglulu 	rmm_ep_info->args.arg0 = linear_id;
390*91f16700Schasinglulu 	rmm_ep_info->args.arg1 = 0ULL;
391*91f16700Schasinglulu 	rmm_ep_info->args.arg2 = 0ULL;
392*91f16700Schasinglulu 	rmm_ep_info->args.arg3 = 0ULL;
393*91f16700Schasinglulu 
394*91f16700Schasinglulu 	/* Initialise RMM context with this entry point information */
395*91f16700Schasinglulu 	cm_setup_context(&ctx->cpu_ctx, rmm_ep_info);
396*91f16700Schasinglulu 
397*91f16700Schasinglulu 	/* Enable architecture extensions */
398*91f16700Schasinglulu 	manage_extensions_realm(&ctx->cpu_ctx);
399*91f16700Schasinglulu 
400*91f16700Schasinglulu 	/* Initialize RMM EL2 context. */
401*91f16700Schasinglulu 	rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
402*91f16700Schasinglulu 
403*91f16700Schasinglulu 	rc = rmmd_rmm_sync_entry(ctx);
404*91f16700Schasinglulu 
405*91f16700Schasinglulu 	if (rc != E_RMM_BOOT_SUCCESS) {
406*91f16700Schasinglulu 		ERROR("RMM init failed on CPU%d: %ld\n", linear_id, rc);
407*91f16700Schasinglulu 		/* Mark the boot as failed for any other booting CPU */
408*91f16700Schasinglulu 		rmm_boot_failed = true;
409*91f16700Schasinglulu 	}
410*91f16700Schasinglulu 
411*91f16700Schasinglulu 	return NULL;
412*91f16700Schasinglulu }
413*91f16700Schasinglulu 
414*91f16700Schasinglulu /* Subscribe to PSCI CPU on to initialize RMM on secondary */
415*91f16700Schasinglulu SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler);
416*91f16700Schasinglulu 
417*91f16700Schasinglulu /* Convert GPT lib error to RMMD GTS error */
418*91f16700Schasinglulu static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address)
419*91f16700Schasinglulu {
420*91f16700Schasinglulu 	int ret;
421*91f16700Schasinglulu 
422*91f16700Schasinglulu 	if (error == 0) {
423*91f16700Schasinglulu 		return E_RMM_OK;
424*91f16700Schasinglulu 	}
425*91f16700Schasinglulu 
426*91f16700Schasinglulu 	if (error == -EINVAL) {
427*91f16700Schasinglulu 		ret = E_RMM_BAD_ADDR;
428*91f16700Schasinglulu 	} else {
429*91f16700Schasinglulu 		/* This is the only other error code we expect */
430*91f16700Schasinglulu 		assert(error == -EPERM);
431*91f16700Schasinglulu 		ret = E_RMM_BAD_PAS;
432*91f16700Schasinglulu 	}
433*91f16700Schasinglulu 
434*91f16700Schasinglulu 	ERROR("RMMD: PAS Transition failed. GPT ret = %d, PA: 0x%"PRIx64 ", FID = 0x%x\n",
435*91f16700Schasinglulu 				error, address, smc_fid);
436*91f16700Schasinglulu 	return ret;
437*91f16700Schasinglulu }
438*91f16700Schasinglulu 
439*91f16700Schasinglulu /*******************************************************************************
440*91f16700Schasinglulu  * This function handles RMM-EL3 interface SMCs
441*91f16700Schasinglulu  ******************************************************************************/
442*91f16700Schasinglulu uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
443*91f16700Schasinglulu 				uint64_t x3, uint64_t x4, void *cookie,
444*91f16700Schasinglulu 				void *handle, uint64_t flags)
445*91f16700Schasinglulu {
446*91f16700Schasinglulu 	uint32_t src_sec_state;
447*91f16700Schasinglulu 	int ret;
448*91f16700Schasinglulu 
449*91f16700Schasinglulu 	/* If RMM failed to boot, treat any RMM-EL3 interface SMC as unknown */
450*91f16700Schasinglulu 	if (rmm_boot_failed) {
451*91f16700Schasinglulu 		WARN("RMMD: Failed to boot up RMM. Ignoring RMM-EL3 call\n");
452*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
453*91f16700Schasinglulu 	}
454*91f16700Schasinglulu 
455*91f16700Schasinglulu 	/* Determine which security state this SMC originated from */
456*91f16700Schasinglulu 	src_sec_state = caller_sec_state(flags);
457*91f16700Schasinglulu 
458*91f16700Schasinglulu 	if (src_sec_state != SMC_FROM_REALM) {
459*91f16700Schasinglulu 		WARN("RMMD: RMM-EL3 call originated from secure or normal world\n");
460*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
461*91f16700Schasinglulu 	}
462*91f16700Schasinglulu 
463*91f16700Schasinglulu 	switch (smc_fid) {
464*91f16700Schasinglulu 	case RMM_GTSI_DELEGATE:
465*91f16700Schasinglulu 		ret = gpt_delegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM);
466*91f16700Schasinglulu 		SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1));
467*91f16700Schasinglulu 	case RMM_GTSI_UNDELEGATE:
468*91f16700Schasinglulu 		ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM);
469*91f16700Schasinglulu 		SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1));
470*91f16700Schasinglulu 	case RMM_ATTEST_GET_PLAT_TOKEN:
471*91f16700Schasinglulu 		ret = rmmd_attest_get_platform_token(x1, &x2, x3);
472*91f16700Schasinglulu 		SMC_RET2(handle, ret, x2);
473*91f16700Schasinglulu 	case RMM_ATTEST_GET_REALM_KEY:
474*91f16700Schasinglulu 		ret = rmmd_attest_get_signing_key(x1, &x2, x3);
475*91f16700Schasinglulu 		SMC_RET2(handle, ret, x2);
476*91f16700Schasinglulu 
477*91f16700Schasinglulu 	case RMM_BOOT_COMPLETE:
478*91f16700Schasinglulu 		VERBOSE("RMMD: running rmmd_rmm_sync_exit\n");
479*91f16700Schasinglulu 		rmmd_rmm_sync_exit(x1);
480*91f16700Schasinglulu 
481*91f16700Schasinglulu 	default:
482*91f16700Schasinglulu 		WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid);
483*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
484*91f16700Schasinglulu 	}
485*91f16700Schasinglulu }
486