xref: /arm-trusted-firmware/services/std_svc/spm/el3_spmc/spmc_main.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 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 <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <arch_helpers.h>
11*91f16700Schasinglulu #include <bl31/bl31.h>
12*91f16700Schasinglulu #include <bl31/ehf.h>
13*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h>
14*91f16700Schasinglulu #include <common/debug.h>
15*91f16700Schasinglulu #include <common/fdt_wrappers.h>
16*91f16700Schasinglulu #include <common/runtime_svc.h>
17*91f16700Schasinglulu #include <common/uuid.h>
18*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h>
19*91f16700Schasinglulu #include <lib/smccc.h>
20*91f16700Schasinglulu #include <lib/utils.h>
21*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
22*91f16700Schasinglulu #include <libfdt.h>
23*91f16700Schasinglulu #include <plat/common/platform.h>
24*91f16700Schasinglulu #include <services/el3_spmc_logical_sp.h>
25*91f16700Schasinglulu #include <services/ffa_svc.h>
26*91f16700Schasinglulu #include <services/spmc_svc.h>
27*91f16700Schasinglulu #include <services/spmd_svc.h>
28*91f16700Schasinglulu #include "spmc.h"
29*91f16700Schasinglulu #include "spmc_shared_mem.h"
30*91f16700Schasinglulu 
31*91f16700Schasinglulu #include <platform_def.h>
32*91f16700Schasinglulu 
33*91f16700Schasinglulu /* Declare the maximum number of SPs and El3 LPs. */
34*91f16700Schasinglulu #define MAX_SP_LP_PARTITIONS SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT
35*91f16700Schasinglulu 
36*91f16700Schasinglulu /*
37*91f16700Schasinglulu  * Allocate a secure partition descriptor to describe each SP in the system that
38*91f16700Schasinglulu  * does not reside at EL3.
39*91f16700Schasinglulu  */
40*91f16700Schasinglulu static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT];
41*91f16700Schasinglulu 
42*91f16700Schasinglulu /*
43*91f16700Schasinglulu  * Allocate an NS endpoint descriptor to describe each VM and the Hypervisor in
44*91f16700Schasinglulu  * the system that interacts with a SP. It is used to track the Hypervisor
45*91f16700Schasinglulu  * buffer pair, version and ID for now. It could be extended to track VM
46*91f16700Schasinglulu  * properties when the SPMC supports indirect messaging.
47*91f16700Schasinglulu  */
48*91f16700Schasinglulu static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT];
49*91f16700Schasinglulu 
50*91f16700Schasinglulu static uint64_t spmc_sp_interrupt_handler(uint32_t id,
51*91f16700Schasinglulu 					  uint32_t flags,
52*91f16700Schasinglulu 					  void *handle,
53*91f16700Schasinglulu 					  void *cookie);
54*91f16700Schasinglulu 
55*91f16700Schasinglulu /*
56*91f16700Schasinglulu  * Helper function to obtain the array storing the EL3
57*91f16700Schasinglulu  * Logical Partition descriptors.
58*91f16700Schasinglulu  */
59*91f16700Schasinglulu struct el3_lp_desc *get_el3_lp_array(void)
60*91f16700Schasinglulu {
61*91f16700Schasinglulu 	return (struct el3_lp_desc *) EL3_LP_DESCS_START;
62*91f16700Schasinglulu }
63*91f16700Schasinglulu 
64*91f16700Schasinglulu /*
65*91f16700Schasinglulu  * Helper function to obtain the descriptor of the last SP to whom control was
66*91f16700Schasinglulu  * handed to on this physical cpu. Currently, we assume there is only one SP.
67*91f16700Schasinglulu  * TODO: Expand to track multiple partitions when required.
68*91f16700Schasinglulu  */
69*91f16700Schasinglulu struct secure_partition_desc *spmc_get_current_sp_ctx(void)
70*91f16700Schasinglulu {
71*91f16700Schasinglulu 	return &(sp_desc[ACTIVE_SP_DESC_INDEX]);
72*91f16700Schasinglulu }
73*91f16700Schasinglulu 
74*91f16700Schasinglulu /*
75*91f16700Schasinglulu  * Helper function to obtain the execution context of an SP on the
76*91f16700Schasinglulu  * current physical cpu.
77*91f16700Schasinglulu  */
78*91f16700Schasinglulu struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp)
79*91f16700Schasinglulu {
80*91f16700Schasinglulu 	return &(sp->ec[get_ec_index(sp)]);
81*91f16700Schasinglulu }
82*91f16700Schasinglulu 
83*91f16700Schasinglulu /* Helper function to get pointer to SP context from its ID. */
84*91f16700Schasinglulu struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id)
85*91f16700Schasinglulu {
86*91f16700Schasinglulu 	/* Check for Secure World Partitions. */
87*91f16700Schasinglulu 	for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
88*91f16700Schasinglulu 		if (sp_desc[i].sp_id == id) {
89*91f16700Schasinglulu 			return &(sp_desc[i]);
90*91f16700Schasinglulu 		}
91*91f16700Schasinglulu 	}
92*91f16700Schasinglulu 	return NULL;
93*91f16700Schasinglulu }
94*91f16700Schasinglulu 
95*91f16700Schasinglulu /*
96*91f16700Schasinglulu  * Helper function to obtain the descriptor of the Hypervisor or OS kernel.
97*91f16700Schasinglulu  * We assume that the first descriptor is reserved for this entity.
98*91f16700Schasinglulu  */
99*91f16700Schasinglulu struct ns_endpoint_desc *spmc_get_hyp_ctx(void)
100*91f16700Schasinglulu {
101*91f16700Schasinglulu 	return &(ns_ep_desc[0]);
102*91f16700Schasinglulu }
103*91f16700Schasinglulu 
104*91f16700Schasinglulu /*
105*91f16700Schasinglulu  * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor
106*91f16700Schasinglulu  * or OS kernel in the normal world or the last SP that was run.
107*91f16700Schasinglulu  */
108*91f16700Schasinglulu struct mailbox *spmc_get_mbox_desc(bool secure_origin)
109*91f16700Schasinglulu {
110*91f16700Schasinglulu 	/* Obtain the RX/TX buffer pair descriptor. */
111*91f16700Schasinglulu 	if (secure_origin) {
112*91f16700Schasinglulu 		return &(spmc_get_current_sp_ctx()->mailbox);
113*91f16700Schasinglulu 	} else {
114*91f16700Schasinglulu 		return &(spmc_get_hyp_ctx()->mailbox);
115*91f16700Schasinglulu 	}
116*91f16700Schasinglulu }
117*91f16700Schasinglulu 
118*91f16700Schasinglulu /******************************************************************************
119*91f16700Schasinglulu  * This function returns to the place where spmc_sp_synchronous_entry() was
120*91f16700Schasinglulu  * called originally.
121*91f16700Schasinglulu  ******************************************************************************/
122*91f16700Schasinglulu __dead2 void spmc_sp_synchronous_exit(struct sp_exec_ctx *ec, uint64_t rc)
123*91f16700Schasinglulu {
124*91f16700Schasinglulu 	/*
125*91f16700Schasinglulu 	 * The SPM must have initiated the original request through a
126*91f16700Schasinglulu 	 * synchronous entry into the secure partition. Jump back to the
127*91f16700Schasinglulu 	 * original C runtime context with the value of rc in x0;
128*91f16700Schasinglulu 	 */
129*91f16700Schasinglulu 	spm_secure_partition_exit(ec->c_rt_ctx, rc);
130*91f16700Schasinglulu 
131*91f16700Schasinglulu 	panic();
132*91f16700Schasinglulu }
133*91f16700Schasinglulu 
134*91f16700Schasinglulu /*******************************************************************************
135*91f16700Schasinglulu  * Return FFA_ERROR with specified error code.
136*91f16700Schasinglulu  ******************************************************************************/
137*91f16700Schasinglulu uint64_t spmc_ffa_error_return(void *handle, int error_code)
138*91f16700Schasinglulu {
139*91f16700Schasinglulu 	SMC_RET8(handle, FFA_ERROR,
140*91f16700Schasinglulu 		 FFA_TARGET_INFO_MBZ, error_code,
141*91f16700Schasinglulu 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
142*91f16700Schasinglulu 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
143*91f16700Schasinglulu }
144*91f16700Schasinglulu 
145*91f16700Schasinglulu /******************************************************************************
146*91f16700Schasinglulu  * Helper function to validate a secure partition ID to ensure it does not
147*91f16700Schasinglulu  * conflict with any other FF-A component and follows the convention to
148*91f16700Schasinglulu  * indicate it resides within the secure world.
149*91f16700Schasinglulu  ******************************************************************************/
150*91f16700Schasinglulu bool is_ffa_secure_id_valid(uint16_t partition_id)
151*91f16700Schasinglulu {
152*91f16700Schasinglulu 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	/* Ensure the ID is not the invalid partition ID. */
155*91f16700Schasinglulu 	if (partition_id == INV_SP_ID) {
156*91f16700Schasinglulu 		return false;
157*91f16700Schasinglulu 	}
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	/* Ensure the ID is not the SPMD ID. */
160*91f16700Schasinglulu 	if (partition_id == SPMD_DIRECT_MSG_ENDPOINT_ID) {
161*91f16700Schasinglulu 		return false;
162*91f16700Schasinglulu 	}
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/*
165*91f16700Schasinglulu 	 * Ensure the ID follows the convention to indicate it resides
166*91f16700Schasinglulu 	 * in the secure world.
167*91f16700Schasinglulu 	 */
168*91f16700Schasinglulu 	if (!ffa_is_secure_world_id(partition_id)) {
169*91f16700Schasinglulu 		return false;
170*91f16700Schasinglulu 	}
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	/* Ensure we don't conflict with the SPMC partition ID. */
173*91f16700Schasinglulu 	if (partition_id == FFA_SPMC_ID) {
174*91f16700Schasinglulu 		return false;
175*91f16700Schasinglulu 	}
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 	/* Ensure we do not already have an SP context with this ID. */
178*91f16700Schasinglulu 	if (spmc_get_sp_ctx(partition_id)) {
179*91f16700Schasinglulu 		return false;
180*91f16700Schasinglulu 	}
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	/* Ensure we don't clash with any Logical SP's. */
183*91f16700Schasinglulu 	for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
184*91f16700Schasinglulu 		if (el3_lp_descs[i].sp_id == partition_id) {
185*91f16700Schasinglulu 			return false;
186*91f16700Schasinglulu 		}
187*91f16700Schasinglulu 	}
188*91f16700Schasinglulu 
189*91f16700Schasinglulu 	return true;
190*91f16700Schasinglulu }
191*91f16700Schasinglulu 
192*91f16700Schasinglulu /*******************************************************************************
193*91f16700Schasinglulu  * This function either forwards the request to the other world or returns
194*91f16700Schasinglulu  * with an ERET depending on the source of the call.
195*91f16700Schasinglulu  * We can assume that the destination is for an entity at a lower exception
196*91f16700Schasinglulu  * level as any messages destined for a logical SP resident in EL3 will have
197*91f16700Schasinglulu  * already been taken care of by the SPMC before entering this function.
198*91f16700Schasinglulu  ******************************************************************************/
199*91f16700Schasinglulu static uint64_t spmc_smc_return(uint32_t smc_fid,
200*91f16700Schasinglulu 				bool secure_origin,
201*91f16700Schasinglulu 				uint64_t x1,
202*91f16700Schasinglulu 				uint64_t x2,
203*91f16700Schasinglulu 				uint64_t x3,
204*91f16700Schasinglulu 				uint64_t x4,
205*91f16700Schasinglulu 				void *handle,
206*91f16700Schasinglulu 				void *cookie,
207*91f16700Schasinglulu 				uint64_t flags,
208*91f16700Schasinglulu 				uint16_t dst_id)
209*91f16700Schasinglulu {
210*91f16700Schasinglulu 	/* If the destination is in the normal world always go via the SPMD. */
211*91f16700Schasinglulu 	if (ffa_is_normal_world_id(dst_id)) {
212*91f16700Schasinglulu 		return spmd_smc_handler(smc_fid, x1, x2, x3, x4,
213*91f16700Schasinglulu 					cookie, handle, flags);
214*91f16700Schasinglulu 	}
215*91f16700Schasinglulu 	/*
216*91f16700Schasinglulu 	 * If the caller is secure and we want to return to the secure world,
217*91f16700Schasinglulu 	 * ERET directly.
218*91f16700Schasinglulu 	 */
219*91f16700Schasinglulu 	else if (secure_origin && ffa_is_secure_world_id(dst_id)) {
220*91f16700Schasinglulu 		SMC_RET5(handle, smc_fid, x1, x2, x3, x4);
221*91f16700Schasinglulu 	}
222*91f16700Schasinglulu 	/* If we originated in the normal world then switch contexts. */
223*91f16700Schasinglulu 	else if (!secure_origin && ffa_is_secure_world_id(dst_id)) {
224*91f16700Schasinglulu 		return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2,
225*91f16700Schasinglulu 					     x3, x4, handle);
226*91f16700Schasinglulu 	} else {
227*91f16700Schasinglulu 		/* Unknown State. */
228*91f16700Schasinglulu 		panic();
229*91f16700Schasinglulu 	}
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 	/* Shouldn't be Reached. */
232*91f16700Schasinglulu 	return 0;
233*91f16700Schasinglulu }
234*91f16700Schasinglulu 
235*91f16700Schasinglulu /*******************************************************************************
236*91f16700Schasinglulu  * FF-A ABI Handlers.
237*91f16700Schasinglulu  ******************************************************************************/
238*91f16700Schasinglulu 
239*91f16700Schasinglulu /*******************************************************************************
240*91f16700Schasinglulu  * Helper function to validate arg2 as part of a direct message.
241*91f16700Schasinglulu  ******************************************************************************/
242*91f16700Schasinglulu static inline bool direct_msg_validate_arg2(uint64_t x2)
243*91f16700Schasinglulu {
244*91f16700Schasinglulu 	/* Check message type. */
245*91f16700Schasinglulu 	if (x2 & FFA_FWK_MSG_BIT) {
246*91f16700Schasinglulu 		/* We have a framework message, ensure it is a known message. */
247*91f16700Schasinglulu 		if (x2 & ~(FFA_FWK_MSG_MASK | FFA_FWK_MSG_BIT)) {
248*91f16700Schasinglulu 			VERBOSE("Invalid message format 0x%lx.\n", x2);
249*91f16700Schasinglulu 			return false;
250*91f16700Schasinglulu 		}
251*91f16700Schasinglulu 	} else {
252*91f16700Schasinglulu 		/* We have a partition messages, ensure x2 is not set. */
253*91f16700Schasinglulu 		if (x2 != (uint64_t) 0) {
254*91f16700Schasinglulu 			VERBOSE("Arg2 MBZ for partition messages. (0x%lx).\n",
255*91f16700Schasinglulu 				x2);
256*91f16700Schasinglulu 			return false;
257*91f16700Schasinglulu 		}
258*91f16700Schasinglulu 	}
259*91f16700Schasinglulu 	return true;
260*91f16700Schasinglulu }
261*91f16700Schasinglulu 
262*91f16700Schasinglulu /*******************************************************************************
263*91f16700Schasinglulu  * Helper function to validate the destination ID of a direct response.
264*91f16700Schasinglulu  ******************************************************************************/
265*91f16700Schasinglulu static bool direct_msg_validate_dst_id(uint16_t dst_id)
266*91f16700Schasinglulu {
267*91f16700Schasinglulu 	struct secure_partition_desc *sp;
268*91f16700Schasinglulu 
269*91f16700Schasinglulu 	/* Check if we're targeting a normal world partition. */
270*91f16700Schasinglulu 	if (ffa_is_normal_world_id(dst_id)) {
271*91f16700Schasinglulu 		return true;
272*91f16700Schasinglulu 	}
273*91f16700Schasinglulu 
274*91f16700Schasinglulu 	/* Or directed to the SPMC itself.*/
275*91f16700Schasinglulu 	if (dst_id == FFA_SPMC_ID) {
276*91f16700Schasinglulu 		return true;
277*91f16700Schasinglulu 	}
278*91f16700Schasinglulu 
279*91f16700Schasinglulu 	/* Otherwise ensure the SP exists. */
280*91f16700Schasinglulu 	sp = spmc_get_sp_ctx(dst_id);
281*91f16700Schasinglulu 	if (sp != NULL) {
282*91f16700Schasinglulu 		return true;
283*91f16700Schasinglulu 	}
284*91f16700Schasinglulu 
285*91f16700Schasinglulu 	return false;
286*91f16700Schasinglulu }
287*91f16700Schasinglulu 
288*91f16700Schasinglulu /*******************************************************************************
289*91f16700Schasinglulu  * Helper function to validate the response from a Logical Partition.
290*91f16700Schasinglulu  ******************************************************************************/
291*91f16700Schasinglulu static bool direct_msg_validate_lp_resp(uint16_t origin_id, uint16_t lp_id,
292*91f16700Schasinglulu 					void *handle)
293*91f16700Schasinglulu {
294*91f16700Schasinglulu 	/* Retrieve populated Direct Response Arguments. */
295*91f16700Schasinglulu 	uint64_t x1 = SMC_GET_GP(handle, CTX_GPREG_X1);
296*91f16700Schasinglulu 	uint64_t x2 = SMC_GET_GP(handle, CTX_GPREG_X2);
297*91f16700Schasinglulu 	uint16_t src_id = ffa_endpoint_source(x1);
298*91f16700Schasinglulu 	uint16_t dst_id = ffa_endpoint_destination(x1);
299*91f16700Schasinglulu 
300*91f16700Schasinglulu 	if (src_id != lp_id) {
301*91f16700Schasinglulu 		ERROR("Invalid EL3 LP source ID (0x%x).\n", src_id);
302*91f16700Schasinglulu 		return false;
303*91f16700Schasinglulu 	}
304*91f16700Schasinglulu 
305*91f16700Schasinglulu 	/*
306*91f16700Schasinglulu 	 * Check the destination ID is valid and ensure the LP is responding to
307*91f16700Schasinglulu 	 * the original request.
308*91f16700Schasinglulu 	 */
309*91f16700Schasinglulu 	if ((!direct_msg_validate_dst_id(dst_id)) || (dst_id != origin_id)) {
310*91f16700Schasinglulu 		ERROR("Invalid EL3 LP destination ID (0x%x).\n", dst_id);
311*91f16700Schasinglulu 		return false;
312*91f16700Schasinglulu 	}
313*91f16700Schasinglulu 
314*91f16700Schasinglulu 	if (!direct_msg_validate_arg2(x2)) {
315*91f16700Schasinglulu 		ERROR("Invalid EL3 LP message encoding.\n");
316*91f16700Schasinglulu 		return false;
317*91f16700Schasinglulu 	}
318*91f16700Schasinglulu 	return true;
319*91f16700Schasinglulu }
320*91f16700Schasinglulu 
321*91f16700Schasinglulu /*******************************************************************************
322*91f16700Schasinglulu  * Handle direct request messages and route to the appropriate destination.
323*91f16700Schasinglulu  ******************************************************************************/
324*91f16700Schasinglulu static uint64_t direct_req_smc_handler(uint32_t smc_fid,
325*91f16700Schasinglulu 				       bool secure_origin,
326*91f16700Schasinglulu 				       uint64_t x1,
327*91f16700Schasinglulu 				       uint64_t x2,
328*91f16700Schasinglulu 				       uint64_t x3,
329*91f16700Schasinglulu 				       uint64_t x4,
330*91f16700Schasinglulu 				       void *cookie,
331*91f16700Schasinglulu 				       void *handle,
332*91f16700Schasinglulu 				       uint64_t flags)
333*91f16700Schasinglulu {
334*91f16700Schasinglulu 	uint16_t src_id = ffa_endpoint_source(x1);
335*91f16700Schasinglulu 	uint16_t dst_id = ffa_endpoint_destination(x1);
336*91f16700Schasinglulu 	struct el3_lp_desc *el3_lp_descs;
337*91f16700Schasinglulu 	struct secure_partition_desc *sp;
338*91f16700Schasinglulu 	unsigned int idx;
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	/* Check if arg2 has been populated correctly based on message type. */
341*91f16700Schasinglulu 	if (!direct_msg_validate_arg2(x2)) {
342*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
343*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
344*91f16700Schasinglulu 	}
345*91f16700Schasinglulu 
346*91f16700Schasinglulu 	/* Validate Sender is either the current SP or from the normal world. */
347*91f16700Schasinglulu 	if ((secure_origin && src_id != spmc_get_current_sp_ctx()->sp_id) ||
348*91f16700Schasinglulu 		(!secure_origin && !ffa_is_normal_world_id(src_id))) {
349*91f16700Schasinglulu 		ERROR("Invalid direct request source ID (0x%x).\n", src_id);
350*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
351*91f16700Schasinglulu 					FFA_ERROR_INVALID_PARAMETER);
352*91f16700Schasinglulu 	}
353*91f16700Schasinglulu 
354*91f16700Schasinglulu 	el3_lp_descs = get_el3_lp_array();
355*91f16700Schasinglulu 
356*91f16700Schasinglulu 	/* Check if the request is destined for a Logical Partition. */
357*91f16700Schasinglulu 	for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) {
358*91f16700Schasinglulu 		if (el3_lp_descs[i].sp_id == dst_id) {
359*91f16700Schasinglulu 			uint64_t ret = el3_lp_descs[i].direct_req(
360*91f16700Schasinglulu 						smc_fid, secure_origin, x1, x2,
361*91f16700Schasinglulu 						x3, x4, cookie, handle, flags);
362*91f16700Schasinglulu 			if (!direct_msg_validate_lp_resp(src_id, dst_id,
363*91f16700Schasinglulu 							 handle)) {
364*91f16700Schasinglulu 				panic();
365*91f16700Schasinglulu 			}
366*91f16700Schasinglulu 
367*91f16700Schasinglulu 			/* Message checks out. */
368*91f16700Schasinglulu 			return ret;
369*91f16700Schasinglulu 		}
370*91f16700Schasinglulu 	}
371*91f16700Schasinglulu 
372*91f16700Schasinglulu 	/*
373*91f16700Schasinglulu 	 * If the request was not targeted to a LSP and from the secure world
374*91f16700Schasinglulu 	 * then it is invalid since a SP cannot call into the Normal world and
375*91f16700Schasinglulu 	 * there is no other SP to call into. If there are other SPs in future
376*91f16700Schasinglulu 	 * then the partition runtime model would need to be validated as well.
377*91f16700Schasinglulu 	 */
378*91f16700Schasinglulu 	if (secure_origin) {
379*91f16700Schasinglulu 		VERBOSE("Direct request not supported to the Normal World.\n");
380*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
381*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
382*91f16700Schasinglulu 	}
383*91f16700Schasinglulu 
384*91f16700Schasinglulu 	/* Check if the SP ID is valid. */
385*91f16700Schasinglulu 	sp = spmc_get_sp_ctx(dst_id);
386*91f16700Schasinglulu 	if (sp == NULL) {
387*91f16700Schasinglulu 		VERBOSE("Direct request to unknown partition ID (0x%x).\n",
388*91f16700Schasinglulu 			dst_id);
389*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
390*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
391*91f16700Schasinglulu 	}
392*91f16700Schasinglulu 
393*91f16700Schasinglulu 	/*
394*91f16700Schasinglulu 	 * Check that the target execution context is in a waiting state before
395*91f16700Schasinglulu 	 * forwarding the direct request to it.
396*91f16700Schasinglulu 	 */
397*91f16700Schasinglulu 	idx = get_ec_index(sp);
398*91f16700Schasinglulu 	if (sp->ec[idx].rt_state != RT_STATE_WAITING) {
399*91f16700Schasinglulu 		VERBOSE("SP context on core%u is not waiting (%u).\n",
400*91f16700Schasinglulu 			idx, sp->ec[idx].rt_model);
401*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
402*91f16700Schasinglulu 	}
403*91f16700Schasinglulu 
404*91f16700Schasinglulu 	/*
405*91f16700Schasinglulu 	 * Everything checks out so forward the request to the SP after updating
406*91f16700Schasinglulu 	 * its state and runtime model.
407*91f16700Schasinglulu 	 */
408*91f16700Schasinglulu 	sp->ec[idx].rt_state = RT_STATE_RUNNING;
409*91f16700Schasinglulu 	sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
410*91f16700Schasinglulu 	sp->ec[idx].dir_req_origin_id = src_id;
411*91f16700Schasinglulu 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
412*91f16700Schasinglulu 			       handle, cookie, flags, dst_id);
413*91f16700Schasinglulu }
414*91f16700Schasinglulu 
415*91f16700Schasinglulu /*******************************************************************************
416*91f16700Schasinglulu  * Handle direct response messages and route to the appropriate destination.
417*91f16700Schasinglulu  ******************************************************************************/
418*91f16700Schasinglulu static uint64_t direct_resp_smc_handler(uint32_t smc_fid,
419*91f16700Schasinglulu 					bool secure_origin,
420*91f16700Schasinglulu 					uint64_t x1,
421*91f16700Schasinglulu 					uint64_t x2,
422*91f16700Schasinglulu 					uint64_t x3,
423*91f16700Schasinglulu 					uint64_t x4,
424*91f16700Schasinglulu 					void *cookie,
425*91f16700Schasinglulu 					void *handle,
426*91f16700Schasinglulu 					uint64_t flags)
427*91f16700Schasinglulu {
428*91f16700Schasinglulu 	uint16_t dst_id = ffa_endpoint_destination(x1);
429*91f16700Schasinglulu 	struct secure_partition_desc *sp;
430*91f16700Schasinglulu 	unsigned int idx;
431*91f16700Schasinglulu 
432*91f16700Schasinglulu 	/* Check if arg2 has been populated correctly based on message type. */
433*91f16700Schasinglulu 	if (!direct_msg_validate_arg2(x2)) {
434*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
435*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
436*91f16700Schasinglulu 	}
437*91f16700Schasinglulu 
438*91f16700Schasinglulu 	/* Check that the response did not originate from the Normal world. */
439*91f16700Schasinglulu 	if (!secure_origin) {
440*91f16700Schasinglulu 		VERBOSE("Direct Response not supported from Normal World.\n");
441*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
442*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
443*91f16700Schasinglulu 	}
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 	/*
446*91f16700Schasinglulu 	 * Check that the response is either targeted to the Normal world or the
447*91f16700Schasinglulu 	 * SPMC e.g. a PM response.
448*91f16700Schasinglulu 	 */
449*91f16700Schasinglulu 	if (!direct_msg_validate_dst_id(dst_id)) {
450*91f16700Schasinglulu 		VERBOSE("Direct response to invalid partition ID (0x%x).\n",
451*91f16700Schasinglulu 			dst_id);
452*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
453*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
454*91f16700Schasinglulu 	}
455*91f16700Schasinglulu 
456*91f16700Schasinglulu 	/* Obtain the SP descriptor and update its runtime state. */
457*91f16700Schasinglulu 	sp = spmc_get_sp_ctx(ffa_endpoint_source(x1));
458*91f16700Schasinglulu 	if (sp == NULL) {
459*91f16700Schasinglulu 		VERBOSE("Direct response to unknown partition ID (0x%x).\n",
460*91f16700Schasinglulu 			dst_id);
461*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
462*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
463*91f16700Schasinglulu 	}
464*91f16700Schasinglulu 
465*91f16700Schasinglulu 	/* Sanity check state is being tracked correctly in the SPMC. */
466*91f16700Schasinglulu 	idx = get_ec_index(sp);
467*91f16700Schasinglulu 	assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
468*91f16700Schasinglulu 
469*91f16700Schasinglulu 	/* Ensure SP execution context was in the right runtime model. */
470*91f16700Schasinglulu 	if (sp->ec[idx].rt_model != RT_MODEL_DIR_REQ) {
471*91f16700Schasinglulu 		VERBOSE("SP context on core%u not handling direct req (%u).\n",
472*91f16700Schasinglulu 			idx, sp->ec[idx].rt_model);
473*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
474*91f16700Schasinglulu 	}
475*91f16700Schasinglulu 
476*91f16700Schasinglulu 	if (sp->ec[idx].dir_req_origin_id != dst_id) {
477*91f16700Schasinglulu 		WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n",
478*91f16700Schasinglulu 		     dst_id, sp->ec[idx].dir_req_origin_id, idx);
479*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
480*91f16700Schasinglulu 	}
481*91f16700Schasinglulu 
482*91f16700Schasinglulu 	/* Update the state of the SP execution context. */
483*91f16700Schasinglulu 	sp->ec[idx].rt_state = RT_STATE_WAITING;
484*91f16700Schasinglulu 
485*91f16700Schasinglulu 	/* Clear the ongoing direct request ID. */
486*91f16700Schasinglulu 	sp->ec[idx].dir_req_origin_id = INV_SP_ID;
487*91f16700Schasinglulu 
488*91f16700Schasinglulu 	/*
489*91f16700Schasinglulu 	 * If the receiver is not the SPMC then forward the response to the
490*91f16700Schasinglulu 	 * Normal world.
491*91f16700Schasinglulu 	 */
492*91f16700Schasinglulu 	if (dst_id == FFA_SPMC_ID) {
493*91f16700Schasinglulu 		spmc_sp_synchronous_exit(&sp->ec[idx], x4);
494*91f16700Schasinglulu 		/* Should not get here. */
495*91f16700Schasinglulu 		panic();
496*91f16700Schasinglulu 	}
497*91f16700Schasinglulu 
498*91f16700Schasinglulu 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
499*91f16700Schasinglulu 			       handle, cookie, flags, dst_id);
500*91f16700Schasinglulu }
501*91f16700Schasinglulu 
502*91f16700Schasinglulu /*******************************************************************************
503*91f16700Schasinglulu  * This function handles the FFA_MSG_WAIT SMC to allow an SP to relinquish its
504*91f16700Schasinglulu  * cycles.
505*91f16700Schasinglulu  ******************************************************************************/
506*91f16700Schasinglulu static uint64_t msg_wait_handler(uint32_t smc_fid,
507*91f16700Schasinglulu 				 bool secure_origin,
508*91f16700Schasinglulu 				 uint64_t x1,
509*91f16700Schasinglulu 				 uint64_t x2,
510*91f16700Schasinglulu 				 uint64_t x3,
511*91f16700Schasinglulu 				 uint64_t x4,
512*91f16700Schasinglulu 				 void *cookie,
513*91f16700Schasinglulu 				 void *handle,
514*91f16700Schasinglulu 				 uint64_t flags)
515*91f16700Schasinglulu {
516*91f16700Schasinglulu 	struct secure_partition_desc *sp;
517*91f16700Schasinglulu 	unsigned int idx;
518*91f16700Schasinglulu 
519*91f16700Schasinglulu 	/*
520*91f16700Schasinglulu 	 * Check that the response did not originate from the Normal world as
521*91f16700Schasinglulu 	 * only the secure world can call this ABI.
522*91f16700Schasinglulu 	 */
523*91f16700Schasinglulu 	if (!secure_origin) {
524*91f16700Schasinglulu 		VERBOSE("Normal world cannot call FFA_MSG_WAIT.\n");
525*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
526*91f16700Schasinglulu 	}
527*91f16700Schasinglulu 
528*91f16700Schasinglulu 	/* Get the descriptor of the SP that invoked FFA_MSG_WAIT. */
529*91f16700Schasinglulu 	sp = spmc_get_current_sp_ctx();
530*91f16700Schasinglulu 	if (sp == NULL) {
531*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
532*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
533*91f16700Schasinglulu 	}
534*91f16700Schasinglulu 
535*91f16700Schasinglulu 	/*
536*91f16700Schasinglulu 	 * Get the execution context of the SP that invoked FFA_MSG_WAIT.
537*91f16700Schasinglulu 	 */
538*91f16700Schasinglulu 	idx = get_ec_index(sp);
539*91f16700Schasinglulu 
540*91f16700Schasinglulu 	/* Ensure SP execution context was in the right runtime model. */
541*91f16700Schasinglulu 	if (sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
542*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
543*91f16700Schasinglulu 	}
544*91f16700Schasinglulu 
545*91f16700Schasinglulu 	/* Sanity check the state is being tracked correctly in the SPMC. */
546*91f16700Schasinglulu 	assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
547*91f16700Schasinglulu 
548*91f16700Schasinglulu 	/*
549*91f16700Schasinglulu 	 * Perform a synchronous exit if the partition was initialising. The
550*91f16700Schasinglulu 	 * state is updated after the exit.
551*91f16700Schasinglulu 	 */
552*91f16700Schasinglulu 	if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
553*91f16700Schasinglulu 		spmc_sp_synchronous_exit(&sp->ec[idx], x4);
554*91f16700Schasinglulu 		/* Should not get here */
555*91f16700Schasinglulu 		panic();
556*91f16700Schasinglulu 	}
557*91f16700Schasinglulu 
558*91f16700Schasinglulu 	/* Update the state of the SP execution context. */
559*91f16700Schasinglulu 	sp->ec[idx].rt_state = RT_STATE_WAITING;
560*91f16700Schasinglulu 
561*91f16700Schasinglulu 	/* Resume normal world if a secure interrupt was handled. */
562*91f16700Schasinglulu 	if (sp->ec[idx].rt_model == RT_MODEL_INTR) {
563*91f16700Schasinglulu 		/* FFA_MSG_WAIT can only be called from the secure world. */
564*91f16700Schasinglulu 		unsigned int secure_state_in = SECURE;
565*91f16700Schasinglulu 		unsigned int secure_state_out = NON_SECURE;
566*91f16700Schasinglulu 
567*91f16700Schasinglulu 		cm_el1_sysregs_context_save(secure_state_in);
568*91f16700Schasinglulu 		cm_el1_sysregs_context_restore(secure_state_out);
569*91f16700Schasinglulu 		cm_set_next_eret_context(secure_state_out);
570*91f16700Schasinglulu 		SMC_RET0(cm_get_context(secure_state_out));
571*91f16700Schasinglulu 	}
572*91f16700Schasinglulu 
573*91f16700Schasinglulu 	/* Forward the response to the Normal world. */
574*91f16700Schasinglulu 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
575*91f16700Schasinglulu 			       handle, cookie, flags, FFA_NWD_ID);
576*91f16700Schasinglulu }
577*91f16700Schasinglulu 
578*91f16700Schasinglulu static uint64_t ffa_error_handler(uint32_t smc_fid,
579*91f16700Schasinglulu 				 bool secure_origin,
580*91f16700Schasinglulu 				 uint64_t x1,
581*91f16700Schasinglulu 				 uint64_t x2,
582*91f16700Schasinglulu 				 uint64_t x3,
583*91f16700Schasinglulu 				 uint64_t x4,
584*91f16700Schasinglulu 				 void *cookie,
585*91f16700Schasinglulu 				 void *handle,
586*91f16700Schasinglulu 				 uint64_t flags)
587*91f16700Schasinglulu {
588*91f16700Schasinglulu 	struct secure_partition_desc *sp;
589*91f16700Schasinglulu 	unsigned int idx;
590*91f16700Schasinglulu 
591*91f16700Schasinglulu 	/* Check that the response did not originate from the Normal world. */
592*91f16700Schasinglulu 	if (!secure_origin) {
593*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
594*91f16700Schasinglulu 	}
595*91f16700Schasinglulu 
596*91f16700Schasinglulu 	/* Get the descriptor of the SP that invoked FFA_ERROR. */
597*91f16700Schasinglulu 	sp = spmc_get_current_sp_ctx();
598*91f16700Schasinglulu 	if (sp == NULL) {
599*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
600*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
601*91f16700Schasinglulu 	}
602*91f16700Schasinglulu 
603*91f16700Schasinglulu 	/* Get the execution context of the SP that invoked FFA_ERROR. */
604*91f16700Schasinglulu 	idx = get_ec_index(sp);
605*91f16700Schasinglulu 
606*91f16700Schasinglulu 	/*
607*91f16700Schasinglulu 	 * We only expect FFA_ERROR to be received during SP initialisation
608*91f16700Schasinglulu 	 * otherwise this is an invalid call.
609*91f16700Schasinglulu 	 */
610*91f16700Schasinglulu 	if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
611*91f16700Schasinglulu 		ERROR("SP 0x%x failed to initialize.\n", sp->sp_id);
612*91f16700Schasinglulu 		spmc_sp_synchronous_exit(&sp->ec[idx], x2);
613*91f16700Schasinglulu 		/* Should not get here. */
614*91f16700Schasinglulu 		panic();
615*91f16700Schasinglulu 	}
616*91f16700Schasinglulu 
617*91f16700Schasinglulu 	return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
618*91f16700Schasinglulu }
619*91f16700Schasinglulu 
620*91f16700Schasinglulu static uint64_t ffa_version_handler(uint32_t smc_fid,
621*91f16700Schasinglulu 				    bool secure_origin,
622*91f16700Schasinglulu 				    uint64_t x1,
623*91f16700Schasinglulu 				    uint64_t x2,
624*91f16700Schasinglulu 				    uint64_t x3,
625*91f16700Schasinglulu 				    uint64_t x4,
626*91f16700Schasinglulu 				    void *cookie,
627*91f16700Schasinglulu 				    void *handle,
628*91f16700Schasinglulu 				    uint64_t flags)
629*91f16700Schasinglulu {
630*91f16700Schasinglulu 	uint32_t requested_version = x1 & FFA_VERSION_MASK;
631*91f16700Schasinglulu 
632*91f16700Schasinglulu 	if (requested_version & FFA_VERSION_BIT31_MASK) {
633*91f16700Schasinglulu 		/* Invalid encoding, return an error. */
634*91f16700Schasinglulu 		SMC_RET1(handle, FFA_ERROR_NOT_SUPPORTED);
635*91f16700Schasinglulu 		/* Execution stops here. */
636*91f16700Schasinglulu 	}
637*91f16700Schasinglulu 
638*91f16700Schasinglulu 	/* Determine the caller to store the requested version. */
639*91f16700Schasinglulu 	if (secure_origin) {
640*91f16700Schasinglulu 		/*
641*91f16700Schasinglulu 		 * Ensure that the SP is reporting the same version as
642*91f16700Schasinglulu 		 * specified in its manifest. If these do not match there is
643*91f16700Schasinglulu 		 * something wrong with the SP.
644*91f16700Schasinglulu 		 * TODO: Should we abort the SP? For now assert this is not
645*91f16700Schasinglulu 		 *       case.
646*91f16700Schasinglulu 		 */
647*91f16700Schasinglulu 		assert(requested_version ==
648*91f16700Schasinglulu 		       spmc_get_current_sp_ctx()->ffa_version);
649*91f16700Schasinglulu 	} else {
650*91f16700Schasinglulu 		/*
651*91f16700Schasinglulu 		 * If this is called by the normal world, record this
652*91f16700Schasinglulu 		 * information in its descriptor.
653*91f16700Schasinglulu 		 */
654*91f16700Schasinglulu 		spmc_get_hyp_ctx()->ffa_version = requested_version;
655*91f16700Schasinglulu 	}
656*91f16700Schasinglulu 
657*91f16700Schasinglulu 	SMC_RET1(handle, MAKE_FFA_VERSION(FFA_VERSION_MAJOR,
658*91f16700Schasinglulu 					  FFA_VERSION_MINOR));
659*91f16700Schasinglulu }
660*91f16700Schasinglulu 
661*91f16700Schasinglulu /*******************************************************************************
662*91f16700Schasinglulu  * Helper function to obtain the FF-A version of the calling partition.
663*91f16700Schasinglulu  ******************************************************************************/
664*91f16700Schasinglulu uint32_t get_partition_ffa_version(bool secure_origin)
665*91f16700Schasinglulu {
666*91f16700Schasinglulu 	if (secure_origin) {
667*91f16700Schasinglulu 		return spmc_get_current_sp_ctx()->ffa_version;
668*91f16700Schasinglulu 	} else {
669*91f16700Schasinglulu 		return spmc_get_hyp_ctx()->ffa_version;
670*91f16700Schasinglulu 	}
671*91f16700Schasinglulu }
672*91f16700Schasinglulu 
673*91f16700Schasinglulu static uint64_t rxtx_map_handler(uint32_t smc_fid,
674*91f16700Schasinglulu 				 bool secure_origin,
675*91f16700Schasinglulu 				 uint64_t x1,
676*91f16700Schasinglulu 				 uint64_t x2,
677*91f16700Schasinglulu 				 uint64_t x3,
678*91f16700Schasinglulu 				 uint64_t x4,
679*91f16700Schasinglulu 				 void *cookie,
680*91f16700Schasinglulu 				 void *handle,
681*91f16700Schasinglulu 				 uint64_t flags)
682*91f16700Schasinglulu {
683*91f16700Schasinglulu 	int ret;
684*91f16700Schasinglulu 	uint32_t error_code;
685*91f16700Schasinglulu 	uint32_t mem_atts = secure_origin ? MT_SECURE : MT_NS;
686*91f16700Schasinglulu 	struct mailbox *mbox;
687*91f16700Schasinglulu 	uintptr_t tx_address = x1;
688*91f16700Schasinglulu 	uintptr_t rx_address = x2;
689*91f16700Schasinglulu 	uint32_t page_count = x3 & FFA_RXTX_PAGE_COUNT_MASK; /* Bits [5:0] */
690*91f16700Schasinglulu 	uint32_t buf_size = page_count * FFA_PAGE_SIZE;
691*91f16700Schasinglulu 
692*91f16700Schasinglulu 	/*
693*91f16700Schasinglulu 	 * The SPMC does not support mapping of VM RX/TX pairs to facilitate
694*91f16700Schasinglulu 	 * indirect messaging with SPs. Check if the Hypervisor has invoked this
695*91f16700Schasinglulu 	 * ABI on behalf of a VM and reject it if this is the case.
696*91f16700Schasinglulu 	 */
697*91f16700Schasinglulu 	if (tx_address == 0 || rx_address == 0) {
698*91f16700Schasinglulu 		WARN("Mapping RX/TX Buffers on behalf of VM not supported.\n");
699*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
700*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
701*91f16700Schasinglulu 	}
702*91f16700Schasinglulu 
703*91f16700Schasinglulu 	/* Ensure the specified buffers are not the same. */
704*91f16700Schasinglulu 	if (tx_address == rx_address) {
705*91f16700Schasinglulu 		WARN("TX Buffer must not be the same as RX Buffer.\n");
706*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
707*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
708*91f16700Schasinglulu 	}
709*91f16700Schasinglulu 
710*91f16700Schasinglulu 	/* Ensure the buffer size is not 0. */
711*91f16700Schasinglulu 	if (buf_size == 0U) {
712*91f16700Schasinglulu 		WARN("Buffer size must not be 0\n");
713*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
714*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
715*91f16700Schasinglulu 	}
716*91f16700Schasinglulu 
717*91f16700Schasinglulu 	/*
718*91f16700Schasinglulu 	 * Ensure the buffer size is a multiple of the translation granule size
719*91f16700Schasinglulu 	 * in TF-A.
720*91f16700Schasinglulu 	 */
721*91f16700Schasinglulu 	if (buf_size % PAGE_SIZE != 0U) {
722*91f16700Schasinglulu 		WARN("Buffer size must be aligned to translation granule.\n");
723*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
724*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
725*91f16700Schasinglulu 	}
726*91f16700Schasinglulu 
727*91f16700Schasinglulu 	/* Obtain the RX/TX buffer pair descriptor. */
728*91f16700Schasinglulu 	mbox = spmc_get_mbox_desc(secure_origin);
729*91f16700Schasinglulu 
730*91f16700Schasinglulu 	spin_lock(&mbox->lock);
731*91f16700Schasinglulu 
732*91f16700Schasinglulu 	/* Check if buffers have already been mapped. */
733*91f16700Schasinglulu 	if (mbox->rx_buffer != 0 || mbox->tx_buffer != 0) {
734*91f16700Schasinglulu 		WARN("RX/TX Buffers already mapped (%p/%p)\n",
735*91f16700Schasinglulu 		     (void *) mbox->rx_buffer, (void *)mbox->tx_buffer);
736*91f16700Schasinglulu 		error_code = FFA_ERROR_DENIED;
737*91f16700Schasinglulu 		goto err;
738*91f16700Schasinglulu 	}
739*91f16700Schasinglulu 
740*91f16700Schasinglulu 	/* memmap the TX buffer as read only. */
741*91f16700Schasinglulu 	ret = mmap_add_dynamic_region(tx_address, /* PA */
742*91f16700Schasinglulu 			tx_address, /* VA */
743*91f16700Schasinglulu 			buf_size, /* size */
744*91f16700Schasinglulu 			mem_atts | MT_RO_DATA); /* attrs */
745*91f16700Schasinglulu 	if (ret != 0) {
746*91f16700Schasinglulu 		/* Return the correct error code. */
747*91f16700Schasinglulu 		error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
748*91f16700Schasinglulu 						FFA_ERROR_INVALID_PARAMETER;
749*91f16700Schasinglulu 		WARN("Unable to map TX buffer: %d\n", error_code);
750*91f16700Schasinglulu 		goto err;
751*91f16700Schasinglulu 	}
752*91f16700Schasinglulu 
753*91f16700Schasinglulu 	/* memmap the RX buffer as read write. */
754*91f16700Schasinglulu 	ret = mmap_add_dynamic_region(rx_address, /* PA */
755*91f16700Schasinglulu 			rx_address, /* VA */
756*91f16700Schasinglulu 			buf_size, /* size */
757*91f16700Schasinglulu 			mem_atts | MT_RW_DATA); /* attrs */
758*91f16700Schasinglulu 
759*91f16700Schasinglulu 	if (ret != 0) {
760*91f16700Schasinglulu 		error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
761*91f16700Schasinglulu 						FFA_ERROR_INVALID_PARAMETER;
762*91f16700Schasinglulu 		WARN("Unable to map RX buffer: %d\n", error_code);
763*91f16700Schasinglulu 		/* Unmap the TX buffer again. */
764*91f16700Schasinglulu 		mmap_remove_dynamic_region(tx_address, buf_size);
765*91f16700Schasinglulu 		goto err;
766*91f16700Schasinglulu 	}
767*91f16700Schasinglulu 
768*91f16700Schasinglulu 	mbox->tx_buffer = (void *) tx_address;
769*91f16700Schasinglulu 	mbox->rx_buffer = (void *) rx_address;
770*91f16700Schasinglulu 	mbox->rxtx_page_count = page_count;
771*91f16700Schasinglulu 	spin_unlock(&mbox->lock);
772*91f16700Schasinglulu 
773*91f16700Schasinglulu 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
774*91f16700Schasinglulu 	/* Execution stops here. */
775*91f16700Schasinglulu err:
776*91f16700Schasinglulu 	spin_unlock(&mbox->lock);
777*91f16700Schasinglulu 	return spmc_ffa_error_return(handle, error_code);
778*91f16700Schasinglulu }
779*91f16700Schasinglulu 
780*91f16700Schasinglulu static uint64_t rxtx_unmap_handler(uint32_t smc_fid,
781*91f16700Schasinglulu 				   bool secure_origin,
782*91f16700Schasinglulu 				   uint64_t x1,
783*91f16700Schasinglulu 				   uint64_t x2,
784*91f16700Schasinglulu 				   uint64_t x3,
785*91f16700Schasinglulu 				   uint64_t x4,
786*91f16700Schasinglulu 				   void *cookie,
787*91f16700Schasinglulu 				   void *handle,
788*91f16700Schasinglulu 				   uint64_t flags)
789*91f16700Schasinglulu {
790*91f16700Schasinglulu 	struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
791*91f16700Schasinglulu 	uint32_t buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
792*91f16700Schasinglulu 
793*91f16700Schasinglulu 	/*
794*91f16700Schasinglulu 	 * The SPMC does not support mapping of VM RX/TX pairs to facilitate
795*91f16700Schasinglulu 	 * indirect messaging with SPs. Check if the Hypervisor has invoked this
796*91f16700Schasinglulu 	 * ABI on behalf of a VM and reject it if this is the case.
797*91f16700Schasinglulu 	 */
798*91f16700Schasinglulu 	if (x1 != 0UL) {
799*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
800*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
801*91f16700Schasinglulu 	}
802*91f16700Schasinglulu 
803*91f16700Schasinglulu 	spin_lock(&mbox->lock);
804*91f16700Schasinglulu 
805*91f16700Schasinglulu 	/* Check if buffers are currently mapped. */
806*91f16700Schasinglulu 	if (mbox->rx_buffer == 0 || mbox->tx_buffer == 0) {
807*91f16700Schasinglulu 		spin_unlock(&mbox->lock);
808*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
809*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
810*91f16700Schasinglulu 	}
811*91f16700Schasinglulu 
812*91f16700Schasinglulu 	/* Unmap RX Buffer */
813*91f16700Schasinglulu 	if (mmap_remove_dynamic_region((uintptr_t) mbox->rx_buffer,
814*91f16700Schasinglulu 				       buf_size) != 0) {
815*91f16700Schasinglulu 		WARN("Unable to unmap RX buffer!\n");
816*91f16700Schasinglulu 	}
817*91f16700Schasinglulu 
818*91f16700Schasinglulu 	mbox->rx_buffer = 0;
819*91f16700Schasinglulu 
820*91f16700Schasinglulu 	/* Unmap TX Buffer */
821*91f16700Schasinglulu 	if (mmap_remove_dynamic_region((uintptr_t) mbox->tx_buffer,
822*91f16700Schasinglulu 				       buf_size) != 0) {
823*91f16700Schasinglulu 		WARN("Unable to unmap TX buffer!\n");
824*91f16700Schasinglulu 	}
825*91f16700Schasinglulu 
826*91f16700Schasinglulu 	mbox->tx_buffer = 0;
827*91f16700Schasinglulu 	mbox->rxtx_page_count = 0;
828*91f16700Schasinglulu 
829*91f16700Schasinglulu 	spin_unlock(&mbox->lock);
830*91f16700Schasinglulu 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
831*91f16700Schasinglulu }
832*91f16700Schasinglulu 
833*91f16700Schasinglulu /*
834*91f16700Schasinglulu  * Helper function to populate the properties field of a Partition Info Get
835*91f16700Schasinglulu  * descriptor.
836*91f16700Schasinglulu  */
837*91f16700Schasinglulu static uint32_t
838*91f16700Schasinglulu partition_info_get_populate_properties(uint32_t sp_properties,
839*91f16700Schasinglulu 				       enum sp_execution_state sp_ec_state)
840*91f16700Schasinglulu {
841*91f16700Schasinglulu 	uint32_t properties = sp_properties;
842*91f16700Schasinglulu 	uint32_t ec_state;
843*91f16700Schasinglulu 
844*91f16700Schasinglulu 	/* Determine the execution state of the SP. */
845*91f16700Schasinglulu 	ec_state = sp_ec_state == SP_STATE_AARCH64 ?
846*91f16700Schasinglulu 		   FFA_PARTITION_INFO_GET_AARCH64_STATE :
847*91f16700Schasinglulu 		   FFA_PARTITION_INFO_GET_AARCH32_STATE;
848*91f16700Schasinglulu 
849*91f16700Schasinglulu 	properties |= ec_state << FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT;
850*91f16700Schasinglulu 
851*91f16700Schasinglulu 	return properties;
852*91f16700Schasinglulu }
853*91f16700Schasinglulu 
854*91f16700Schasinglulu /*
855*91f16700Schasinglulu  * Collate the partition information in a v1.1 partition information
856*91f16700Schasinglulu  * descriptor format, this will be converter later if required.
857*91f16700Schasinglulu  */
858*91f16700Schasinglulu static int partition_info_get_handler_v1_1(uint32_t *uuid,
859*91f16700Schasinglulu 					   struct ffa_partition_info_v1_1
860*91f16700Schasinglulu 						  *partitions,
861*91f16700Schasinglulu 					   uint32_t max_partitions,
862*91f16700Schasinglulu 					   uint32_t *partition_count)
863*91f16700Schasinglulu {
864*91f16700Schasinglulu 	uint32_t index;
865*91f16700Schasinglulu 	struct ffa_partition_info_v1_1 *desc;
866*91f16700Schasinglulu 	bool null_uuid = is_null_uuid(uuid);
867*91f16700Schasinglulu 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
868*91f16700Schasinglulu 
869*91f16700Schasinglulu 	/* Deal with Logical Partitions. */
870*91f16700Schasinglulu 	for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
871*91f16700Schasinglulu 		if (null_uuid || uuid_match(uuid, el3_lp_descs[index].uuid)) {
872*91f16700Schasinglulu 			/* Found a matching UUID, populate appropriately. */
873*91f16700Schasinglulu 			if (*partition_count >= max_partitions) {
874*91f16700Schasinglulu 				return FFA_ERROR_NO_MEMORY;
875*91f16700Schasinglulu 			}
876*91f16700Schasinglulu 
877*91f16700Schasinglulu 			desc = &partitions[*partition_count];
878*91f16700Schasinglulu 			desc->ep_id = el3_lp_descs[index].sp_id;
879*91f16700Schasinglulu 			desc->execution_ctx_count = PLATFORM_CORE_COUNT;
880*91f16700Schasinglulu 			/* LSPs must be AArch64. */
881*91f16700Schasinglulu 			desc->properties =
882*91f16700Schasinglulu 				partition_info_get_populate_properties(
883*91f16700Schasinglulu 					el3_lp_descs[index].properties,
884*91f16700Schasinglulu 					SP_STATE_AARCH64);
885*91f16700Schasinglulu 
886*91f16700Schasinglulu 			if (null_uuid) {
887*91f16700Schasinglulu 				copy_uuid(desc->uuid, el3_lp_descs[index].uuid);
888*91f16700Schasinglulu 			}
889*91f16700Schasinglulu 			(*partition_count)++;
890*91f16700Schasinglulu 		}
891*91f16700Schasinglulu 	}
892*91f16700Schasinglulu 
893*91f16700Schasinglulu 	/* Deal with physical SP's. */
894*91f16700Schasinglulu 	for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
895*91f16700Schasinglulu 		if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) {
896*91f16700Schasinglulu 			/* Found a matching UUID, populate appropriately. */
897*91f16700Schasinglulu 			if (*partition_count >= max_partitions) {
898*91f16700Schasinglulu 				return FFA_ERROR_NO_MEMORY;
899*91f16700Schasinglulu 			}
900*91f16700Schasinglulu 
901*91f16700Schasinglulu 			desc = &partitions[*partition_count];
902*91f16700Schasinglulu 			desc->ep_id = sp_desc[index].sp_id;
903*91f16700Schasinglulu 			/*
904*91f16700Schasinglulu 			 * Execution context count must match No. cores for
905*91f16700Schasinglulu 			 * S-EL1 SPs.
906*91f16700Schasinglulu 			 */
907*91f16700Schasinglulu 			desc->execution_ctx_count = PLATFORM_CORE_COUNT;
908*91f16700Schasinglulu 			desc->properties =
909*91f16700Schasinglulu 				partition_info_get_populate_properties(
910*91f16700Schasinglulu 					sp_desc[index].properties,
911*91f16700Schasinglulu 					sp_desc[index].execution_state);
912*91f16700Schasinglulu 
913*91f16700Schasinglulu 			if (null_uuid) {
914*91f16700Schasinglulu 				copy_uuid(desc->uuid, sp_desc[index].uuid);
915*91f16700Schasinglulu 			}
916*91f16700Schasinglulu 			(*partition_count)++;
917*91f16700Schasinglulu 		}
918*91f16700Schasinglulu 	}
919*91f16700Schasinglulu 	return 0;
920*91f16700Schasinglulu }
921*91f16700Schasinglulu 
922*91f16700Schasinglulu /*
923*91f16700Schasinglulu  * Handle the case where that caller only wants the count of partitions
924*91f16700Schasinglulu  * matching a given UUID and does not want the corresponding descriptors
925*91f16700Schasinglulu  * populated.
926*91f16700Schasinglulu  */
927*91f16700Schasinglulu static uint32_t partition_info_get_handler_count_only(uint32_t *uuid)
928*91f16700Schasinglulu {
929*91f16700Schasinglulu 	uint32_t index = 0;
930*91f16700Schasinglulu 	uint32_t partition_count = 0;
931*91f16700Schasinglulu 	bool null_uuid = is_null_uuid(uuid);
932*91f16700Schasinglulu 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
933*91f16700Schasinglulu 
934*91f16700Schasinglulu 	/* Deal with Logical Partitions. */
935*91f16700Schasinglulu 	for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
936*91f16700Schasinglulu 		if (null_uuid ||
937*91f16700Schasinglulu 		    uuid_match(uuid, el3_lp_descs[index].uuid)) {
938*91f16700Schasinglulu 			(partition_count)++;
939*91f16700Schasinglulu 		}
940*91f16700Schasinglulu 	}
941*91f16700Schasinglulu 
942*91f16700Schasinglulu 	/* Deal with physical SP's. */
943*91f16700Schasinglulu 	for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
944*91f16700Schasinglulu 		if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) {
945*91f16700Schasinglulu 			(partition_count)++;
946*91f16700Schasinglulu 		}
947*91f16700Schasinglulu 	}
948*91f16700Schasinglulu 	return partition_count;
949*91f16700Schasinglulu }
950*91f16700Schasinglulu 
951*91f16700Schasinglulu /*
952*91f16700Schasinglulu  * If the caller of the PARTITION_INFO_GET ABI was a v1.0 caller, populate
953*91f16700Schasinglulu  * the corresponding descriptor format from the v1.1 descriptor array.
954*91f16700Schasinglulu  */
955*91f16700Schasinglulu static uint64_t partition_info_populate_v1_0(struct ffa_partition_info_v1_1
956*91f16700Schasinglulu 					     *partitions,
957*91f16700Schasinglulu 					     struct mailbox *mbox,
958*91f16700Schasinglulu 					     int partition_count)
959*91f16700Schasinglulu {
960*91f16700Schasinglulu 	uint32_t index;
961*91f16700Schasinglulu 	uint32_t buf_size;
962*91f16700Schasinglulu 	uint32_t descriptor_size;
963*91f16700Schasinglulu 	struct ffa_partition_info_v1_0 *v1_0_partitions =
964*91f16700Schasinglulu 		(struct ffa_partition_info_v1_0 *) mbox->rx_buffer;
965*91f16700Schasinglulu 
966*91f16700Schasinglulu 	buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
967*91f16700Schasinglulu 	descriptor_size = partition_count *
968*91f16700Schasinglulu 			  sizeof(struct ffa_partition_info_v1_0);
969*91f16700Schasinglulu 
970*91f16700Schasinglulu 	if (descriptor_size > buf_size) {
971*91f16700Schasinglulu 		return FFA_ERROR_NO_MEMORY;
972*91f16700Schasinglulu 	}
973*91f16700Schasinglulu 
974*91f16700Schasinglulu 	for (index = 0U; index < partition_count; index++) {
975*91f16700Schasinglulu 		v1_0_partitions[index].ep_id = partitions[index].ep_id;
976*91f16700Schasinglulu 		v1_0_partitions[index].execution_ctx_count =
977*91f16700Schasinglulu 			partitions[index].execution_ctx_count;
978*91f16700Schasinglulu 		/* Only report v1.0 properties. */
979*91f16700Schasinglulu 		v1_0_partitions[index].properties =
980*91f16700Schasinglulu 			(partitions[index].properties &
981*91f16700Schasinglulu 			FFA_PARTITION_INFO_GET_PROPERTIES_V1_0_MASK);
982*91f16700Schasinglulu 	}
983*91f16700Schasinglulu 	return 0;
984*91f16700Schasinglulu }
985*91f16700Schasinglulu 
986*91f16700Schasinglulu /*
987*91f16700Schasinglulu  * Main handler for FFA_PARTITION_INFO_GET which supports both FF-A v1.1 and
988*91f16700Schasinglulu  * v1.0 implementations.
989*91f16700Schasinglulu  */
990*91f16700Schasinglulu static uint64_t partition_info_get_handler(uint32_t smc_fid,
991*91f16700Schasinglulu 					   bool secure_origin,
992*91f16700Schasinglulu 					   uint64_t x1,
993*91f16700Schasinglulu 					   uint64_t x2,
994*91f16700Schasinglulu 					   uint64_t x3,
995*91f16700Schasinglulu 					   uint64_t x4,
996*91f16700Schasinglulu 					   void *cookie,
997*91f16700Schasinglulu 					   void *handle,
998*91f16700Schasinglulu 					   uint64_t flags)
999*91f16700Schasinglulu {
1000*91f16700Schasinglulu 	int ret;
1001*91f16700Schasinglulu 	uint32_t partition_count = 0;
1002*91f16700Schasinglulu 	uint32_t size = 0;
1003*91f16700Schasinglulu 	uint32_t ffa_version = get_partition_ffa_version(secure_origin);
1004*91f16700Schasinglulu 	struct mailbox *mbox;
1005*91f16700Schasinglulu 	uint64_t info_get_flags;
1006*91f16700Schasinglulu 	bool count_only;
1007*91f16700Schasinglulu 	uint32_t uuid[4];
1008*91f16700Schasinglulu 
1009*91f16700Schasinglulu 	uuid[0] = x1;
1010*91f16700Schasinglulu 	uuid[1] = x2;
1011*91f16700Schasinglulu 	uuid[2] = x3;
1012*91f16700Schasinglulu 	uuid[3] = x4;
1013*91f16700Schasinglulu 
1014*91f16700Schasinglulu 	/* Determine if the Partition descriptors should be populated. */
1015*91f16700Schasinglulu 	info_get_flags = SMC_GET_GP(handle, CTX_GPREG_X5);
1016*91f16700Schasinglulu 	count_only = (info_get_flags & FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK);
1017*91f16700Schasinglulu 
1018*91f16700Schasinglulu 	/* Handle the case where we don't need to populate the descriptors. */
1019*91f16700Schasinglulu 	if (count_only) {
1020*91f16700Schasinglulu 		partition_count = partition_info_get_handler_count_only(uuid);
1021*91f16700Schasinglulu 		if (partition_count == 0) {
1022*91f16700Schasinglulu 			return spmc_ffa_error_return(handle,
1023*91f16700Schasinglulu 						FFA_ERROR_INVALID_PARAMETER);
1024*91f16700Schasinglulu 		}
1025*91f16700Schasinglulu 	} else {
1026*91f16700Schasinglulu 		struct ffa_partition_info_v1_1 partitions[MAX_SP_LP_PARTITIONS];
1027*91f16700Schasinglulu 
1028*91f16700Schasinglulu 		/*
1029*91f16700Schasinglulu 		 * Handle the case where the partition descriptors are required,
1030*91f16700Schasinglulu 		 * check we have the buffers available and populate the
1031*91f16700Schasinglulu 		 * appropriate structure version.
1032*91f16700Schasinglulu 		 */
1033*91f16700Schasinglulu 
1034*91f16700Schasinglulu 		/* Obtain the v1.1 format of the descriptors. */
1035*91f16700Schasinglulu 		ret = partition_info_get_handler_v1_1(uuid, partitions,
1036*91f16700Schasinglulu 						      MAX_SP_LP_PARTITIONS,
1037*91f16700Schasinglulu 						      &partition_count);
1038*91f16700Schasinglulu 
1039*91f16700Schasinglulu 		/* Check if an error occurred during discovery. */
1040*91f16700Schasinglulu 		if (ret != 0) {
1041*91f16700Schasinglulu 			goto err;
1042*91f16700Schasinglulu 		}
1043*91f16700Schasinglulu 
1044*91f16700Schasinglulu 		/* If we didn't find any matches the UUID is unknown. */
1045*91f16700Schasinglulu 		if (partition_count == 0) {
1046*91f16700Schasinglulu 			ret = FFA_ERROR_INVALID_PARAMETER;
1047*91f16700Schasinglulu 			goto err;
1048*91f16700Schasinglulu 		}
1049*91f16700Schasinglulu 
1050*91f16700Schasinglulu 		/* Obtain the partition mailbox RX/TX buffer pair descriptor. */
1051*91f16700Schasinglulu 		mbox = spmc_get_mbox_desc(secure_origin);
1052*91f16700Schasinglulu 
1053*91f16700Schasinglulu 		/*
1054*91f16700Schasinglulu 		 * If the caller has not bothered registering its RX/TX pair
1055*91f16700Schasinglulu 		 * then return an error code.
1056*91f16700Schasinglulu 		 */
1057*91f16700Schasinglulu 		spin_lock(&mbox->lock);
1058*91f16700Schasinglulu 		if (mbox->rx_buffer == NULL) {
1059*91f16700Schasinglulu 			ret = FFA_ERROR_BUSY;
1060*91f16700Schasinglulu 			goto err_unlock;
1061*91f16700Schasinglulu 		}
1062*91f16700Schasinglulu 
1063*91f16700Schasinglulu 		/* Ensure the RX buffer is currently free. */
1064*91f16700Schasinglulu 		if (mbox->state != MAILBOX_STATE_EMPTY) {
1065*91f16700Schasinglulu 			ret = FFA_ERROR_BUSY;
1066*91f16700Schasinglulu 			goto err_unlock;
1067*91f16700Schasinglulu 		}
1068*91f16700Schasinglulu 
1069*91f16700Schasinglulu 		/* Zero the RX buffer before populating. */
1070*91f16700Schasinglulu 		(void)memset(mbox->rx_buffer, 0,
1071*91f16700Schasinglulu 			     mbox->rxtx_page_count * FFA_PAGE_SIZE);
1072*91f16700Schasinglulu 
1073*91f16700Schasinglulu 		/*
1074*91f16700Schasinglulu 		 * Depending on the FF-A version of the requesting partition
1075*91f16700Schasinglulu 		 * we may need to convert to a v1.0 format otherwise we can copy
1076*91f16700Schasinglulu 		 * directly.
1077*91f16700Schasinglulu 		 */
1078*91f16700Schasinglulu 		if (ffa_version == MAKE_FFA_VERSION(U(1), U(0))) {
1079*91f16700Schasinglulu 			ret = partition_info_populate_v1_0(partitions,
1080*91f16700Schasinglulu 							   mbox,
1081*91f16700Schasinglulu 							   partition_count);
1082*91f16700Schasinglulu 			if (ret != 0) {
1083*91f16700Schasinglulu 				goto err_unlock;
1084*91f16700Schasinglulu 			}
1085*91f16700Schasinglulu 		} else {
1086*91f16700Schasinglulu 			uint32_t buf_size = mbox->rxtx_page_count *
1087*91f16700Schasinglulu 					    FFA_PAGE_SIZE;
1088*91f16700Schasinglulu 
1089*91f16700Schasinglulu 			/* Ensure the descriptor will fit in the buffer. */
1090*91f16700Schasinglulu 			size = sizeof(struct ffa_partition_info_v1_1);
1091*91f16700Schasinglulu 			if (partition_count * size  > buf_size) {
1092*91f16700Schasinglulu 				ret = FFA_ERROR_NO_MEMORY;
1093*91f16700Schasinglulu 				goto err_unlock;
1094*91f16700Schasinglulu 			}
1095*91f16700Schasinglulu 			memcpy(mbox->rx_buffer, partitions,
1096*91f16700Schasinglulu 			       partition_count * size);
1097*91f16700Schasinglulu 		}
1098*91f16700Schasinglulu 
1099*91f16700Schasinglulu 		mbox->state = MAILBOX_STATE_FULL;
1100*91f16700Schasinglulu 		spin_unlock(&mbox->lock);
1101*91f16700Schasinglulu 	}
1102*91f16700Schasinglulu 	SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, partition_count, size);
1103*91f16700Schasinglulu 
1104*91f16700Schasinglulu err_unlock:
1105*91f16700Schasinglulu 	spin_unlock(&mbox->lock);
1106*91f16700Schasinglulu err:
1107*91f16700Schasinglulu 	return spmc_ffa_error_return(handle, ret);
1108*91f16700Schasinglulu }
1109*91f16700Schasinglulu 
1110*91f16700Schasinglulu static uint64_t ffa_feature_success(void *handle, uint32_t arg2)
1111*91f16700Schasinglulu {
1112*91f16700Schasinglulu 	SMC_RET3(handle, FFA_SUCCESS_SMC32, 0, arg2);
1113*91f16700Schasinglulu }
1114*91f16700Schasinglulu 
1115*91f16700Schasinglulu static uint64_t ffa_features_retrieve_request(bool secure_origin,
1116*91f16700Schasinglulu 					      uint32_t input_properties,
1117*91f16700Schasinglulu 					      void *handle)
1118*91f16700Schasinglulu {
1119*91f16700Schasinglulu 	/*
1120*91f16700Schasinglulu 	 * If we're called by the normal world we don't support any
1121*91f16700Schasinglulu 	 * additional features.
1122*91f16700Schasinglulu 	 */
1123*91f16700Schasinglulu 	if (!secure_origin) {
1124*91f16700Schasinglulu 		if ((input_properties & FFA_FEATURES_RET_REQ_NS_BIT) != 0U) {
1125*91f16700Schasinglulu 			return spmc_ffa_error_return(handle,
1126*91f16700Schasinglulu 						     FFA_ERROR_NOT_SUPPORTED);
1127*91f16700Schasinglulu 		}
1128*91f16700Schasinglulu 
1129*91f16700Schasinglulu 	} else {
1130*91f16700Schasinglulu 		struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
1131*91f16700Schasinglulu 		/*
1132*91f16700Schasinglulu 		 * If v1.1 the NS bit must be set otherwise it is an invalid
1133*91f16700Schasinglulu 		 * call. If v1.0 check and store whether the SP has requested
1134*91f16700Schasinglulu 		 * the use of the NS bit.
1135*91f16700Schasinglulu 		 */
1136*91f16700Schasinglulu 		if (sp->ffa_version == MAKE_FFA_VERSION(1, 1)) {
1137*91f16700Schasinglulu 			if ((input_properties &
1138*91f16700Schasinglulu 			     FFA_FEATURES_RET_REQ_NS_BIT) == 0U) {
1139*91f16700Schasinglulu 				return spmc_ffa_error_return(handle,
1140*91f16700Schasinglulu 						       FFA_ERROR_NOT_SUPPORTED);
1141*91f16700Schasinglulu 			}
1142*91f16700Schasinglulu 			return ffa_feature_success(handle,
1143*91f16700Schasinglulu 						   FFA_FEATURES_RET_REQ_NS_BIT);
1144*91f16700Schasinglulu 		} else {
1145*91f16700Schasinglulu 			sp->ns_bit_requested = (input_properties &
1146*91f16700Schasinglulu 					       FFA_FEATURES_RET_REQ_NS_BIT) !=
1147*91f16700Schasinglulu 					       0U;
1148*91f16700Schasinglulu 		}
1149*91f16700Schasinglulu 		if (sp->ns_bit_requested) {
1150*91f16700Schasinglulu 			return ffa_feature_success(handle,
1151*91f16700Schasinglulu 						   FFA_FEATURES_RET_REQ_NS_BIT);
1152*91f16700Schasinglulu 		}
1153*91f16700Schasinglulu 	}
1154*91f16700Schasinglulu 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
1155*91f16700Schasinglulu }
1156*91f16700Schasinglulu 
1157*91f16700Schasinglulu static uint64_t ffa_features_handler(uint32_t smc_fid,
1158*91f16700Schasinglulu 				     bool secure_origin,
1159*91f16700Schasinglulu 				     uint64_t x1,
1160*91f16700Schasinglulu 				     uint64_t x2,
1161*91f16700Schasinglulu 				     uint64_t x3,
1162*91f16700Schasinglulu 				     uint64_t x4,
1163*91f16700Schasinglulu 				     void *cookie,
1164*91f16700Schasinglulu 				     void *handle,
1165*91f16700Schasinglulu 				     uint64_t flags)
1166*91f16700Schasinglulu {
1167*91f16700Schasinglulu 	uint32_t function_id = (uint32_t) x1;
1168*91f16700Schasinglulu 	uint32_t input_properties = (uint32_t) x2;
1169*91f16700Schasinglulu 
1170*91f16700Schasinglulu 	/* Check if a Feature ID was requested. */
1171*91f16700Schasinglulu 	if ((function_id & FFA_FEATURES_BIT31_MASK) == 0U) {
1172*91f16700Schasinglulu 		/* We currently don't support any additional features. */
1173*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
1174*91f16700Schasinglulu 	}
1175*91f16700Schasinglulu 
1176*91f16700Schasinglulu 	/*
1177*91f16700Schasinglulu 	 * Handle the cases where we have separate handlers due to additional
1178*91f16700Schasinglulu 	 * properties.
1179*91f16700Schasinglulu 	 */
1180*91f16700Schasinglulu 	switch (function_id) {
1181*91f16700Schasinglulu 	case FFA_MEM_RETRIEVE_REQ_SMC32:
1182*91f16700Schasinglulu 	case FFA_MEM_RETRIEVE_REQ_SMC64:
1183*91f16700Schasinglulu 		return ffa_features_retrieve_request(secure_origin,
1184*91f16700Schasinglulu 						     input_properties,
1185*91f16700Schasinglulu 						     handle);
1186*91f16700Schasinglulu 	}
1187*91f16700Schasinglulu 
1188*91f16700Schasinglulu 	/*
1189*91f16700Schasinglulu 	 * We don't currently support additional input properties for these
1190*91f16700Schasinglulu 	 * other ABIs therefore ensure this value is set to 0.
1191*91f16700Schasinglulu 	 */
1192*91f16700Schasinglulu 	if (input_properties != 0U) {
1193*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1194*91f16700Schasinglulu 					     FFA_ERROR_NOT_SUPPORTED);
1195*91f16700Schasinglulu 	}
1196*91f16700Schasinglulu 
1197*91f16700Schasinglulu 	/* Report if any other FF-A ABI is supported. */
1198*91f16700Schasinglulu 	switch (function_id) {
1199*91f16700Schasinglulu 	/* Supported features from both worlds. */
1200*91f16700Schasinglulu 	case FFA_ERROR:
1201*91f16700Schasinglulu 	case FFA_SUCCESS_SMC32:
1202*91f16700Schasinglulu 	case FFA_INTERRUPT:
1203*91f16700Schasinglulu 	case FFA_SPM_ID_GET:
1204*91f16700Schasinglulu 	case FFA_ID_GET:
1205*91f16700Schasinglulu 	case FFA_FEATURES:
1206*91f16700Schasinglulu 	case FFA_VERSION:
1207*91f16700Schasinglulu 	case FFA_RX_RELEASE:
1208*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
1209*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
1210*91f16700Schasinglulu 	case FFA_PARTITION_INFO_GET:
1211*91f16700Schasinglulu 	case FFA_RXTX_MAP_SMC32:
1212*91f16700Schasinglulu 	case FFA_RXTX_MAP_SMC64:
1213*91f16700Schasinglulu 	case FFA_RXTX_UNMAP:
1214*91f16700Schasinglulu 	case FFA_MEM_FRAG_TX:
1215*91f16700Schasinglulu 	case FFA_MSG_RUN:
1216*91f16700Schasinglulu 
1217*91f16700Schasinglulu 		/*
1218*91f16700Schasinglulu 		 * We are relying on the fact that the other registers
1219*91f16700Schasinglulu 		 * will be set to 0 as these values align with the
1220*91f16700Schasinglulu 		 * currently implemented features of the SPMC. If this
1221*91f16700Schasinglulu 		 * changes this function must be extended to handle
1222*91f16700Schasinglulu 		 * reporting the additional functionality.
1223*91f16700Schasinglulu 		 */
1224*91f16700Schasinglulu 
1225*91f16700Schasinglulu 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
1226*91f16700Schasinglulu 		/* Execution stops here. */
1227*91f16700Schasinglulu 
1228*91f16700Schasinglulu 	/* Supported ABIs only from the secure world. */
1229*91f16700Schasinglulu 	case FFA_SECONDARY_EP_REGISTER_SMC64:
1230*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
1231*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
1232*91f16700Schasinglulu 	case FFA_MEM_RELINQUISH:
1233*91f16700Schasinglulu 	case FFA_MSG_WAIT:
1234*91f16700Schasinglulu 
1235*91f16700Schasinglulu 		if (!secure_origin) {
1236*91f16700Schasinglulu 			return spmc_ffa_error_return(handle,
1237*91f16700Schasinglulu 				FFA_ERROR_NOT_SUPPORTED);
1238*91f16700Schasinglulu 		}
1239*91f16700Schasinglulu 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
1240*91f16700Schasinglulu 		/* Execution stops here. */
1241*91f16700Schasinglulu 
1242*91f16700Schasinglulu 	/* Supported features only from the normal world. */
1243*91f16700Schasinglulu 	case FFA_MEM_SHARE_SMC32:
1244*91f16700Schasinglulu 	case FFA_MEM_SHARE_SMC64:
1245*91f16700Schasinglulu 	case FFA_MEM_LEND_SMC32:
1246*91f16700Schasinglulu 	case FFA_MEM_LEND_SMC64:
1247*91f16700Schasinglulu 	case FFA_MEM_RECLAIM:
1248*91f16700Schasinglulu 	case FFA_MEM_FRAG_RX:
1249*91f16700Schasinglulu 
1250*91f16700Schasinglulu 		if (secure_origin) {
1251*91f16700Schasinglulu 			return spmc_ffa_error_return(handle,
1252*91f16700Schasinglulu 					FFA_ERROR_NOT_SUPPORTED);
1253*91f16700Schasinglulu 		}
1254*91f16700Schasinglulu 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
1255*91f16700Schasinglulu 		/* Execution stops here. */
1256*91f16700Schasinglulu 
1257*91f16700Schasinglulu 	default:
1258*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1259*91f16700Schasinglulu 					FFA_ERROR_NOT_SUPPORTED);
1260*91f16700Schasinglulu 	}
1261*91f16700Schasinglulu }
1262*91f16700Schasinglulu 
1263*91f16700Schasinglulu static uint64_t ffa_id_get_handler(uint32_t smc_fid,
1264*91f16700Schasinglulu 				   bool secure_origin,
1265*91f16700Schasinglulu 				   uint64_t x1,
1266*91f16700Schasinglulu 				   uint64_t x2,
1267*91f16700Schasinglulu 				   uint64_t x3,
1268*91f16700Schasinglulu 				   uint64_t x4,
1269*91f16700Schasinglulu 				   void *cookie,
1270*91f16700Schasinglulu 				   void *handle,
1271*91f16700Schasinglulu 				   uint64_t flags)
1272*91f16700Schasinglulu {
1273*91f16700Schasinglulu 	if (secure_origin) {
1274*91f16700Schasinglulu 		SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
1275*91f16700Schasinglulu 			 spmc_get_current_sp_ctx()->sp_id);
1276*91f16700Schasinglulu 	} else {
1277*91f16700Schasinglulu 		SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
1278*91f16700Schasinglulu 			 spmc_get_hyp_ctx()->ns_ep_id);
1279*91f16700Schasinglulu 	}
1280*91f16700Schasinglulu }
1281*91f16700Schasinglulu 
1282*91f16700Schasinglulu /*
1283*91f16700Schasinglulu  * Enable an SP to query the ID assigned to the SPMC.
1284*91f16700Schasinglulu  */
1285*91f16700Schasinglulu static uint64_t ffa_spm_id_get_handler(uint32_t smc_fid,
1286*91f16700Schasinglulu 				       bool secure_origin,
1287*91f16700Schasinglulu 				       uint64_t x1,
1288*91f16700Schasinglulu 				       uint64_t x2,
1289*91f16700Schasinglulu 				       uint64_t x3,
1290*91f16700Schasinglulu 				       uint64_t x4,
1291*91f16700Schasinglulu 				       void *cookie,
1292*91f16700Schasinglulu 				       void *handle,
1293*91f16700Schasinglulu 				       uint64_t flags)
1294*91f16700Schasinglulu {
1295*91f16700Schasinglulu 	assert(x1 == 0UL);
1296*91f16700Schasinglulu 	assert(x2 == 0UL);
1297*91f16700Schasinglulu 	assert(x3 == 0UL);
1298*91f16700Schasinglulu 	assert(x4 == 0UL);
1299*91f16700Schasinglulu 	assert(SMC_GET_GP(handle, CTX_GPREG_X5) == 0UL);
1300*91f16700Schasinglulu 	assert(SMC_GET_GP(handle, CTX_GPREG_X6) == 0UL);
1301*91f16700Schasinglulu 	assert(SMC_GET_GP(handle, CTX_GPREG_X7) == 0UL);
1302*91f16700Schasinglulu 
1303*91f16700Schasinglulu 	SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0, FFA_SPMC_ID);
1304*91f16700Schasinglulu }
1305*91f16700Schasinglulu 
1306*91f16700Schasinglulu static uint64_t ffa_run_handler(uint32_t smc_fid,
1307*91f16700Schasinglulu 				bool secure_origin,
1308*91f16700Schasinglulu 				uint64_t x1,
1309*91f16700Schasinglulu 				uint64_t x2,
1310*91f16700Schasinglulu 				uint64_t x3,
1311*91f16700Schasinglulu 				uint64_t x4,
1312*91f16700Schasinglulu 				void *cookie,
1313*91f16700Schasinglulu 				void *handle,
1314*91f16700Schasinglulu 				uint64_t flags)
1315*91f16700Schasinglulu {
1316*91f16700Schasinglulu 	struct secure_partition_desc *sp;
1317*91f16700Schasinglulu 	uint16_t target_id = FFA_RUN_EP_ID(x1);
1318*91f16700Schasinglulu 	uint16_t vcpu_id = FFA_RUN_VCPU_ID(x1);
1319*91f16700Schasinglulu 	unsigned int idx;
1320*91f16700Schasinglulu 	unsigned int *rt_state;
1321*91f16700Schasinglulu 	unsigned int *rt_model;
1322*91f16700Schasinglulu 
1323*91f16700Schasinglulu 	/* Can only be called from the normal world. */
1324*91f16700Schasinglulu 	if (secure_origin) {
1325*91f16700Schasinglulu 		ERROR("FFA_RUN can only be called from NWd.\n");
1326*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1327*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1328*91f16700Schasinglulu 	}
1329*91f16700Schasinglulu 
1330*91f16700Schasinglulu 	/* Cannot run a Normal world partition. */
1331*91f16700Schasinglulu 	if (ffa_is_normal_world_id(target_id)) {
1332*91f16700Schasinglulu 		ERROR("Cannot run a NWd partition (0x%x).\n", target_id);
1333*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1334*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1335*91f16700Schasinglulu 	}
1336*91f16700Schasinglulu 
1337*91f16700Schasinglulu 	/* Check that the target SP exists. */
1338*91f16700Schasinglulu 	sp = spmc_get_sp_ctx(target_id);
1339*91f16700Schasinglulu 		ERROR("Unknown partition ID (0x%x).\n", target_id);
1340*91f16700Schasinglulu 	if (sp == NULL) {
1341*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1342*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1343*91f16700Schasinglulu 	}
1344*91f16700Schasinglulu 
1345*91f16700Schasinglulu 	idx = get_ec_index(sp);
1346*91f16700Schasinglulu 	if (idx != vcpu_id) {
1347*91f16700Schasinglulu 		ERROR("Cannot run vcpu %d != %d.\n", idx, vcpu_id);
1348*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1349*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1350*91f16700Schasinglulu 	}
1351*91f16700Schasinglulu 	rt_state = &((sp->ec[idx]).rt_state);
1352*91f16700Schasinglulu 	rt_model = &((sp->ec[idx]).rt_model);
1353*91f16700Schasinglulu 	if (*rt_state == RT_STATE_RUNNING) {
1354*91f16700Schasinglulu 		ERROR("Partition (0x%x) is already running.\n", target_id);
1355*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
1356*91f16700Schasinglulu 	}
1357*91f16700Schasinglulu 
1358*91f16700Schasinglulu 	/*
1359*91f16700Schasinglulu 	 * Sanity check that if the execution context was not waiting then it
1360*91f16700Schasinglulu 	 * was either in the direct request or the run partition runtime model.
1361*91f16700Schasinglulu 	 */
1362*91f16700Schasinglulu 	if (*rt_state == RT_STATE_PREEMPTED || *rt_state == RT_STATE_BLOCKED) {
1363*91f16700Schasinglulu 		assert(*rt_model == RT_MODEL_RUN ||
1364*91f16700Schasinglulu 		       *rt_model == RT_MODEL_DIR_REQ);
1365*91f16700Schasinglulu 	}
1366*91f16700Schasinglulu 
1367*91f16700Schasinglulu 	/*
1368*91f16700Schasinglulu 	 * If the context was waiting then update the partition runtime model.
1369*91f16700Schasinglulu 	 */
1370*91f16700Schasinglulu 	if (*rt_state == RT_STATE_WAITING) {
1371*91f16700Schasinglulu 		*rt_model = RT_MODEL_RUN;
1372*91f16700Schasinglulu 	}
1373*91f16700Schasinglulu 
1374*91f16700Schasinglulu 	/*
1375*91f16700Schasinglulu 	 * Forward the request to the correct SP vCPU after updating
1376*91f16700Schasinglulu 	 * its state.
1377*91f16700Schasinglulu 	 */
1378*91f16700Schasinglulu 	*rt_state = RT_STATE_RUNNING;
1379*91f16700Schasinglulu 
1380*91f16700Schasinglulu 	return spmc_smc_return(smc_fid, secure_origin, x1, 0, 0, 0,
1381*91f16700Schasinglulu 			       handle, cookie, flags, target_id);
1382*91f16700Schasinglulu }
1383*91f16700Schasinglulu 
1384*91f16700Schasinglulu static uint64_t rx_release_handler(uint32_t smc_fid,
1385*91f16700Schasinglulu 				   bool secure_origin,
1386*91f16700Schasinglulu 				   uint64_t x1,
1387*91f16700Schasinglulu 				   uint64_t x2,
1388*91f16700Schasinglulu 				   uint64_t x3,
1389*91f16700Schasinglulu 				   uint64_t x4,
1390*91f16700Schasinglulu 				   void *cookie,
1391*91f16700Schasinglulu 				   void *handle,
1392*91f16700Schasinglulu 				   uint64_t flags)
1393*91f16700Schasinglulu {
1394*91f16700Schasinglulu 	struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
1395*91f16700Schasinglulu 
1396*91f16700Schasinglulu 	spin_lock(&mbox->lock);
1397*91f16700Schasinglulu 
1398*91f16700Schasinglulu 	if (mbox->state != MAILBOX_STATE_FULL) {
1399*91f16700Schasinglulu 		spin_unlock(&mbox->lock);
1400*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
1401*91f16700Schasinglulu 	}
1402*91f16700Schasinglulu 
1403*91f16700Schasinglulu 	mbox->state = MAILBOX_STATE_EMPTY;
1404*91f16700Schasinglulu 	spin_unlock(&mbox->lock);
1405*91f16700Schasinglulu 
1406*91f16700Schasinglulu 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
1407*91f16700Schasinglulu }
1408*91f16700Schasinglulu 
1409*91f16700Schasinglulu /*
1410*91f16700Schasinglulu  * Perform initial validation on the provided secondary entry point.
1411*91f16700Schasinglulu  * For now ensure it does not lie within the BL31 Image or the SP's
1412*91f16700Schasinglulu  * RX/TX buffers as these are mapped within EL3.
1413*91f16700Schasinglulu  * TODO: perform validation for additional invalid memory regions.
1414*91f16700Schasinglulu  */
1415*91f16700Schasinglulu static int validate_secondary_ep(uintptr_t ep, struct secure_partition_desc *sp)
1416*91f16700Schasinglulu {
1417*91f16700Schasinglulu 	struct mailbox *mb;
1418*91f16700Schasinglulu 	uintptr_t buffer_size;
1419*91f16700Schasinglulu 	uintptr_t sp_rx_buffer;
1420*91f16700Schasinglulu 	uintptr_t sp_tx_buffer;
1421*91f16700Schasinglulu 	uintptr_t sp_rx_buffer_limit;
1422*91f16700Schasinglulu 	uintptr_t sp_tx_buffer_limit;
1423*91f16700Schasinglulu 
1424*91f16700Schasinglulu 	mb = &sp->mailbox;
1425*91f16700Schasinglulu 	buffer_size = (uintptr_t) (mb->rxtx_page_count * FFA_PAGE_SIZE);
1426*91f16700Schasinglulu 	sp_rx_buffer = (uintptr_t) mb->rx_buffer;
1427*91f16700Schasinglulu 	sp_tx_buffer = (uintptr_t) mb->tx_buffer;
1428*91f16700Schasinglulu 	sp_rx_buffer_limit = sp_rx_buffer + buffer_size;
1429*91f16700Schasinglulu 	sp_tx_buffer_limit = sp_tx_buffer + buffer_size;
1430*91f16700Schasinglulu 
1431*91f16700Schasinglulu 	/*
1432*91f16700Schasinglulu 	 * Check if the entry point lies within BL31, or the
1433*91f16700Schasinglulu 	 * SP's RX or TX buffer.
1434*91f16700Schasinglulu 	 */
1435*91f16700Schasinglulu 	if ((ep >= BL31_BASE && ep < BL31_LIMIT) ||
1436*91f16700Schasinglulu 	    (ep >= sp_rx_buffer && ep < sp_rx_buffer_limit) ||
1437*91f16700Schasinglulu 	    (ep >= sp_tx_buffer && ep < sp_tx_buffer_limit)) {
1438*91f16700Schasinglulu 		return -EINVAL;
1439*91f16700Schasinglulu 	}
1440*91f16700Schasinglulu 	return 0;
1441*91f16700Schasinglulu }
1442*91f16700Schasinglulu 
1443*91f16700Schasinglulu /*******************************************************************************
1444*91f16700Schasinglulu  * This function handles the FFA_SECONDARY_EP_REGISTER SMC to allow an SP to
1445*91f16700Schasinglulu  *  register an entry point for initialization during a secondary cold boot.
1446*91f16700Schasinglulu  ******************************************************************************/
1447*91f16700Schasinglulu static uint64_t ffa_sec_ep_register_handler(uint32_t smc_fid,
1448*91f16700Schasinglulu 					    bool secure_origin,
1449*91f16700Schasinglulu 					    uint64_t x1,
1450*91f16700Schasinglulu 					    uint64_t x2,
1451*91f16700Schasinglulu 					    uint64_t x3,
1452*91f16700Schasinglulu 					    uint64_t x4,
1453*91f16700Schasinglulu 					    void *cookie,
1454*91f16700Schasinglulu 					    void *handle,
1455*91f16700Schasinglulu 					    uint64_t flags)
1456*91f16700Schasinglulu {
1457*91f16700Schasinglulu 	struct secure_partition_desc *sp;
1458*91f16700Schasinglulu 	struct sp_exec_ctx *sp_ctx;
1459*91f16700Schasinglulu 
1460*91f16700Schasinglulu 	/* This request cannot originate from the Normal world. */
1461*91f16700Schasinglulu 	if (!secure_origin) {
1462*91f16700Schasinglulu 		WARN("%s: Can only be called from SWd.\n", __func__);
1463*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
1464*91f16700Schasinglulu 	}
1465*91f16700Schasinglulu 
1466*91f16700Schasinglulu 	/* Get the context of the current SP. */
1467*91f16700Schasinglulu 	sp = spmc_get_current_sp_ctx();
1468*91f16700Schasinglulu 	if (sp == NULL) {
1469*91f16700Schasinglulu 		WARN("%s: Cannot find SP context.\n", __func__);
1470*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1471*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1472*91f16700Schasinglulu 	}
1473*91f16700Schasinglulu 
1474*91f16700Schasinglulu 	/* Only an S-EL1 SP should be invoking this ABI. */
1475*91f16700Schasinglulu 	if (sp->runtime_el != S_EL1) {
1476*91f16700Schasinglulu 		WARN("%s: Can only be called for a S-EL1 SP.\n", __func__);
1477*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
1478*91f16700Schasinglulu 	}
1479*91f16700Schasinglulu 
1480*91f16700Schasinglulu 	/* Ensure the SP is in its initialization state. */
1481*91f16700Schasinglulu 	sp_ctx = spmc_get_sp_ec(sp);
1482*91f16700Schasinglulu 	if (sp_ctx->rt_model != RT_MODEL_INIT) {
1483*91f16700Schasinglulu 		WARN("%s: Can only be called during SP initialization.\n",
1484*91f16700Schasinglulu 		     __func__);
1485*91f16700Schasinglulu 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
1486*91f16700Schasinglulu 	}
1487*91f16700Schasinglulu 
1488*91f16700Schasinglulu 	/* Perform initial validation of the secondary entry point. */
1489*91f16700Schasinglulu 	if (validate_secondary_ep(x1, sp)) {
1490*91f16700Schasinglulu 		WARN("%s: Invalid entry point provided (0x%lx).\n",
1491*91f16700Schasinglulu 		     __func__, x1);
1492*91f16700Schasinglulu 		return spmc_ffa_error_return(handle,
1493*91f16700Schasinglulu 					     FFA_ERROR_INVALID_PARAMETER);
1494*91f16700Schasinglulu 	}
1495*91f16700Schasinglulu 
1496*91f16700Schasinglulu 	/*
1497*91f16700Schasinglulu 	 * Update the secondary entrypoint in SP context.
1498*91f16700Schasinglulu 	 * We don't need a lock here as during partition initialization there
1499*91f16700Schasinglulu 	 * will only be a single core online.
1500*91f16700Schasinglulu 	 */
1501*91f16700Schasinglulu 	sp->secondary_ep = x1;
1502*91f16700Schasinglulu 	VERBOSE("%s: 0x%lx\n", __func__, sp->secondary_ep);
1503*91f16700Schasinglulu 
1504*91f16700Schasinglulu 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
1505*91f16700Schasinglulu }
1506*91f16700Schasinglulu 
1507*91f16700Schasinglulu /*******************************************************************************
1508*91f16700Schasinglulu  * This function will parse the Secure Partition Manifest. From manifest, it
1509*91f16700Schasinglulu  * will fetch details for preparing Secure partition image context and secure
1510*91f16700Schasinglulu  * partition image boot arguments if any.
1511*91f16700Schasinglulu  ******************************************************************************/
1512*91f16700Schasinglulu static int sp_manifest_parse(void *sp_manifest, int offset,
1513*91f16700Schasinglulu 			     struct secure_partition_desc *sp,
1514*91f16700Schasinglulu 			     entry_point_info_t *ep_info,
1515*91f16700Schasinglulu 			     int32_t *boot_info_reg)
1516*91f16700Schasinglulu {
1517*91f16700Schasinglulu 	int32_t ret, node;
1518*91f16700Schasinglulu 	uint32_t config_32;
1519*91f16700Schasinglulu 
1520*91f16700Schasinglulu 	/*
1521*91f16700Schasinglulu 	 * Look for the mandatory fields that are expected to be present in
1522*91f16700Schasinglulu 	 * the SP manifests.
1523*91f16700Schasinglulu 	 */
1524*91f16700Schasinglulu 	node = fdt_path_offset(sp_manifest, "/");
1525*91f16700Schasinglulu 	if (node < 0) {
1526*91f16700Schasinglulu 		ERROR("Did not find root node.\n");
1527*91f16700Schasinglulu 		return node;
1528*91f16700Schasinglulu 	}
1529*91f16700Schasinglulu 
1530*91f16700Schasinglulu 	ret = fdt_read_uint32_array(sp_manifest, node, "uuid",
1531*91f16700Schasinglulu 				    ARRAY_SIZE(sp->uuid), sp->uuid);
1532*91f16700Schasinglulu 	if (ret != 0) {
1533*91f16700Schasinglulu 		ERROR("Missing Secure Partition UUID.\n");
1534*91f16700Schasinglulu 		return ret;
1535*91f16700Schasinglulu 	}
1536*91f16700Schasinglulu 
1537*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32);
1538*91f16700Schasinglulu 	if (ret != 0) {
1539*91f16700Schasinglulu 		ERROR("Missing SP Exception Level information.\n");
1540*91f16700Schasinglulu 		return ret;
1541*91f16700Schasinglulu 	}
1542*91f16700Schasinglulu 
1543*91f16700Schasinglulu 	sp->runtime_el = config_32;
1544*91f16700Schasinglulu 
1545*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node, "ffa-version", &config_32);
1546*91f16700Schasinglulu 	if (ret != 0) {
1547*91f16700Schasinglulu 		ERROR("Missing Secure Partition FF-A Version.\n");
1548*91f16700Schasinglulu 		return ret;
1549*91f16700Schasinglulu 	}
1550*91f16700Schasinglulu 
1551*91f16700Schasinglulu 	sp->ffa_version = config_32;
1552*91f16700Schasinglulu 
1553*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node, "execution-state", &config_32);
1554*91f16700Schasinglulu 	if (ret != 0) {
1555*91f16700Schasinglulu 		ERROR("Missing Secure Partition Execution State.\n");
1556*91f16700Schasinglulu 		return ret;
1557*91f16700Schasinglulu 	}
1558*91f16700Schasinglulu 
1559*91f16700Schasinglulu 	sp->execution_state = config_32;
1560*91f16700Schasinglulu 
1561*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node,
1562*91f16700Schasinglulu 			      "messaging-method", &config_32);
1563*91f16700Schasinglulu 	if (ret != 0) {
1564*91f16700Schasinglulu 		ERROR("Missing Secure Partition messaging method.\n");
1565*91f16700Schasinglulu 		return ret;
1566*91f16700Schasinglulu 	}
1567*91f16700Schasinglulu 
1568*91f16700Schasinglulu 	/* Validate this entry, we currently only support direct messaging. */
1569*91f16700Schasinglulu 	if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV |
1570*91f16700Schasinglulu 			  FFA_PARTITION_DIRECT_REQ_SEND)) != 0U) {
1571*91f16700Schasinglulu 		WARN("Invalid Secure Partition messaging method (0x%x)\n",
1572*91f16700Schasinglulu 		     config_32);
1573*91f16700Schasinglulu 		return -EINVAL;
1574*91f16700Schasinglulu 	}
1575*91f16700Schasinglulu 
1576*91f16700Schasinglulu 	sp->properties = config_32;
1577*91f16700Schasinglulu 
1578*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node,
1579*91f16700Schasinglulu 			      "execution-ctx-count", &config_32);
1580*91f16700Schasinglulu 
1581*91f16700Schasinglulu 	if (ret != 0) {
1582*91f16700Schasinglulu 		ERROR("Missing SP Execution Context Count.\n");
1583*91f16700Schasinglulu 		return ret;
1584*91f16700Schasinglulu 	}
1585*91f16700Schasinglulu 
1586*91f16700Schasinglulu 	/*
1587*91f16700Schasinglulu 	 * Ensure this field is set correctly in the manifest however
1588*91f16700Schasinglulu 	 * since this is currently a hardcoded value for S-EL1 partitions
1589*91f16700Schasinglulu 	 * we don't need to save it here, just validate.
1590*91f16700Schasinglulu 	 */
1591*91f16700Schasinglulu 	if (config_32 != PLATFORM_CORE_COUNT) {
1592*91f16700Schasinglulu 		ERROR("SP Execution Context Count (%u) must be %u.\n",
1593*91f16700Schasinglulu 			config_32, PLATFORM_CORE_COUNT);
1594*91f16700Schasinglulu 		return -EINVAL;
1595*91f16700Schasinglulu 	}
1596*91f16700Schasinglulu 
1597*91f16700Schasinglulu 	/*
1598*91f16700Schasinglulu 	 * Look for the optional fields that are expected to be present in
1599*91f16700Schasinglulu 	 * an SP manifest.
1600*91f16700Schasinglulu 	 */
1601*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node, "id", &config_32);
1602*91f16700Schasinglulu 	if (ret != 0) {
1603*91f16700Schasinglulu 		WARN("Missing Secure Partition ID.\n");
1604*91f16700Schasinglulu 	} else {
1605*91f16700Schasinglulu 		if (!is_ffa_secure_id_valid(config_32)) {
1606*91f16700Schasinglulu 			ERROR("Invalid Secure Partition ID (0x%x).\n",
1607*91f16700Schasinglulu 			      config_32);
1608*91f16700Schasinglulu 			return -EINVAL;
1609*91f16700Schasinglulu 		}
1610*91f16700Schasinglulu 		sp->sp_id = config_32;
1611*91f16700Schasinglulu 	}
1612*91f16700Schasinglulu 
1613*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node,
1614*91f16700Schasinglulu 			      "power-management-messages", &config_32);
1615*91f16700Schasinglulu 	if (ret != 0) {
1616*91f16700Schasinglulu 		WARN("Missing Power Management Messages entry.\n");
1617*91f16700Schasinglulu 	} else {
1618*91f16700Schasinglulu 		/*
1619*91f16700Schasinglulu 		 * Ensure only the currently supported power messages have
1620*91f16700Schasinglulu 		 * been requested.
1621*91f16700Schasinglulu 		 */
1622*91f16700Schasinglulu 		if (config_32 & ~(FFA_PM_MSG_SUB_CPU_OFF |
1623*91f16700Schasinglulu 				  FFA_PM_MSG_SUB_CPU_SUSPEND |
1624*91f16700Schasinglulu 				  FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME)) {
1625*91f16700Schasinglulu 			ERROR("Requested unsupported PM messages (%x)\n",
1626*91f16700Schasinglulu 			      config_32);
1627*91f16700Schasinglulu 			return -EINVAL;
1628*91f16700Schasinglulu 		}
1629*91f16700Schasinglulu 		sp->pwr_mgmt_msgs = config_32;
1630*91f16700Schasinglulu 	}
1631*91f16700Schasinglulu 
1632*91f16700Schasinglulu 	ret = fdt_read_uint32(sp_manifest, node,
1633*91f16700Schasinglulu 			      "gp-register-num", &config_32);
1634*91f16700Schasinglulu 	if (ret != 0) {
1635*91f16700Schasinglulu 		WARN("Missing boot information register.\n");
1636*91f16700Schasinglulu 	} else {
1637*91f16700Schasinglulu 		/* Check if a register number between 0-3 is specified. */
1638*91f16700Schasinglulu 		if (config_32 < 4) {
1639*91f16700Schasinglulu 			*boot_info_reg = config_32;
1640*91f16700Schasinglulu 		} else {
1641*91f16700Schasinglulu 			WARN("Incorrect boot information register (%u).\n",
1642*91f16700Schasinglulu 			     config_32);
1643*91f16700Schasinglulu 		}
1644*91f16700Schasinglulu 	}
1645*91f16700Schasinglulu 
1646*91f16700Schasinglulu 	return 0;
1647*91f16700Schasinglulu }
1648*91f16700Schasinglulu 
1649*91f16700Schasinglulu /*******************************************************************************
1650*91f16700Schasinglulu  * This function gets the Secure Partition Manifest base and maps the manifest
1651*91f16700Schasinglulu  * region.
1652*91f16700Schasinglulu  * Currently only one Secure Partition manifest is considered which is used to
1653*91f16700Schasinglulu  * prepare the context for the single Secure Partition.
1654*91f16700Schasinglulu  ******************************************************************************/
1655*91f16700Schasinglulu static int find_and_prepare_sp_context(void)
1656*91f16700Schasinglulu {
1657*91f16700Schasinglulu 	void *sp_manifest;
1658*91f16700Schasinglulu 	uintptr_t manifest_base;
1659*91f16700Schasinglulu 	uintptr_t manifest_base_align;
1660*91f16700Schasinglulu 	entry_point_info_t *next_image_ep_info;
1661*91f16700Schasinglulu 	int32_t ret, boot_info_reg = -1;
1662*91f16700Schasinglulu 	struct secure_partition_desc *sp;
1663*91f16700Schasinglulu 
1664*91f16700Schasinglulu 	next_image_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
1665*91f16700Schasinglulu 	if (next_image_ep_info == NULL) {
1666*91f16700Schasinglulu 		WARN("No Secure Partition image provided by BL2.\n");
1667*91f16700Schasinglulu 		return -ENOENT;
1668*91f16700Schasinglulu 	}
1669*91f16700Schasinglulu 
1670*91f16700Schasinglulu 	sp_manifest = (void *)next_image_ep_info->args.arg0;
1671*91f16700Schasinglulu 	if (sp_manifest == NULL) {
1672*91f16700Schasinglulu 		WARN("Secure Partition manifest absent.\n");
1673*91f16700Schasinglulu 		return -ENOENT;
1674*91f16700Schasinglulu 	}
1675*91f16700Schasinglulu 
1676*91f16700Schasinglulu 	manifest_base = (uintptr_t)sp_manifest;
1677*91f16700Schasinglulu 	manifest_base_align = page_align(manifest_base, DOWN);
1678*91f16700Schasinglulu 
1679*91f16700Schasinglulu 	/*
1680*91f16700Schasinglulu 	 * Map the secure partition manifest region in the EL3 translation
1681*91f16700Schasinglulu 	 * regime.
1682*91f16700Schasinglulu 	 * Map an area equal to (2 * PAGE_SIZE) for now. During manifest base
1683*91f16700Schasinglulu 	 * alignment the region of 1 PAGE_SIZE from manifest align base may
1684*91f16700Schasinglulu 	 * not completely accommodate the secure partition manifest region.
1685*91f16700Schasinglulu 	 */
1686*91f16700Schasinglulu 	ret = mmap_add_dynamic_region((unsigned long long)manifest_base_align,
1687*91f16700Schasinglulu 				      manifest_base_align,
1688*91f16700Schasinglulu 				      PAGE_SIZE * 2,
1689*91f16700Schasinglulu 				      MT_RO_DATA);
1690*91f16700Schasinglulu 	if (ret != 0) {
1691*91f16700Schasinglulu 		ERROR("Error while mapping SP manifest (%d).\n", ret);
1692*91f16700Schasinglulu 		return ret;
1693*91f16700Schasinglulu 	}
1694*91f16700Schasinglulu 
1695*91f16700Schasinglulu 	ret = fdt_node_offset_by_compatible(sp_manifest, -1,
1696*91f16700Schasinglulu 					    "arm,ffa-manifest-1.0");
1697*91f16700Schasinglulu 	if (ret < 0) {
1698*91f16700Schasinglulu 		ERROR("Error happened in SP manifest reading.\n");
1699*91f16700Schasinglulu 		return -EINVAL;
1700*91f16700Schasinglulu 	}
1701*91f16700Schasinglulu 
1702*91f16700Schasinglulu 	/*
1703*91f16700Schasinglulu 	 * Store the size of the manifest so that it can be used later to pass
1704*91f16700Schasinglulu 	 * the manifest as boot information later.
1705*91f16700Schasinglulu 	 */
1706*91f16700Schasinglulu 	next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest);
1707*91f16700Schasinglulu 	INFO("Manifest size = %lu bytes.\n", next_image_ep_info->args.arg1);
1708*91f16700Schasinglulu 
1709*91f16700Schasinglulu 	/*
1710*91f16700Schasinglulu 	 * Select an SP descriptor for initialising the partition's execution
1711*91f16700Schasinglulu 	 * context on the primary CPU.
1712*91f16700Schasinglulu 	 */
1713*91f16700Schasinglulu 	sp = spmc_get_current_sp_ctx();
1714*91f16700Schasinglulu 
1715*91f16700Schasinglulu 	/* Initialize entry point information for the SP */
1716*91f16700Schasinglulu 	SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1,
1717*91f16700Schasinglulu 		       SECURE | EP_ST_ENABLE);
1718*91f16700Schasinglulu 
1719*91f16700Schasinglulu 	/* Parse the SP manifest. */
1720*91f16700Schasinglulu 	ret = sp_manifest_parse(sp_manifest, ret, sp, next_image_ep_info,
1721*91f16700Schasinglulu 				&boot_info_reg);
1722*91f16700Schasinglulu 	if (ret != 0) {
1723*91f16700Schasinglulu 		ERROR("Error in Secure Partition manifest parsing.\n");
1724*91f16700Schasinglulu 		return ret;
1725*91f16700Schasinglulu 	}
1726*91f16700Schasinglulu 
1727*91f16700Schasinglulu 	/* Check that the runtime EL in the manifest was correct. */
1728*91f16700Schasinglulu 	if (sp->runtime_el != S_EL1) {
1729*91f16700Schasinglulu 		ERROR("Unexpected runtime EL: %d\n", sp->runtime_el);
1730*91f16700Schasinglulu 		return -EINVAL;
1731*91f16700Schasinglulu 	}
1732*91f16700Schasinglulu 
1733*91f16700Schasinglulu 	/* Perform any common initialisation. */
1734*91f16700Schasinglulu 	spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg);
1735*91f16700Schasinglulu 
1736*91f16700Schasinglulu 	/* Perform any initialisation specific to S-EL1 SPs. */
1737*91f16700Schasinglulu 	spmc_el1_sp_setup(sp, next_image_ep_info);
1738*91f16700Schasinglulu 
1739*91f16700Schasinglulu 	/* Initialize the SP context with the required ep info. */
1740*91f16700Schasinglulu 	spmc_sp_common_ep_commit(sp, next_image_ep_info);
1741*91f16700Schasinglulu 
1742*91f16700Schasinglulu 	return 0;
1743*91f16700Schasinglulu }
1744*91f16700Schasinglulu 
1745*91f16700Schasinglulu /*******************************************************************************
1746*91f16700Schasinglulu  * This function takes an SP context pointer and performs a synchronous entry
1747*91f16700Schasinglulu  * into it.
1748*91f16700Schasinglulu  ******************************************************************************/
1749*91f16700Schasinglulu static int32_t logical_sp_init(void)
1750*91f16700Schasinglulu {
1751*91f16700Schasinglulu 	int32_t rc = 0;
1752*91f16700Schasinglulu 	struct el3_lp_desc *el3_lp_descs;
1753*91f16700Schasinglulu 
1754*91f16700Schasinglulu 	/* Perform initial validation of the Logical Partitions. */
1755*91f16700Schasinglulu 	rc = el3_sp_desc_validate();
1756*91f16700Schasinglulu 	if (rc != 0) {
1757*91f16700Schasinglulu 		ERROR("Logical Partition validation failed!\n");
1758*91f16700Schasinglulu 		return rc;
1759*91f16700Schasinglulu 	}
1760*91f16700Schasinglulu 
1761*91f16700Schasinglulu 	el3_lp_descs = get_el3_lp_array();
1762*91f16700Schasinglulu 
1763*91f16700Schasinglulu 	INFO("Logical Secure Partition init start.\n");
1764*91f16700Schasinglulu 	for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
1765*91f16700Schasinglulu 		rc = el3_lp_descs[i].init();
1766*91f16700Schasinglulu 		if (rc != 0) {
1767*91f16700Schasinglulu 			ERROR("Logical SP (0x%x) Failed to Initialize\n",
1768*91f16700Schasinglulu 			      el3_lp_descs[i].sp_id);
1769*91f16700Schasinglulu 			return rc;
1770*91f16700Schasinglulu 		}
1771*91f16700Schasinglulu 		VERBOSE("Logical SP (0x%x) Initialized\n",
1772*91f16700Schasinglulu 			      el3_lp_descs[i].sp_id);
1773*91f16700Schasinglulu 	}
1774*91f16700Schasinglulu 
1775*91f16700Schasinglulu 	INFO("Logical Secure Partition init completed.\n");
1776*91f16700Schasinglulu 
1777*91f16700Schasinglulu 	return rc;
1778*91f16700Schasinglulu }
1779*91f16700Schasinglulu 
1780*91f16700Schasinglulu uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec)
1781*91f16700Schasinglulu {
1782*91f16700Schasinglulu 	uint64_t rc;
1783*91f16700Schasinglulu 
1784*91f16700Schasinglulu 	assert(ec != NULL);
1785*91f16700Schasinglulu 
1786*91f16700Schasinglulu 	/* Assign the context of the SP to this CPU */
1787*91f16700Schasinglulu 	cm_set_context(&(ec->cpu_ctx), SECURE);
1788*91f16700Schasinglulu 
1789*91f16700Schasinglulu 	/* Restore the context assigned above */
1790*91f16700Schasinglulu 	cm_el1_sysregs_context_restore(SECURE);
1791*91f16700Schasinglulu 	cm_set_next_eret_context(SECURE);
1792*91f16700Schasinglulu 
1793*91f16700Schasinglulu 	/* Invalidate TLBs at EL1. */
1794*91f16700Schasinglulu 	tlbivmalle1();
1795*91f16700Schasinglulu 	dsbish();
1796*91f16700Schasinglulu 
1797*91f16700Schasinglulu 	/* Enter Secure Partition */
1798*91f16700Schasinglulu 	rc = spm_secure_partition_enter(&ec->c_rt_ctx);
1799*91f16700Schasinglulu 
1800*91f16700Schasinglulu 	/* Save secure state */
1801*91f16700Schasinglulu 	cm_el1_sysregs_context_save(SECURE);
1802*91f16700Schasinglulu 
1803*91f16700Schasinglulu 	return rc;
1804*91f16700Schasinglulu }
1805*91f16700Schasinglulu 
1806*91f16700Schasinglulu /*******************************************************************************
1807*91f16700Schasinglulu  * SPMC Helper Functions.
1808*91f16700Schasinglulu  ******************************************************************************/
1809*91f16700Schasinglulu static int32_t sp_init(void)
1810*91f16700Schasinglulu {
1811*91f16700Schasinglulu 	uint64_t rc;
1812*91f16700Schasinglulu 	struct secure_partition_desc *sp;
1813*91f16700Schasinglulu 	struct sp_exec_ctx *ec;
1814*91f16700Schasinglulu 
1815*91f16700Schasinglulu 	sp = spmc_get_current_sp_ctx();
1816*91f16700Schasinglulu 	ec = spmc_get_sp_ec(sp);
1817*91f16700Schasinglulu 	ec->rt_model = RT_MODEL_INIT;
1818*91f16700Schasinglulu 	ec->rt_state = RT_STATE_RUNNING;
1819*91f16700Schasinglulu 
1820*91f16700Schasinglulu 	INFO("Secure Partition (0x%x) init start.\n", sp->sp_id);
1821*91f16700Schasinglulu 
1822*91f16700Schasinglulu 	rc = spmc_sp_synchronous_entry(ec);
1823*91f16700Schasinglulu 	if (rc != 0) {
1824*91f16700Schasinglulu 		/* Indicate SP init was not successful. */
1825*91f16700Schasinglulu 		ERROR("SP (0x%x) failed to initialize (%lu).\n",
1826*91f16700Schasinglulu 		      sp->sp_id, rc);
1827*91f16700Schasinglulu 		return 0;
1828*91f16700Schasinglulu 	}
1829*91f16700Schasinglulu 
1830*91f16700Schasinglulu 	ec->rt_state = RT_STATE_WAITING;
1831*91f16700Schasinglulu 	INFO("Secure Partition initialized.\n");
1832*91f16700Schasinglulu 
1833*91f16700Schasinglulu 	return 1;
1834*91f16700Schasinglulu }
1835*91f16700Schasinglulu 
1836*91f16700Schasinglulu static void initalize_sp_descs(void)
1837*91f16700Schasinglulu {
1838*91f16700Schasinglulu 	struct secure_partition_desc *sp;
1839*91f16700Schasinglulu 
1840*91f16700Schasinglulu 	for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
1841*91f16700Schasinglulu 		sp = &sp_desc[i];
1842*91f16700Schasinglulu 		sp->sp_id = INV_SP_ID;
1843*91f16700Schasinglulu 		sp->mailbox.rx_buffer = NULL;
1844*91f16700Schasinglulu 		sp->mailbox.tx_buffer = NULL;
1845*91f16700Schasinglulu 		sp->mailbox.state = MAILBOX_STATE_EMPTY;
1846*91f16700Schasinglulu 		sp->secondary_ep = 0;
1847*91f16700Schasinglulu 	}
1848*91f16700Schasinglulu }
1849*91f16700Schasinglulu 
1850*91f16700Schasinglulu static void initalize_ns_ep_descs(void)
1851*91f16700Schasinglulu {
1852*91f16700Schasinglulu 	struct ns_endpoint_desc *ns_ep;
1853*91f16700Schasinglulu 
1854*91f16700Schasinglulu 	for (unsigned int i = 0U; i < NS_PARTITION_COUNT; i++) {
1855*91f16700Schasinglulu 		ns_ep = &ns_ep_desc[i];
1856*91f16700Schasinglulu 		/*
1857*91f16700Schasinglulu 		 * Clashes with the Hypervisor ID but will not be a
1858*91f16700Schasinglulu 		 * problem in practice.
1859*91f16700Schasinglulu 		 */
1860*91f16700Schasinglulu 		ns_ep->ns_ep_id = 0;
1861*91f16700Schasinglulu 		ns_ep->ffa_version = 0;
1862*91f16700Schasinglulu 		ns_ep->mailbox.rx_buffer = NULL;
1863*91f16700Schasinglulu 		ns_ep->mailbox.tx_buffer = NULL;
1864*91f16700Schasinglulu 		ns_ep->mailbox.state = MAILBOX_STATE_EMPTY;
1865*91f16700Schasinglulu 	}
1866*91f16700Schasinglulu }
1867*91f16700Schasinglulu 
1868*91f16700Schasinglulu /*******************************************************************************
1869*91f16700Schasinglulu  * Initialize SPMC attributes for the SPMD.
1870*91f16700Schasinglulu  ******************************************************************************/
1871*91f16700Schasinglulu void spmc_populate_attrs(spmc_manifest_attribute_t *spmc_attrs)
1872*91f16700Schasinglulu {
1873*91f16700Schasinglulu 	spmc_attrs->major_version = FFA_VERSION_MAJOR;
1874*91f16700Schasinglulu 	spmc_attrs->minor_version = FFA_VERSION_MINOR;
1875*91f16700Schasinglulu 	spmc_attrs->exec_state = MODE_RW_64;
1876*91f16700Schasinglulu 	spmc_attrs->spmc_id = FFA_SPMC_ID;
1877*91f16700Schasinglulu }
1878*91f16700Schasinglulu 
1879*91f16700Schasinglulu /*******************************************************************************
1880*91f16700Schasinglulu  * Initialize contexts of all Secure Partitions.
1881*91f16700Schasinglulu  ******************************************************************************/
1882*91f16700Schasinglulu int32_t spmc_setup(void)
1883*91f16700Schasinglulu {
1884*91f16700Schasinglulu 	int32_t ret;
1885*91f16700Schasinglulu 	uint32_t flags;
1886*91f16700Schasinglulu 
1887*91f16700Schasinglulu 	/* Initialize endpoint descriptors */
1888*91f16700Schasinglulu 	initalize_sp_descs();
1889*91f16700Schasinglulu 	initalize_ns_ep_descs();
1890*91f16700Schasinglulu 
1891*91f16700Schasinglulu 	/*
1892*91f16700Schasinglulu 	 * Retrieve the information of the datastore for tracking shared memory
1893*91f16700Schasinglulu 	 * requests allocated by platform code and zero the region if available.
1894*91f16700Schasinglulu 	 */
1895*91f16700Schasinglulu 	ret = plat_spmc_shmem_datastore_get(&spmc_shmem_obj_state.data,
1896*91f16700Schasinglulu 					    &spmc_shmem_obj_state.data_size);
1897*91f16700Schasinglulu 	if (ret != 0) {
1898*91f16700Schasinglulu 		ERROR("Failed to obtain memory descriptor backing store!\n");
1899*91f16700Schasinglulu 		return ret;
1900*91f16700Schasinglulu 	}
1901*91f16700Schasinglulu 	memset(spmc_shmem_obj_state.data, 0, spmc_shmem_obj_state.data_size);
1902*91f16700Schasinglulu 
1903*91f16700Schasinglulu 	/* Setup logical SPs. */
1904*91f16700Schasinglulu 	ret = logical_sp_init();
1905*91f16700Schasinglulu 	if (ret != 0) {
1906*91f16700Schasinglulu 		ERROR("Failed to initialize Logical Partitions.\n");
1907*91f16700Schasinglulu 		return ret;
1908*91f16700Schasinglulu 	}
1909*91f16700Schasinglulu 
1910*91f16700Schasinglulu 	/* Perform physical SP setup. */
1911*91f16700Schasinglulu 
1912*91f16700Schasinglulu 	/* Disable MMU at EL1 (initialized by BL2) */
1913*91f16700Schasinglulu 	disable_mmu_icache_el1();
1914*91f16700Schasinglulu 
1915*91f16700Schasinglulu 	/* Initialize context of the SP */
1916*91f16700Schasinglulu 	INFO("Secure Partition context setup start.\n");
1917*91f16700Schasinglulu 
1918*91f16700Schasinglulu 	ret = find_and_prepare_sp_context();
1919*91f16700Schasinglulu 	if (ret != 0) {
1920*91f16700Schasinglulu 		ERROR("Error in SP finding and context preparation.\n");
1921*91f16700Schasinglulu 		return ret;
1922*91f16700Schasinglulu 	}
1923*91f16700Schasinglulu 
1924*91f16700Schasinglulu 	/* Register power management hooks with PSCI */
1925*91f16700Schasinglulu 	psci_register_spd_pm_hook(&spmc_pm);
1926*91f16700Schasinglulu 
1927*91f16700Schasinglulu 	/*
1928*91f16700Schasinglulu 	 * Register an interrupt handler for S-EL1 interrupts
1929*91f16700Schasinglulu 	 * when generated during code executing in the
1930*91f16700Schasinglulu 	 * non-secure state.
1931*91f16700Schasinglulu 	 */
1932*91f16700Schasinglulu 	flags = 0;
1933*91f16700Schasinglulu 	set_interrupt_rm_flag(flags, NON_SECURE);
1934*91f16700Schasinglulu 	ret = register_interrupt_type_handler(INTR_TYPE_S_EL1,
1935*91f16700Schasinglulu 					      spmc_sp_interrupt_handler,
1936*91f16700Schasinglulu 					      flags);
1937*91f16700Schasinglulu 	if (ret != 0) {
1938*91f16700Schasinglulu 		ERROR("Failed to register interrupt handler! (%d)\n", ret);
1939*91f16700Schasinglulu 		panic();
1940*91f16700Schasinglulu 	}
1941*91f16700Schasinglulu 
1942*91f16700Schasinglulu 	/* Register init function for deferred init.  */
1943*91f16700Schasinglulu 	bl31_register_bl32_init(&sp_init);
1944*91f16700Schasinglulu 
1945*91f16700Schasinglulu 	INFO("Secure Partition setup done.\n");
1946*91f16700Schasinglulu 
1947*91f16700Schasinglulu 	return 0;
1948*91f16700Schasinglulu }
1949*91f16700Schasinglulu 
1950*91f16700Schasinglulu /*******************************************************************************
1951*91f16700Schasinglulu  * Secure Partition Manager SMC handler.
1952*91f16700Schasinglulu  ******************************************************************************/
1953*91f16700Schasinglulu uint64_t spmc_smc_handler(uint32_t smc_fid,
1954*91f16700Schasinglulu 			  bool secure_origin,
1955*91f16700Schasinglulu 			  uint64_t x1,
1956*91f16700Schasinglulu 			  uint64_t x2,
1957*91f16700Schasinglulu 			  uint64_t x3,
1958*91f16700Schasinglulu 			  uint64_t x4,
1959*91f16700Schasinglulu 			  void *cookie,
1960*91f16700Schasinglulu 			  void *handle,
1961*91f16700Schasinglulu 			  uint64_t flags)
1962*91f16700Schasinglulu {
1963*91f16700Schasinglulu 	switch (smc_fid) {
1964*91f16700Schasinglulu 
1965*91f16700Schasinglulu 	case FFA_VERSION:
1966*91f16700Schasinglulu 		return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3,
1967*91f16700Schasinglulu 					   x4, cookie, handle, flags);
1968*91f16700Schasinglulu 
1969*91f16700Schasinglulu 	case FFA_SPM_ID_GET:
1970*91f16700Schasinglulu 		return ffa_spm_id_get_handler(smc_fid, secure_origin, x1, x2,
1971*91f16700Schasinglulu 					     x3, x4, cookie, handle, flags);
1972*91f16700Schasinglulu 
1973*91f16700Schasinglulu 	case FFA_ID_GET:
1974*91f16700Schasinglulu 		return ffa_id_get_handler(smc_fid, secure_origin, x1, x2, x3,
1975*91f16700Schasinglulu 					  x4, cookie, handle, flags);
1976*91f16700Schasinglulu 
1977*91f16700Schasinglulu 	case FFA_FEATURES:
1978*91f16700Schasinglulu 		return ffa_features_handler(smc_fid, secure_origin, x1, x2, x3,
1979*91f16700Schasinglulu 					    x4, cookie, handle, flags);
1980*91f16700Schasinglulu 
1981*91f16700Schasinglulu 	case FFA_SECONDARY_EP_REGISTER_SMC64:
1982*91f16700Schasinglulu 		return ffa_sec_ep_register_handler(smc_fid, secure_origin, x1,
1983*91f16700Schasinglulu 						   x2, x3, x4, cookie, handle,
1984*91f16700Schasinglulu 						   flags);
1985*91f16700Schasinglulu 
1986*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
1987*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
1988*91f16700Schasinglulu 		return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
1989*91f16700Schasinglulu 					      x3, x4, cookie, handle, flags);
1990*91f16700Schasinglulu 
1991*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
1992*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
1993*91f16700Schasinglulu 		return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2,
1994*91f16700Schasinglulu 					       x3, x4, cookie, handle, flags);
1995*91f16700Schasinglulu 
1996*91f16700Schasinglulu 	case FFA_RXTX_MAP_SMC32:
1997*91f16700Schasinglulu 	case FFA_RXTX_MAP_SMC64:
1998*91f16700Schasinglulu 		return rxtx_map_handler(smc_fid, secure_origin, x1, x2, x3, x4,
1999*91f16700Schasinglulu 					cookie, handle, flags);
2000*91f16700Schasinglulu 
2001*91f16700Schasinglulu 	case FFA_RXTX_UNMAP:
2002*91f16700Schasinglulu 		return rxtx_unmap_handler(smc_fid, secure_origin, x1, x2, x3,
2003*91f16700Schasinglulu 					  x4, cookie, handle, flags);
2004*91f16700Schasinglulu 
2005*91f16700Schasinglulu 	case FFA_PARTITION_INFO_GET:
2006*91f16700Schasinglulu 		return partition_info_get_handler(smc_fid, secure_origin, x1,
2007*91f16700Schasinglulu 						  x2, x3, x4, cookie, handle,
2008*91f16700Schasinglulu 						  flags);
2009*91f16700Schasinglulu 
2010*91f16700Schasinglulu 	case FFA_RX_RELEASE:
2011*91f16700Schasinglulu 		return rx_release_handler(smc_fid, secure_origin, x1, x2, x3,
2012*91f16700Schasinglulu 					  x4, cookie, handle, flags);
2013*91f16700Schasinglulu 
2014*91f16700Schasinglulu 	case FFA_MSG_WAIT:
2015*91f16700Schasinglulu 		return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2016*91f16700Schasinglulu 					cookie, handle, flags);
2017*91f16700Schasinglulu 
2018*91f16700Schasinglulu 	case FFA_ERROR:
2019*91f16700Schasinglulu 		return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2020*91f16700Schasinglulu 					cookie, handle, flags);
2021*91f16700Schasinglulu 
2022*91f16700Schasinglulu 	case FFA_MSG_RUN:
2023*91f16700Schasinglulu 		return ffa_run_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2024*91f16700Schasinglulu 				       cookie, handle, flags);
2025*91f16700Schasinglulu 
2026*91f16700Schasinglulu 	case FFA_MEM_SHARE_SMC32:
2027*91f16700Schasinglulu 	case FFA_MEM_SHARE_SMC64:
2028*91f16700Schasinglulu 	case FFA_MEM_LEND_SMC32:
2029*91f16700Schasinglulu 	case FFA_MEM_LEND_SMC64:
2030*91f16700Schasinglulu 		return spmc_ffa_mem_send(smc_fid, secure_origin, x1, x2, x3, x4,
2031*91f16700Schasinglulu 					 cookie, handle, flags);
2032*91f16700Schasinglulu 
2033*91f16700Schasinglulu 	case FFA_MEM_FRAG_TX:
2034*91f16700Schasinglulu 		return spmc_ffa_mem_frag_tx(smc_fid, secure_origin, x1, x2, x3,
2035*91f16700Schasinglulu 					    x4, cookie, handle, flags);
2036*91f16700Schasinglulu 
2037*91f16700Schasinglulu 	case FFA_MEM_FRAG_RX:
2038*91f16700Schasinglulu 		return spmc_ffa_mem_frag_rx(smc_fid, secure_origin, x1, x2, x3,
2039*91f16700Schasinglulu 					    x4, cookie, handle, flags);
2040*91f16700Schasinglulu 
2041*91f16700Schasinglulu 	case FFA_MEM_RETRIEVE_REQ_SMC32:
2042*91f16700Schasinglulu 	case FFA_MEM_RETRIEVE_REQ_SMC64:
2043*91f16700Schasinglulu 		return spmc_ffa_mem_retrieve_req(smc_fid, secure_origin, x1, x2,
2044*91f16700Schasinglulu 						 x3, x4, cookie, handle, flags);
2045*91f16700Schasinglulu 
2046*91f16700Schasinglulu 	case FFA_MEM_RELINQUISH:
2047*91f16700Schasinglulu 		return spmc_ffa_mem_relinquish(smc_fid, secure_origin, x1, x2,
2048*91f16700Schasinglulu 					       x3, x4, cookie, handle, flags);
2049*91f16700Schasinglulu 
2050*91f16700Schasinglulu 	case FFA_MEM_RECLAIM:
2051*91f16700Schasinglulu 		return spmc_ffa_mem_reclaim(smc_fid, secure_origin, x1, x2, x3,
2052*91f16700Schasinglulu 					    x4, cookie, handle, flags);
2053*91f16700Schasinglulu 
2054*91f16700Schasinglulu 	default:
2055*91f16700Schasinglulu 		WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
2056*91f16700Schasinglulu 		break;
2057*91f16700Schasinglulu 	}
2058*91f16700Schasinglulu 	return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
2059*91f16700Schasinglulu }
2060*91f16700Schasinglulu 
2061*91f16700Schasinglulu /*******************************************************************************
2062*91f16700Schasinglulu  * This function is the handler registered for S-EL1 interrupts by the SPMC. It
2063*91f16700Schasinglulu  * validates the interrupt and upon success arranges entry into the SP for
2064*91f16700Schasinglulu  * handling the interrupt.
2065*91f16700Schasinglulu  ******************************************************************************/
2066*91f16700Schasinglulu static uint64_t spmc_sp_interrupt_handler(uint32_t id,
2067*91f16700Schasinglulu 					  uint32_t flags,
2068*91f16700Schasinglulu 					  void *handle,
2069*91f16700Schasinglulu 					  void *cookie)
2070*91f16700Schasinglulu {
2071*91f16700Schasinglulu 	struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
2072*91f16700Schasinglulu 	struct sp_exec_ctx *ec;
2073*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
2074*91f16700Schasinglulu 
2075*91f16700Schasinglulu 	/* Sanity check for a NULL pointer dereference. */
2076*91f16700Schasinglulu 	assert(sp != NULL);
2077*91f16700Schasinglulu 
2078*91f16700Schasinglulu 	/* Check the security state when the exception was generated. */
2079*91f16700Schasinglulu 	assert(get_interrupt_src_ss(flags) == NON_SECURE);
2080*91f16700Schasinglulu 
2081*91f16700Schasinglulu 	/* Panic if not an S-EL1 Partition. */
2082*91f16700Schasinglulu 	if (sp->runtime_el != S_EL1) {
2083*91f16700Schasinglulu 		ERROR("Interrupt received for a non S-EL1 SP on core%u.\n",
2084*91f16700Schasinglulu 		      linear_id);
2085*91f16700Schasinglulu 		panic();
2086*91f16700Schasinglulu 	}
2087*91f16700Schasinglulu 
2088*91f16700Schasinglulu 	/* Obtain a reference to the SP execution context. */
2089*91f16700Schasinglulu 	ec = spmc_get_sp_ec(sp);
2090*91f16700Schasinglulu 
2091*91f16700Schasinglulu 	/* Ensure that the execution context is in waiting state else panic. */
2092*91f16700Schasinglulu 	if (ec->rt_state != RT_STATE_WAITING) {
2093*91f16700Schasinglulu 		ERROR("SP EC on core%u is not waiting (%u), it is (%u).\n",
2094*91f16700Schasinglulu 		      linear_id, RT_STATE_WAITING, ec->rt_state);
2095*91f16700Schasinglulu 		panic();
2096*91f16700Schasinglulu 	}
2097*91f16700Schasinglulu 
2098*91f16700Schasinglulu 	/* Update the runtime model and state of the partition. */
2099*91f16700Schasinglulu 	ec->rt_model = RT_MODEL_INTR;
2100*91f16700Schasinglulu 	ec->rt_state = RT_STATE_RUNNING;
2101*91f16700Schasinglulu 
2102*91f16700Schasinglulu 	VERBOSE("SP (0x%x) interrupt start on core%u.\n", sp->sp_id, linear_id);
2103*91f16700Schasinglulu 
2104*91f16700Schasinglulu 	/*
2105*91f16700Schasinglulu 	 * Forward the interrupt to the S-EL1 SP. The interrupt ID is not
2106*91f16700Schasinglulu 	 * populated as the SP can determine this by itself.
2107*91f16700Schasinglulu 	 */
2108*91f16700Schasinglulu 	return spmd_smc_switch_state(FFA_INTERRUPT, false,
2109*91f16700Schasinglulu 				     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
2110*91f16700Schasinglulu 				     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
2111*91f16700Schasinglulu 				     handle);
2112*91f16700Schasinglulu }
2113