xref: /rk3399_ARM-atf/services/std_svc/spm/el3_spmc/spmc_main.c (revision 234519eec022a8dc9b25aee9fe3d9e9084e18993)
15096aeb2SMarc Bonnici /*
29bfe78c2SLevi Yun  * Copyright (c) 2022-2025, ARM Limited and Contributors. All rights reserved.
35096aeb2SMarc Bonnici  *
45096aeb2SMarc Bonnici  * SPDX-License-Identifier: BSD-3-Clause
55096aeb2SMarc Bonnici  */
65096aeb2SMarc Bonnici 
75096aeb2SMarc Bonnici #include <assert.h>
85096aeb2SMarc Bonnici #include <errno.h>
9638a6f8eSShruti Gupta #include <stdio.h>
105096aeb2SMarc Bonnici 
115096aeb2SMarc Bonnici #include <arch_helpers.h>
125096aeb2SMarc Bonnici #include <bl31/bl31.h>
135096aeb2SMarc Bonnici #include <bl31/ehf.h>
14729d7793SAchin Gupta #include <bl31/interrupt_mgmt.h>
155096aeb2SMarc Bonnici #include <common/debug.h>
165096aeb2SMarc Bonnici #include <common/fdt_wrappers.h>
175096aeb2SMarc Bonnici #include <common/runtime_svc.h>
18f74e2772SMarc Bonnici #include <common/uuid.h>
195096aeb2SMarc Bonnici #include <lib/el3_runtime/context_mgmt.h>
205096aeb2SMarc Bonnici #include <lib/smccc.h>
215096aeb2SMarc Bonnici #include <lib/utils.h>
225096aeb2SMarc Bonnici #include <lib/xlat_tables/xlat_tables_v2.h>
235096aeb2SMarc Bonnici #include <libfdt.h>
245096aeb2SMarc Bonnici #include <plat/common/platform.h>
257affa25cSMarc Bonnici #include <services/el3_spmc_logical_sp.h>
265096aeb2SMarc Bonnici #include <services/ffa_svc.h>
275096aeb2SMarc Bonnici #include <services/spmc_svc.h>
285096aeb2SMarc Bonnici #include <services/spmd_svc.h>
295096aeb2SMarc Bonnici #include "spmc.h"
30e0b1a6d5SMarc Bonnici #include "spmc_shared_mem.h"
31aae2370cSYeoreum Yun #if TRANSFER_LIST
32aae2370cSYeoreum Yun #include <transfer_list.h>
33aae2370cSYeoreum Yun #endif
345096aeb2SMarc Bonnici 
355096aeb2SMarc Bonnici #include <platform_def.h>
365096aeb2SMarc Bonnici 
371f6b2b26SNishant Sharma /* FFA_MEM_PERM_* helpers */
381f6b2b26SNishant Sharma #define FFA_MEM_PERM_MASK		U(7)
391f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_MASK		U(3)
401f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_SHIFT		U(0)
411f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_NA		U(0)
421f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_RW		U(1)
431f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_RES		U(2)
441f6b2b26SNishant Sharma #define FFA_MEM_PERM_DATA_RO		U(3)
451f6b2b26SNishant Sharma #define FFA_MEM_PERM_INST_EXEC          (U(0) << 2)
461f6b2b26SNishant Sharma #define FFA_MEM_PERM_INST_NON_EXEC      (U(1) << 2)
471f6b2b26SNishant Sharma 
48f74e2772SMarc Bonnici /* Declare the maximum number of SPs and El3 LPs. */
49*0322d7afSJay Monkman #define MAX_SP_LP_PARTITIONS (SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT)
50f74e2772SMarc Bonnici 
51dd87b735SJ-Alves #define FFA_VERSION_SPMC_MAJOR U(1)
52dd87b735SJ-Alves #define FFA_VERSION_SPMC_MINOR U(2)
53dd87b735SJ-Alves 
545096aeb2SMarc Bonnici /*
555096aeb2SMarc Bonnici  * Allocate a secure partition descriptor to describe each SP in the system that
565096aeb2SMarc Bonnici  * does not reside at EL3.
575096aeb2SMarc Bonnici  */
585096aeb2SMarc Bonnici static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT];
595096aeb2SMarc Bonnici 
605096aeb2SMarc Bonnici /*
615096aeb2SMarc Bonnici  * Allocate an NS endpoint descriptor to describe each VM and the Hypervisor in
625096aeb2SMarc Bonnici  * the system that interacts with a SP. It is used to track the Hypervisor
635096aeb2SMarc Bonnici  * buffer pair, version and ID for now. It could be extended to track VM
645096aeb2SMarc Bonnici  * properties when the SPMC supports indirect messaging.
655096aeb2SMarc Bonnici  */
665096aeb2SMarc Bonnici static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT];
675096aeb2SMarc Bonnici 
68729d7793SAchin Gupta static uint64_t spmc_sp_interrupt_handler(uint32_t id,
69729d7793SAchin Gupta 					  uint32_t flags,
70729d7793SAchin Gupta 					  void *handle,
71729d7793SAchin Gupta 					  void *cookie);
72729d7793SAchin Gupta 
735096aeb2SMarc Bonnici /*
747affa25cSMarc Bonnici  * Helper function to obtain the array storing the EL3
757affa25cSMarc Bonnici  * Logical Partition descriptors.
767affa25cSMarc Bonnici  */
get_el3_lp_array(void)777affa25cSMarc Bonnici struct el3_lp_desc *get_el3_lp_array(void)
787affa25cSMarc Bonnici {
797affa25cSMarc Bonnici 	return (struct el3_lp_desc *) EL3_LP_DESCS_START;
807affa25cSMarc Bonnici }
817affa25cSMarc Bonnici 
827affa25cSMarc Bonnici /*
835096aeb2SMarc Bonnici  * Helper function to obtain the descriptor of the last SP to whom control was
845096aeb2SMarc Bonnici  * handed to on this physical cpu. Currently, we assume there is only one SP.
855096aeb2SMarc Bonnici  * TODO: Expand to track multiple partitions when required.
865096aeb2SMarc Bonnici  */
spmc_get_current_sp_ctx(void)875096aeb2SMarc Bonnici struct secure_partition_desc *spmc_get_current_sp_ctx(void)
885096aeb2SMarc Bonnici {
895096aeb2SMarc Bonnici 	return &(sp_desc[ACTIVE_SP_DESC_INDEX]);
905096aeb2SMarc Bonnici }
915096aeb2SMarc Bonnici 
925096aeb2SMarc Bonnici /*
935096aeb2SMarc Bonnici  * Helper function to obtain the execution context of an SP on the
945096aeb2SMarc Bonnici  * current physical cpu.
955096aeb2SMarc Bonnici  */
spmc_get_sp_ec(struct secure_partition_desc * sp)965096aeb2SMarc Bonnici struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp)
975096aeb2SMarc Bonnici {
985096aeb2SMarc Bonnici 	return &(sp->ec[get_ec_index(sp)]);
995096aeb2SMarc Bonnici }
1005096aeb2SMarc Bonnici 
1015096aeb2SMarc Bonnici /* Helper function to get pointer to SP context from its ID. */
spmc_get_sp_ctx(uint16_t id)1025096aeb2SMarc Bonnici struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id)
1035096aeb2SMarc Bonnici {
1040c7707fdSMarc Bonnici 	/* Check for Secure World Partitions. */
1055096aeb2SMarc Bonnici 	for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
1065096aeb2SMarc Bonnici 		if (sp_desc[i].sp_id == id) {
1075096aeb2SMarc Bonnici 			return &(sp_desc[i]);
1085096aeb2SMarc Bonnici 		}
1095096aeb2SMarc Bonnici 	}
1105096aeb2SMarc Bonnici 	return NULL;
1115096aeb2SMarc Bonnici }
1125096aeb2SMarc Bonnici 
113a7c00505SMarc Bonnici /*
114a7c00505SMarc Bonnici  * Helper function to obtain the descriptor of the Hypervisor or OS kernel.
115a7c00505SMarc Bonnici  * We assume that the first descriptor is reserved for this entity.
116a7c00505SMarc Bonnici  */
spmc_get_hyp_ctx(void)117a7c00505SMarc Bonnici struct ns_endpoint_desc *spmc_get_hyp_ctx(void)
118a7c00505SMarc Bonnici {
119a7c00505SMarc Bonnici 	return &(ns_ep_desc[0]);
120a7c00505SMarc Bonnici }
121a7c00505SMarc Bonnici 
122f16b6ee3SMarc Bonnici /*
123f16b6ee3SMarc Bonnici  * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor
124f16b6ee3SMarc Bonnici  * or OS kernel in the normal world or the last SP that was run.
125f16b6ee3SMarc Bonnici  */
spmc_get_mbox_desc(bool secure_origin)126f16b6ee3SMarc Bonnici struct mailbox *spmc_get_mbox_desc(bool secure_origin)
127f16b6ee3SMarc Bonnici {
128f16b6ee3SMarc Bonnici 	/* Obtain the RX/TX buffer pair descriptor. */
129f16b6ee3SMarc Bonnici 	if (secure_origin) {
130f16b6ee3SMarc Bonnici 		return &(spmc_get_current_sp_ctx()->mailbox);
131f16b6ee3SMarc Bonnici 	} else {
132f16b6ee3SMarc Bonnici 		return &(spmc_get_hyp_ctx()->mailbox);
133f16b6ee3SMarc Bonnici 	}
134f16b6ee3SMarc Bonnici }
135f16b6ee3SMarc Bonnici 
1365096aeb2SMarc Bonnici /******************************************************************************
1375096aeb2SMarc Bonnici  * This function returns to the place where spmc_sp_synchronous_entry() was
1385096aeb2SMarc Bonnici  * called originally.
1395096aeb2SMarc Bonnici  ******************************************************************************/
spmc_sp_synchronous_exit(struct sp_exec_ctx * ec,uint64_t rc)1405096aeb2SMarc Bonnici __dead2 void spmc_sp_synchronous_exit(struct sp_exec_ctx *ec, uint64_t rc)
1415096aeb2SMarc Bonnici {
1425096aeb2SMarc Bonnici 	/*
1435096aeb2SMarc Bonnici 	 * The SPM must have initiated the original request through a
1445096aeb2SMarc Bonnici 	 * synchronous entry into the secure partition. Jump back to the
1455096aeb2SMarc Bonnici 	 * original C runtime context with the value of rc in x0;
1465096aeb2SMarc Bonnici 	 */
1475096aeb2SMarc Bonnici 	spm_secure_partition_exit(ec->c_rt_ctx, rc);
1485096aeb2SMarc Bonnici 
1495096aeb2SMarc Bonnici 	panic();
1505096aeb2SMarc Bonnici }
1515096aeb2SMarc Bonnici 
1525096aeb2SMarc Bonnici /*******************************************************************************
1535096aeb2SMarc Bonnici  * Return FFA_ERROR with specified error code.
1545096aeb2SMarc Bonnici  ******************************************************************************/
spmc_ffa_error_return(void * handle,int error_code)1555096aeb2SMarc Bonnici uint64_t spmc_ffa_error_return(void *handle, int error_code)
1565096aeb2SMarc Bonnici {
1575096aeb2SMarc Bonnici 	SMC_RET8(handle, FFA_ERROR,
1585096aeb2SMarc Bonnici 		 FFA_TARGET_INFO_MBZ, error_code,
1595096aeb2SMarc Bonnici 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
1605096aeb2SMarc Bonnici 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
1615096aeb2SMarc Bonnici }
1625096aeb2SMarc Bonnici 
1635096aeb2SMarc Bonnici /******************************************************************************
1645096aeb2SMarc Bonnici  * Helper function to validate a secure partition ID to ensure it does not
1655096aeb2SMarc Bonnici  * conflict with any other FF-A component and follows the convention to
1665096aeb2SMarc Bonnici  * indicate it resides within the secure world.
1675096aeb2SMarc Bonnici  ******************************************************************************/
is_ffa_secure_id_valid(uint16_t partition_id)1685096aeb2SMarc Bonnici bool is_ffa_secure_id_valid(uint16_t partition_id)
1695096aeb2SMarc Bonnici {
1707affa25cSMarc Bonnici 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
1717affa25cSMarc Bonnici 
1725096aeb2SMarc Bonnici 	/* Ensure the ID is not the invalid partition ID. */
1735096aeb2SMarc Bonnici 	if (partition_id == INV_SP_ID) {
1745096aeb2SMarc Bonnici 		return false;
1755096aeb2SMarc Bonnici 	}
1765096aeb2SMarc Bonnici 
1775096aeb2SMarc Bonnici 	/* Ensure the ID is not the SPMD ID. */
1785096aeb2SMarc Bonnici 	if (partition_id == SPMD_DIRECT_MSG_ENDPOINT_ID) {
1795096aeb2SMarc Bonnici 		return false;
1805096aeb2SMarc Bonnici 	}
1815096aeb2SMarc Bonnici 
1825096aeb2SMarc Bonnici 	/*
1835096aeb2SMarc Bonnici 	 * Ensure the ID follows the convention to indicate it resides
1845096aeb2SMarc Bonnici 	 * in the secure world.
1855096aeb2SMarc Bonnici 	 */
1865096aeb2SMarc Bonnici 	if (!ffa_is_secure_world_id(partition_id)) {
1875096aeb2SMarc Bonnici 		return false;
1885096aeb2SMarc Bonnici 	}
1895096aeb2SMarc Bonnici 
1905096aeb2SMarc Bonnici 	/* Ensure we don't conflict with the SPMC partition ID. */
1915096aeb2SMarc Bonnici 	if (partition_id == FFA_SPMC_ID) {
1925096aeb2SMarc Bonnici 		return false;
1935096aeb2SMarc Bonnici 	}
1945096aeb2SMarc Bonnici 
1955096aeb2SMarc Bonnici 	/* Ensure we do not already have an SP context with this ID. */
1965096aeb2SMarc Bonnici 	if (spmc_get_sp_ctx(partition_id)) {
1975096aeb2SMarc Bonnici 		return false;
1985096aeb2SMarc Bonnici 	}
1995096aeb2SMarc Bonnici 
2007affa25cSMarc Bonnici 	/* Ensure we don't clash with any Logical SP's. */
2017affa25cSMarc Bonnici 	for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
2027affa25cSMarc Bonnici 		if (el3_lp_descs[i].sp_id == partition_id) {
2037affa25cSMarc Bonnici 			return false;
2047affa25cSMarc Bonnici 		}
2057affa25cSMarc Bonnici 	}
2067affa25cSMarc Bonnici 
2075096aeb2SMarc Bonnici 	return true;
2085096aeb2SMarc Bonnici }
2095096aeb2SMarc Bonnici 
2105096aeb2SMarc Bonnici /*******************************************************************************
21120fae0a7SMarc Bonnici  * This function either forwards the request to the other world or returns
21220fae0a7SMarc Bonnici  * with an ERET depending on the source of the call.
2137affa25cSMarc Bonnici  * We can assume that the destination is for an entity at a lower exception
2147affa25cSMarc Bonnici  * level as any messages destined for a logical SP resident in EL3 will have
2157affa25cSMarc Bonnici  * already been taken care of by the SPMC before entering this function.
21620fae0a7SMarc Bonnici  ******************************************************************************/
spmc_smc_return(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * handle,void * cookie,uint64_t flags,uint16_t dst_id,uint32_t sp_ffa_version)21720fae0a7SMarc Bonnici static uint64_t spmc_smc_return(uint32_t smc_fid,
21820fae0a7SMarc Bonnici 				bool secure_origin,
21920fae0a7SMarc Bonnici 				uint64_t x1,
22020fae0a7SMarc Bonnici 				uint64_t x2,
22120fae0a7SMarc Bonnici 				uint64_t x3,
22220fae0a7SMarc Bonnici 				uint64_t x4,
22320fae0a7SMarc Bonnici 				void *handle,
22420fae0a7SMarc Bonnici 				void *cookie,
22520fae0a7SMarc Bonnici 				uint64_t flags,
226bb9fc8c0SJay Monkman 				uint16_t dst_id,
227bb9fc8c0SJay Monkman 				uint32_t sp_ffa_version)
22820fae0a7SMarc Bonnici {
22920fae0a7SMarc Bonnici 	/* If the destination is in the normal world always go via the SPMD. */
23020fae0a7SMarc Bonnici 	if (ffa_is_normal_world_id(dst_id)) {
23120fae0a7SMarc Bonnici 		return spmd_smc_handler(smc_fid, x1, x2, x3, x4,
232bb9fc8c0SJay Monkman 					cookie, handle, flags, sp_ffa_version);
23320fae0a7SMarc Bonnici 	}
23420fae0a7SMarc Bonnici 	/*
23520fae0a7SMarc Bonnici 	 * If the caller is secure and we want to return to the secure world,
23620fae0a7SMarc Bonnici 	 * ERET directly.
23720fae0a7SMarc Bonnici 	 */
23820fae0a7SMarc Bonnici 	else if (secure_origin && ffa_is_secure_world_id(dst_id)) {
23920fae0a7SMarc Bonnici 		SMC_RET5(handle, smc_fid, x1, x2, x3, x4);
24020fae0a7SMarc Bonnici 	}
24120fae0a7SMarc Bonnici 	/* If we originated in the normal world then switch contexts. */
24220fae0a7SMarc Bonnici 	else if (!secure_origin && ffa_is_secure_world_id(dst_id)) {
24320fae0a7SMarc Bonnici 		return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2,
244bb9fc8c0SJay Monkman 					     x3, x4, handle, flags, sp_ffa_version);
24520fae0a7SMarc Bonnici 	} else {
24620fae0a7SMarc Bonnici 		/* Unknown State. */
24720fae0a7SMarc Bonnici 		panic();
24820fae0a7SMarc Bonnici 	}
24920fae0a7SMarc Bonnici 
25020fae0a7SMarc Bonnici 	/* Shouldn't be Reached. */
25120fae0a7SMarc Bonnici 	return 0;
25220fae0a7SMarc Bonnici }
25320fae0a7SMarc Bonnici 
25420fae0a7SMarc Bonnici /*******************************************************************************
255c4db76f0SMarc Bonnici  * FF-A ABI Handlers.
256c4db76f0SMarc Bonnici  ******************************************************************************/
2579741327dSMarc Bonnici 
2589741327dSMarc Bonnici /*******************************************************************************
2599741327dSMarc Bonnici  * Helper function to validate arg2 as part of a direct message.
2609741327dSMarc Bonnici  ******************************************************************************/
direct_msg_validate_arg2(uint64_t x2)2619741327dSMarc Bonnici static inline bool direct_msg_validate_arg2(uint64_t x2)
2629741327dSMarc Bonnici {
26359bd2ad8SMarc Bonnici 	/* Check message type. */
26459bd2ad8SMarc Bonnici 	if (x2 & FFA_FWK_MSG_BIT) {
26559bd2ad8SMarc Bonnici 		/* We have a framework message, ensure it is a known message. */
26659bd2ad8SMarc Bonnici 		if (x2 & ~(FFA_FWK_MSG_MASK | FFA_FWK_MSG_BIT)) {
26759bd2ad8SMarc Bonnici 			VERBOSE("Invalid message format 0x%lx.\n", x2);
2689741327dSMarc Bonnici 			return false;
2699741327dSMarc Bonnici 		}
27059bd2ad8SMarc Bonnici 	} else {
27159bd2ad8SMarc Bonnici 		/* We have a partition messages, ensure x2 is not set. */
27259bd2ad8SMarc Bonnici 		if (x2 != (uint64_t) 0) {
27359bd2ad8SMarc Bonnici 			VERBOSE("Arg2 MBZ for partition messages. (0x%lx).\n",
27459bd2ad8SMarc Bonnici 				x2);
27559bd2ad8SMarc Bonnici 			return false;
27659bd2ad8SMarc Bonnici 		}
27759bd2ad8SMarc Bonnici 	}
2789741327dSMarc Bonnici 	return true;
2799741327dSMarc Bonnici }
2809741327dSMarc Bonnici 
2819741327dSMarc Bonnici /*******************************************************************************
28248fe24c5SMarc Bonnici  * Helper function to validate the destination ID of a direct response.
28348fe24c5SMarc Bonnici  ******************************************************************************/
direct_msg_validate_dst_id(uint16_t dst_id)28448fe24c5SMarc Bonnici static bool direct_msg_validate_dst_id(uint16_t dst_id)
28548fe24c5SMarc Bonnici {
28648fe24c5SMarc Bonnici 	struct secure_partition_desc *sp;
28748fe24c5SMarc Bonnici 
28848fe24c5SMarc Bonnici 	/* Check if we're targeting a normal world partition. */
28948fe24c5SMarc Bonnici 	if (ffa_is_normal_world_id(dst_id)) {
29048fe24c5SMarc Bonnici 		return true;
29148fe24c5SMarc Bonnici 	}
29248fe24c5SMarc Bonnici 
29348fe24c5SMarc Bonnici 	/* Or directed to the SPMC itself.*/
29448fe24c5SMarc Bonnici 	if (dst_id == FFA_SPMC_ID) {
29548fe24c5SMarc Bonnici 		return true;
29648fe24c5SMarc Bonnici 	}
29748fe24c5SMarc Bonnici 
29848fe24c5SMarc Bonnici 	/* Otherwise ensure the SP exists. */
29948fe24c5SMarc Bonnici 	sp = spmc_get_sp_ctx(dst_id);
30048fe24c5SMarc Bonnici 	if (sp != NULL) {
30148fe24c5SMarc Bonnici 		return true;
30248fe24c5SMarc Bonnici 	}
30348fe24c5SMarc Bonnici 
30448fe24c5SMarc Bonnici 	return false;
30548fe24c5SMarc Bonnici }
30648fe24c5SMarc Bonnici 
30748fe24c5SMarc Bonnici /*******************************************************************************
30848fe24c5SMarc Bonnici  * Helper function to validate the response from a Logical Partition.
30948fe24c5SMarc Bonnici  ******************************************************************************/
direct_msg_validate_lp_resp(uint16_t origin_id,uint16_t lp_id,void * handle)31048fe24c5SMarc Bonnici static bool direct_msg_validate_lp_resp(uint16_t origin_id, uint16_t lp_id,
31148fe24c5SMarc Bonnici 					void *handle)
31248fe24c5SMarc Bonnici {
31348fe24c5SMarc Bonnici 	/* Retrieve populated Direct Response Arguments. */
31409a580b7SLevi Yun 	uint64_t smc_fid = SMC_GET_GP(handle, CTX_GPREG_X0);
31548fe24c5SMarc Bonnici 	uint64_t x1 = SMC_GET_GP(handle, CTX_GPREG_X1);
31648fe24c5SMarc Bonnici 	uint64_t x2 = SMC_GET_GP(handle, CTX_GPREG_X2);
31748fe24c5SMarc Bonnici 	uint16_t src_id = ffa_endpoint_source(x1);
31848fe24c5SMarc Bonnici 	uint16_t dst_id = ffa_endpoint_destination(x1);
31948fe24c5SMarc Bonnici 
32048fe24c5SMarc Bonnici 	if (src_id != lp_id) {
32148fe24c5SMarc Bonnici 		ERROR("Invalid EL3 LP source ID (0x%x).\n", src_id);
32248fe24c5SMarc Bonnici 		return false;
32348fe24c5SMarc Bonnici 	}
32448fe24c5SMarc Bonnici 
32548fe24c5SMarc Bonnici 	/*
32648fe24c5SMarc Bonnici 	 * Check the destination ID is valid and ensure the LP is responding to
32748fe24c5SMarc Bonnici 	 * the original request.
32848fe24c5SMarc Bonnici 	 */
32948fe24c5SMarc Bonnici 	if ((!direct_msg_validate_dst_id(dst_id)) || (dst_id != origin_id)) {
33048fe24c5SMarc Bonnici 		ERROR("Invalid EL3 LP destination ID (0x%x).\n", dst_id);
33148fe24c5SMarc Bonnici 		return false;
33248fe24c5SMarc Bonnici 	}
33348fe24c5SMarc Bonnici 
33409a580b7SLevi Yun 	if ((smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) &&
33509a580b7SLevi Yun 			!direct_msg_validate_arg2(x2)) {
33648fe24c5SMarc Bonnici 		ERROR("Invalid EL3 LP message encoding.\n");
33748fe24c5SMarc Bonnici 		return false;
33848fe24c5SMarc Bonnici 	}
33948fe24c5SMarc Bonnici 	return true;
34048fe24c5SMarc Bonnici }
34148fe24c5SMarc Bonnici 
34248fe24c5SMarc Bonnici /*******************************************************************************
34309a580b7SLevi Yun  * Helper function to check that partition can receive direct msg or not.
34409a580b7SLevi Yun  ******************************************************************************/
direct_msg_receivable(uint32_t properties,uint16_t dir_req_fnum)34509a580b7SLevi Yun static bool direct_msg_receivable(uint32_t properties, uint16_t dir_req_fnum)
34609a580b7SLevi Yun {
34709a580b7SLevi Yun 	if ((dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ &&
34809a580b7SLevi Yun 			((properties & FFA_PARTITION_DIRECT_REQ_RECV) == 0U)) ||
34909a580b7SLevi Yun 			(dir_req_fnum == FFA_FNUM_MSG_SEND_DIRECT_REQ2 &&
35009a580b7SLevi Yun 			((properties & FFA_PARTITION_DIRECT_REQ2_RECV) == 0U))) {
35109a580b7SLevi Yun 		return false;
35209a580b7SLevi Yun 	}
35309a580b7SLevi Yun 
35409a580b7SLevi Yun 	return true;
35509a580b7SLevi Yun }
35609a580b7SLevi Yun 
35709a580b7SLevi Yun /*******************************************************************************
358bb9fc8c0SJay Monkman  * Helper function to obtain the FF-A version of the calling partition.
359bb9fc8c0SJay Monkman  ******************************************************************************/
get_partition_ffa_version(bool secure_origin)360bb9fc8c0SJay Monkman uint32_t get_partition_ffa_version(bool secure_origin)
361bb9fc8c0SJay Monkman {
362bb9fc8c0SJay Monkman 	if (secure_origin) {
363bb9fc8c0SJay Monkman 		return spmc_get_current_sp_ctx()->ffa_version;
364bb9fc8c0SJay Monkman 	} else {
365bb9fc8c0SJay Monkman 		return spmc_get_hyp_ctx()->ffa_version;
366bb9fc8c0SJay Monkman 	}
367bb9fc8c0SJay Monkman }
368bb9fc8c0SJay Monkman 
369bb9fc8c0SJay Monkman /*******************************************************************************
3709741327dSMarc Bonnici  * Handle direct request messages and route to the appropriate destination.
3719741327dSMarc Bonnici  ******************************************************************************/
direct_req_smc_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)3729741327dSMarc Bonnici static uint64_t direct_req_smc_handler(uint32_t smc_fid,
3739741327dSMarc Bonnici 				       bool secure_origin,
3749741327dSMarc Bonnici 				       uint64_t x1,
3759741327dSMarc Bonnici 				       uint64_t x2,
3769741327dSMarc Bonnici 				       uint64_t x3,
3779741327dSMarc Bonnici 				       uint64_t x4,
3789741327dSMarc Bonnici 				       void *cookie,
3799741327dSMarc Bonnici 				       void *handle,
3809741327dSMarc Bonnici 				       uint64_t flags)
3819741327dSMarc Bonnici {
38248fe24c5SMarc Bonnici 	uint16_t src_id = ffa_endpoint_source(x1);
3839741327dSMarc Bonnici 	uint16_t dst_id = ffa_endpoint_destination(x1);
38409a580b7SLevi Yun 	uint16_t dir_req_funcid;
3857affa25cSMarc Bonnici 	struct el3_lp_desc *el3_lp_descs;
3869741327dSMarc Bonnici 	struct secure_partition_desc *sp;
3879741327dSMarc Bonnici 	unsigned int idx;
388bb9fc8c0SJay Monkman 	uint32_t ffa_version = get_partition_ffa_version(secure_origin);
3899741327dSMarc Bonnici 
39009a580b7SLevi Yun 	dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_REQ2_SMC64) ?
39109a580b7SLevi Yun 		FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2;
39209a580b7SLevi Yun 
393bb9fc8c0SJay Monkman 	if ((dir_req_funcid == FFA_FNUM_MSG_SEND_DIRECT_REQ2) &&
394bb9fc8c0SJay Monkman 			ffa_version < MAKE_FFA_VERSION(U(1), U(2))) {
395bb9fc8c0SJay Monkman 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
396bb9fc8c0SJay Monkman 	}
397bb9fc8c0SJay Monkman 
39809a580b7SLevi Yun 	/*
39909a580b7SLevi Yun 	 * Sanity check for DIRECT_REQ:
40009a580b7SLevi Yun 	 * Check if arg2 has been populated correctly based on message type
40109a580b7SLevi Yun 	 */
40209a580b7SLevi Yun 	if ((dir_req_funcid == FFA_FNUM_MSG_SEND_DIRECT_REQ) &&
40309a580b7SLevi Yun 			!direct_msg_validate_arg2(x2)) {
40409a580b7SLevi Yun 		return spmc_ffa_error_return(handle, FFA_ERROR_INVALID_PARAMETER);
4059741327dSMarc Bonnici 	}
4069741327dSMarc Bonnici 
40748fe24c5SMarc Bonnici 	/* Validate Sender is either the current SP or from the normal world. */
40848fe24c5SMarc Bonnici 	if ((secure_origin && src_id != spmc_get_current_sp_ctx()->sp_id) ||
40948fe24c5SMarc Bonnici 		(!secure_origin && !ffa_is_normal_world_id(src_id))) {
41048fe24c5SMarc Bonnici 		ERROR("Invalid direct request source ID (0x%x).\n", src_id);
41148fe24c5SMarc Bonnici 		return spmc_ffa_error_return(handle,
41248fe24c5SMarc Bonnici 					FFA_ERROR_INVALID_PARAMETER);
41348fe24c5SMarc Bonnici 	}
41448fe24c5SMarc Bonnici 
4157affa25cSMarc Bonnici 	el3_lp_descs = get_el3_lp_array();
4167affa25cSMarc Bonnici 
4177affa25cSMarc Bonnici 	/* Check if the request is destined for a Logical Partition. */
4187affa25cSMarc Bonnici 	for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) {
4197affa25cSMarc Bonnici 		if (el3_lp_descs[i].sp_id == dst_id) {
42009a580b7SLevi Yun 			if (!direct_msg_receivable(el3_lp_descs[i].properties, dir_req_funcid)) {
42109a580b7SLevi Yun 				return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
42209a580b7SLevi Yun 			}
42309a580b7SLevi Yun 
42448fe24c5SMarc Bonnici 			uint64_t ret = el3_lp_descs[i].direct_req(
42548fe24c5SMarc Bonnici 						smc_fid, secure_origin, x1, x2,
42648fe24c5SMarc Bonnici 						x3, x4, cookie, handle, flags);
42748fe24c5SMarc Bonnici 			if (!direct_msg_validate_lp_resp(src_id, dst_id,
42848fe24c5SMarc Bonnici 							 handle)) {
42948fe24c5SMarc Bonnici 				panic();
43048fe24c5SMarc Bonnici 			}
43148fe24c5SMarc Bonnici 
43248fe24c5SMarc Bonnici 			/* Message checks out. */
43348fe24c5SMarc Bonnici 			return ret;
4347affa25cSMarc Bonnici 		}
4357affa25cSMarc Bonnici 	}
4367affa25cSMarc Bonnici 
4379741327dSMarc Bonnici 	/*
4387affa25cSMarc Bonnici 	 * If the request was not targeted to a LSP and from the secure world
4397affa25cSMarc Bonnici 	 * then it is invalid since a SP cannot call into the Normal world and
4407affa25cSMarc Bonnici 	 * there is no other SP to call into. If there are other SPs in future
4417affa25cSMarc Bonnici 	 * then the partition runtime model would need to be validated as well.
4429741327dSMarc Bonnici 	 */
4439741327dSMarc Bonnici 	if (secure_origin) {
4449741327dSMarc Bonnici 		VERBOSE("Direct request not supported to the Normal World.\n");
4459741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
4469741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
4479741327dSMarc Bonnici 	}
4489741327dSMarc Bonnici 
4499741327dSMarc Bonnici 	/* Check if the SP ID is valid. */
4509741327dSMarc Bonnici 	sp = spmc_get_sp_ctx(dst_id);
4519741327dSMarc Bonnici 	if (sp == NULL) {
4529741327dSMarc Bonnici 		VERBOSE("Direct request to unknown partition ID (0x%x).\n",
4539741327dSMarc Bonnici 			dst_id);
4549741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
4559741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
4569741327dSMarc Bonnici 	}
4579741327dSMarc Bonnici 
45809a580b7SLevi Yun 	if (!direct_msg_receivable(sp->properties, dir_req_funcid)) {
45909a580b7SLevi Yun 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
46009a580b7SLevi Yun 	}
46109a580b7SLevi Yun 
4625ed8e255SNishant Sharma 	/* Protect the runtime state of a UP S-EL0 SP with a lock. */
4635ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
4645ed8e255SNishant Sharma 		spin_lock(&sp->rt_state_lock);
4655ed8e255SNishant Sharma 	}
4665ed8e255SNishant Sharma 
4679741327dSMarc Bonnici 	/*
4689741327dSMarc Bonnici 	 * Check that the target execution context is in a waiting state before
4699741327dSMarc Bonnici 	 * forwarding the direct request to it.
4709741327dSMarc Bonnici 	 */
4719741327dSMarc Bonnici 	idx = get_ec_index(sp);
4729741327dSMarc Bonnici 	if (sp->ec[idx].rt_state != RT_STATE_WAITING) {
4739741327dSMarc Bonnici 		VERBOSE("SP context on core%u is not waiting (%u).\n",
4749741327dSMarc Bonnici 			idx, sp->ec[idx].rt_model);
4755ed8e255SNishant Sharma 
4765ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
4775ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
4785ed8e255SNishant Sharma 		}
4795ed8e255SNishant Sharma 
4809741327dSMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
4819741327dSMarc Bonnici 	}
4829741327dSMarc Bonnici 
4839741327dSMarc Bonnici 	/*
4849741327dSMarc Bonnici 	 * Everything checks out so forward the request to the SP after updating
4859741327dSMarc Bonnici 	 * its state and runtime model.
4869741327dSMarc Bonnici 	 */
4879741327dSMarc Bonnici 	sp->ec[idx].rt_state = RT_STATE_RUNNING;
4889741327dSMarc Bonnici 	sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
48948fe24c5SMarc Bonnici 	sp->ec[idx].dir_req_origin_id = src_id;
49009a580b7SLevi Yun 	sp->ec[idx].dir_req_funcid = dir_req_funcid;
4915ed8e255SNishant Sharma 
4925ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
4935ed8e255SNishant Sharma 		spin_unlock(&sp->rt_state_lock);
4945ed8e255SNishant Sharma 	}
4955ed8e255SNishant Sharma 
4969741327dSMarc Bonnici 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
497bb9fc8c0SJay Monkman 			       handle, cookie, flags, dst_id, sp->ffa_version);
4989741327dSMarc Bonnici }
4999741327dSMarc Bonnici 
5009741327dSMarc Bonnici /*******************************************************************************
5019741327dSMarc Bonnici  * Handle direct response messages and route to the appropriate destination.
5029741327dSMarc Bonnici  ******************************************************************************/
direct_resp_smc_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)5039741327dSMarc Bonnici static uint64_t direct_resp_smc_handler(uint32_t smc_fid,
5049741327dSMarc Bonnici 					bool secure_origin,
5059741327dSMarc Bonnici 					uint64_t x1,
5069741327dSMarc Bonnici 					uint64_t x2,
5079741327dSMarc Bonnici 					uint64_t x3,
5089741327dSMarc Bonnici 					uint64_t x4,
5099741327dSMarc Bonnici 					void *cookie,
5109741327dSMarc Bonnici 					void *handle,
5119741327dSMarc Bonnici 					uint64_t flags)
5129741327dSMarc Bonnici {
5139741327dSMarc Bonnici 	uint16_t dst_id = ffa_endpoint_destination(x1);
51409a580b7SLevi Yun 	uint16_t dir_req_funcid;
5159741327dSMarc Bonnici 	struct secure_partition_desc *sp;
5169741327dSMarc Bonnici 	unsigned int idx;
5179741327dSMarc Bonnici 
51809a580b7SLevi Yun 	dir_req_funcid = (smc_fid != FFA_MSG_SEND_DIRECT_RESP2_SMC64) ?
51909a580b7SLevi Yun 		FFA_FNUM_MSG_SEND_DIRECT_REQ : FFA_FNUM_MSG_SEND_DIRECT_REQ2;
52009a580b7SLevi Yun 
5219741327dSMarc Bonnici 	/* Check if arg2 has been populated correctly based on message type. */
5229741327dSMarc Bonnici 	if (!direct_msg_validate_arg2(x2)) {
5239741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
5249741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
5259741327dSMarc Bonnici 	}
5269741327dSMarc Bonnici 
5279741327dSMarc Bonnici 	/* Check that the response did not originate from the Normal world. */
5289741327dSMarc Bonnici 	if (!secure_origin) {
5299741327dSMarc Bonnici 		VERBOSE("Direct Response not supported from Normal World.\n");
5309741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
5319741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
5329741327dSMarc Bonnici 	}
5339741327dSMarc Bonnici 
5349741327dSMarc Bonnici 	/*
5359741327dSMarc Bonnici 	 * Check that the response is either targeted to the Normal world or the
5369741327dSMarc Bonnici 	 * SPMC e.g. a PM response.
5379741327dSMarc Bonnici 	 */
53848fe24c5SMarc Bonnici 	if (!direct_msg_validate_dst_id(dst_id)) {
5399741327dSMarc Bonnici 		VERBOSE("Direct response to invalid partition ID (0x%x).\n",
5409741327dSMarc Bonnici 			dst_id);
5419741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
5429741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
5439741327dSMarc Bonnici 	}
5449741327dSMarc Bonnici 
5459741327dSMarc Bonnici 	/* Obtain the SP descriptor and update its runtime state. */
5469741327dSMarc Bonnici 	sp = spmc_get_sp_ctx(ffa_endpoint_source(x1));
5479741327dSMarc Bonnici 	if (sp == NULL) {
5489741327dSMarc Bonnici 		VERBOSE("Direct response to unknown partition ID (0x%x).\n",
5499741327dSMarc Bonnici 			dst_id);
5509741327dSMarc Bonnici 		return spmc_ffa_error_return(handle,
5519741327dSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
5529741327dSMarc Bonnici 	}
5539741327dSMarc Bonnici 
5545ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
5555ed8e255SNishant Sharma 		spin_lock(&sp->rt_state_lock);
5565ed8e255SNishant Sharma 	}
5575ed8e255SNishant Sharma 
5589741327dSMarc Bonnici 	/* Sanity check state is being tracked correctly in the SPMC. */
5599741327dSMarc Bonnici 	idx = get_ec_index(sp);
5609741327dSMarc Bonnici 	assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
5619741327dSMarc Bonnici 
5629741327dSMarc Bonnici 	/* Ensure SP execution context was in the right runtime model. */
5639741327dSMarc Bonnici 	if (sp->ec[idx].rt_model != RT_MODEL_DIR_REQ) {
5649741327dSMarc Bonnici 		VERBOSE("SP context on core%u not handling direct req (%u).\n",
5659741327dSMarc Bonnici 			idx, sp->ec[idx].rt_model);
5665ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
5675ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
5685ed8e255SNishant Sharma 		}
5699741327dSMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
5709741327dSMarc Bonnici 	}
5719741327dSMarc Bonnici 
57209a580b7SLevi Yun 	if (dir_req_funcid != sp->ec[idx].dir_req_funcid) {
57309a580b7SLevi Yun 		WARN("Unmatched direct req/resp func id. req:%x, resp:%x on core%u.\n",
57409a580b7SLevi Yun 		     sp->ec[idx].dir_req_funcid, (smc_fid & FUNCID_NUM_MASK), idx);
57509a580b7SLevi Yun 		if (sp->runtime_el == S_EL0) {
57609a580b7SLevi Yun 			spin_unlock(&sp->rt_state_lock);
57709a580b7SLevi Yun 		}
57809a580b7SLevi Yun 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
57909a580b7SLevi Yun 	}
58009a580b7SLevi Yun 
58148fe24c5SMarc Bonnici 	if (sp->ec[idx].dir_req_origin_id != dst_id) {
58248fe24c5SMarc Bonnici 		WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n",
58348fe24c5SMarc Bonnici 		     dst_id, sp->ec[idx].dir_req_origin_id, idx);
5845ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
5855ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
5865ed8e255SNishant Sharma 		}
58748fe24c5SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
58848fe24c5SMarc Bonnici 	}
58948fe24c5SMarc Bonnici 
5909741327dSMarc Bonnici 	/* Update the state of the SP execution context. */
5919741327dSMarc Bonnici 	sp->ec[idx].rt_state = RT_STATE_WAITING;
5929741327dSMarc Bonnici 
59348fe24c5SMarc Bonnici 	/* Clear the ongoing direct request ID. */
59448fe24c5SMarc Bonnici 	sp->ec[idx].dir_req_origin_id = INV_SP_ID;
59548fe24c5SMarc Bonnici 
59609a580b7SLevi Yun 	/* Clear the ongoing direct request message version. */
59709a580b7SLevi Yun 	sp->ec[idx].dir_req_funcid = 0U;
59809a580b7SLevi Yun 
5995ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
6005ed8e255SNishant Sharma 		spin_unlock(&sp->rt_state_lock);
6015ed8e255SNishant Sharma 	}
6025ed8e255SNishant Sharma 
6039741327dSMarc Bonnici 	/*
6049741327dSMarc Bonnici 	 * If the receiver is not the SPMC then forward the response to the
6059741327dSMarc Bonnici 	 * Normal world.
6069741327dSMarc Bonnici 	 */
6079741327dSMarc Bonnici 	if (dst_id == FFA_SPMC_ID) {
6089741327dSMarc Bonnici 		spmc_sp_synchronous_exit(&sp->ec[idx], x4);
6099741327dSMarc Bonnici 		/* Should not get here. */
6109741327dSMarc Bonnici 		panic();
6119741327dSMarc Bonnici 	}
6129741327dSMarc Bonnici 
6139741327dSMarc Bonnici 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
614bb9fc8c0SJay Monkman 			       handle, cookie, flags, dst_id, sp->ffa_version);
6159741327dSMarc Bonnici }
6169741327dSMarc Bonnici 
617c4db76f0SMarc Bonnici /*******************************************************************************
618c4db76f0SMarc Bonnici  * This function handles the FFA_MSG_WAIT SMC to allow an SP to relinquish its
619c4db76f0SMarc Bonnici  * cycles.
620c4db76f0SMarc Bonnici  ******************************************************************************/
msg_wait_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)621c4db76f0SMarc Bonnici static uint64_t msg_wait_handler(uint32_t smc_fid,
622c4db76f0SMarc Bonnici 				 bool secure_origin,
623c4db76f0SMarc Bonnici 				 uint64_t x1,
624c4db76f0SMarc Bonnici 				 uint64_t x2,
625c4db76f0SMarc Bonnici 				 uint64_t x3,
626c4db76f0SMarc Bonnici 				 uint64_t x4,
627c4db76f0SMarc Bonnici 				 void *cookie,
628c4db76f0SMarc Bonnici 				 void *handle,
629c4db76f0SMarc Bonnici 				 uint64_t flags)
630c4db76f0SMarc Bonnici {
631c4db76f0SMarc Bonnici 	struct secure_partition_desc *sp;
632c4db76f0SMarc Bonnici 	unsigned int idx;
633c4db76f0SMarc Bonnici 
634c4db76f0SMarc Bonnici 	/*
635c4db76f0SMarc Bonnici 	 * Check that the response did not originate from the Normal world as
636c4db76f0SMarc Bonnici 	 * only the secure world can call this ABI.
637c4db76f0SMarc Bonnici 	 */
638c4db76f0SMarc Bonnici 	if (!secure_origin) {
639c4db76f0SMarc Bonnici 		VERBOSE("Normal world cannot call FFA_MSG_WAIT.\n");
640c4db76f0SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
641c4db76f0SMarc Bonnici 	}
642c4db76f0SMarc Bonnici 
643c4db76f0SMarc Bonnici 	/* Get the descriptor of the SP that invoked FFA_MSG_WAIT. */
644c4db76f0SMarc Bonnici 	sp = spmc_get_current_sp_ctx();
645c4db76f0SMarc Bonnici 	if (sp == NULL) {
646c4db76f0SMarc Bonnici 		return spmc_ffa_error_return(handle,
647c4db76f0SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
648c4db76f0SMarc Bonnici 	}
649c4db76f0SMarc Bonnici 
650c4db76f0SMarc Bonnici 	/*
651c4db76f0SMarc Bonnici 	 * Get the execution context of the SP that invoked FFA_MSG_WAIT.
652c4db76f0SMarc Bonnici 	 */
653c4db76f0SMarc Bonnici 	idx = get_ec_index(sp);
6545ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
6555ed8e255SNishant Sharma 		spin_lock(&sp->rt_state_lock);
6565ed8e255SNishant Sharma 	}
657c4db76f0SMarc Bonnici 
658c4db76f0SMarc Bonnici 	/* Ensure SP execution context was in the right runtime model. */
659c4db76f0SMarc Bonnici 	if (sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
6605ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
6615ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
6625ed8e255SNishant Sharma 		}
663c4db76f0SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
664c4db76f0SMarc Bonnici 	}
665c4db76f0SMarc Bonnici 
666c4db76f0SMarc Bonnici 	/* Sanity check the state is being tracked correctly in the SPMC. */
667c4db76f0SMarc Bonnici 	assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
668c4db76f0SMarc Bonnici 
669c4db76f0SMarc Bonnici 	/*
670c4db76f0SMarc Bonnici 	 * Perform a synchronous exit if the partition was initialising. The
671c4db76f0SMarc Bonnici 	 * state is updated after the exit.
672c4db76f0SMarc Bonnici 	 */
673c4db76f0SMarc Bonnici 	if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
6745ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
6755ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
6765ed8e255SNishant Sharma 		}
677c4db76f0SMarc Bonnici 		spmc_sp_synchronous_exit(&sp->ec[idx], x4);
678c4db76f0SMarc Bonnici 		/* Should not get here */
679c4db76f0SMarc Bonnici 		panic();
680c4db76f0SMarc Bonnici 	}
681c4db76f0SMarc Bonnici 
682c4db76f0SMarc Bonnici 	/* Update the state of the SP execution context. */
683c4db76f0SMarc Bonnici 	sp->ec[idx].rt_state = RT_STATE_WAITING;
684c4db76f0SMarc Bonnici 
685c4db76f0SMarc Bonnici 	/* Resume normal world if a secure interrupt was handled. */
686c4db76f0SMarc Bonnici 	if (sp->ec[idx].rt_model == RT_MODEL_INTR) {
6875ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
6885ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
6895ed8e255SNishant Sharma 		}
6905ed8e255SNishant Sharma 
691a0a7f158SAndrei Homescu 		return spmd_smc_switch_state(FFA_NORMAL_WORLD_RESUME, secure_origin,
692a0a7f158SAndrei Homescu 					     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
693a0a7f158SAndrei Homescu 					     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
694bb9fc8c0SJay Monkman 					     handle, flags, sp->ffa_version);
695c4db76f0SMarc Bonnici 	}
696c4db76f0SMarc Bonnici 
6975ed8e255SNishant Sharma 	/* Protect the runtime state of a S-EL0 SP with a lock. */
6985ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
6995ed8e255SNishant Sharma 		spin_unlock(&sp->rt_state_lock);
7005ed8e255SNishant Sharma 	}
7015ed8e255SNishant Sharma 
702c4db76f0SMarc Bonnici 	/* Forward the response to the Normal world. */
703c4db76f0SMarc Bonnici 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
704bb9fc8c0SJay Monkman 			       handle, cookie, flags, FFA_NWD_ID, sp->ffa_version);
705c4db76f0SMarc Bonnici }
706c4db76f0SMarc Bonnici 
ffa_error_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)707d663fe7aSMarc Bonnici static uint64_t ffa_error_handler(uint32_t smc_fid,
708d663fe7aSMarc Bonnici 				 bool secure_origin,
709d663fe7aSMarc Bonnici 				 uint64_t x1,
710d663fe7aSMarc Bonnici 				 uint64_t x2,
711d663fe7aSMarc Bonnici 				 uint64_t x3,
712d663fe7aSMarc Bonnici 				 uint64_t x4,
713d663fe7aSMarc Bonnici 				 void *cookie,
714d663fe7aSMarc Bonnici 				 void *handle,
715d663fe7aSMarc Bonnici 				 uint64_t flags)
716d663fe7aSMarc Bonnici {
717d663fe7aSMarc Bonnici 	struct secure_partition_desc *sp;
718d663fe7aSMarc Bonnici 	unsigned int idx;
719e1168bc3SLevi Yun 	uint16_t dst_id = ffa_endpoint_destination(x1);
720e1168bc3SLevi Yun 	bool cancel_dir_req = false;
721d663fe7aSMarc Bonnici 
722d663fe7aSMarc Bonnici 	/* Check that the response did not originate from the Normal world. */
723d663fe7aSMarc Bonnici 	if (!secure_origin) {
724d663fe7aSMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
725d663fe7aSMarc Bonnici 	}
726d663fe7aSMarc Bonnici 
727d663fe7aSMarc Bonnici 	/* Get the descriptor of the SP that invoked FFA_ERROR. */
728d663fe7aSMarc Bonnici 	sp = spmc_get_current_sp_ctx();
729d663fe7aSMarc Bonnici 	if (sp == NULL) {
730d663fe7aSMarc Bonnici 		return spmc_ffa_error_return(handle,
731d663fe7aSMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
732d663fe7aSMarc Bonnici 	}
733d663fe7aSMarc Bonnici 
734d663fe7aSMarc Bonnici 	/* Get the execution context of the SP that invoked FFA_ERROR. */
735d663fe7aSMarc Bonnici 	idx = get_ec_index(sp);
736d663fe7aSMarc Bonnici 
737d663fe7aSMarc Bonnici 	/*
738d663fe7aSMarc Bonnici 	 * We only expect FFA_ERROR to be received during SP initialisation
739d663fe7aSMarc Bonnici 	 * otherwise this is an invalid call.
740d663fe7aSMarc Bonnici 	 */
741d663fe7aSMarc Bonnici 	if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
742d663fe7aSMarc Bonnici 		ERROR("SP 0x%x failed to initialize.\n", sp->sp_id);
743d663fe7aSMarc Bonnici 		spmc_sp_synchronous_exit(&sp->ec[idx], x2);
744d663fe7aSMarc Bonnici 		/* Should not get here. */
745d663fe7aSMarc Bonnici 		panic();
746d663fe7aSMarc Bonnici 	}
747d663fe7aSMarc Bonnici 
748e1168bc3SLevi Yun 	if (sp->runtime_el == S_EL0) {
749e1168bc3SLevi Yun 		spin_lock(&sp->rt_state_lock);
750e1168bc3SLevi Yun 	}
751e1168bc3SLevi Yun 
752e1168bc3SLevi Yun 	if (sp->ec[idx].rt_state == RT_STATE_RUNNING &&
753e1168bc3SLevi Yun 			sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
754e1168bc3SLevi Yun 		sp->ec[idx].rt_state = RT_STATE_WAITING;
755e1168bc3SLevi Yun 		sp->ec[idx].dir_req_origin_id = INV_SP_ID;
756e1168bc3SLevi Yun 		sp->ec[idx].dir_req_funcid = 0x00;
757e1168bc3SLevi Yun 		cancel_dir_req = true;
758e1168bc3SLevi Yun 	}
759e1168bc3SLevi Yun 
760e1168bc3SLevi Yun 	if (sp->runtime_el == S_EL0) {
761e1168bc3SLevi Yun 		spin_unlock(&sp->rt_state_lock);
762e1168bc3SLevi Yun 	}
763e1168bc3SLevi Yun 
764e1168bc3SLevi Yun 	if (cancel_dir_req) {
765e1168bc3SLevi Yun 		if (dst_id == FFA_SPMC_ID) {
766e1168bc3SLevi Yun 			spmc_sp_synchronous_exit(&sp->ec[idx], x4);
767e1168bc3SLevi Yun 			/* Should not get here. */
768e1168bc3SLevi Yun 			panic();
769e1168bc3SLevi Yun 		} else
770e1168bc3SLevi Yun 			return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
771bb9fc8c0SJay Monkman 					       handle, cookie, flags, dst_id, sp->ffa_version);
772e1168bc3SLevi Yun 	}
773e1168bc3SLevi Yun 
774d663fe7aSMarc Bonnici 	return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
775d663fe7aSMarc Bonnici }
776d663fe7aSMarc Bonnici 
ffa_version_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)7770c7707fdSMarc Bonnici static uint64_t ffa_version_handler(uint32_t smc_fid,
7780c7707fdSMarc Bonnici 				    bool secure_origin,
7790c7707fdSMarc Bonnici 				    uint64_t x1,
7800c7707fdSMarc Bonnici 				    uint64_t x2,
7810c7707fdSMarc Bonnici 				    uint64_t x3,
7820c7707fdSMarc Bonnici 				    uint64_t x4,
7830c7707fdSMarc Bonnici 				    void *cookie,
7840c7707fdSMarc Bonnici 				    void *handle,
7850c7707fdSMarc Bonnici 				    uint64_t flags)
7860c7707fdSMarc Bonnici {
7870c7707fdSMarc Bonnici 	uint32_t requested_version = x1 & FFA_VERSION_MASK;
7880c7707fdSMarc Bonnici 
7890c7707fdSMarc Bonnici 	if (requested_version & FFA_VERSION_BIT31_MASK) {
7900c7707fdSMarc Bonnici 		/* Invalid encoding, return an error. */
7910c7707fdSMarc Bonnici 		SMC_RET1(handle, FFA_ERROR_NOT_SUPPORTED);
7920c7707fdSMarc Bonnici 		/* Execution stops here. */
7930c7707fdSMarc Bonnici 	}
7940c7707fdSMarc Bonnici 
7950c7707fdSMarc Bonnici 	/* Determine the caller to store the requested version. */
7960c7707fdSMarc Bonnici 	if (secure_origin) {
7970c7707fdSMarc Bonnici 		/*
7980c7707fdSMarc Bonnici 		 * Ensure that the SP is reporting the same version as
7990c7707fdSMarc Bonnici 		 * specified in its manifest. If these do not match there is
8000c7707fdSMarc Bonnici 		 * something wrong with the SP.
8010c7707fdSMarc Bonnici 		 * TODO: Should we abort the SP? For now assert this is not
8020c7707fdSMarc Bonnici 		 *       case.
8030c7707fdSMarc Bonnici 		 */
8040c7707fdSMarc Bonnici 		assert(requested_version ==
8050c7707fdSMarc Bonnici 		       spmc_get_current_sp_ctx()->ffa_version);
8060c7707fdSMarc Bonnici 	} else {
8070c7707fdSMarc Bonnici 		/*
8080c7707fdSMarc Bonnici 		 * If this is called by the normal world, record this
8090c7707fdSMarc Bonnici 		 * information in its descriptor.
8100c7707fdSMarc Bonnici 		 */
8110c7707fdSMarc Bonnici 		spmc_get_hyp_ctx()->ffa_version = requested_version;
8120c7707fdSMarc Bonnici 	}
8130c7707fdSMarc Bonnici 
814dd87b735SJ-Alves 	SMC_RET1(handle, MAKE_FFA_VERSION(FFA_VERSION_SPMC_MAJOR,
815dd87b735SJ-Alves 					  FFA_VERSION_SPMC_MINOR));
8160c7707fdSMarc Bonnici }
8170c7707fdSMarc Bonnici 
rxtx_map_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)8181a752245SMarc Bonnici static uint64_t rxtx_map_handler(uint32_t smc_fid,
8191a752245SMarc Bonnici 				 bool secure_origin,
8201a752245SMarc Bonnici 				 uint64_t x1,
8211a752245SMarc Bonnici 				 uint64_t x2,
8221a752245SMarc Bonnici 				 uint64_t x3,
8231a752245SMarc Bonnici 				 uint64_t x4,
8241a752245SMarc Bonnici 				 void *cookie,
8251a752245SMarc Bonnici 				 void *handle,
8261a752245SMarc Bonnici 				 uint64_t flags)
8271a752245SMarc Bonnici {
8281a752245SMarc Bonnici 	int ret;
8291a752245SMarc Bonnici 	uint32_t error_code;
8301a752245SMarc Bonnici 	uint32_t mem_atts = secure_origin ? MT_SECURE : MT_NS;
8311a752245SMarc Bonnici 	struct mailbox *mbox;
8321a752245SMarc Bonnici 	uintptr_t tx_address = x1;
8331a752245SMarc Bonnici 	uintptr_t rx_address = x2;
8341a752245SMarc Bonnici 	uint32_t page_count = x3 & FFA_RXTX_PAGE_COUNT_MASK; /* Bits [5:0] */
8351a752245SMarc Bonnici 	uint32_t buf_size = page_count * FFA_PAGE_SIZE;
8361a752245SMarc Bonnici 
8371a752245SMarc Bonnici 	/*
8381a752245SMarc Bonnici 	 * The SPMC does not support mapping of VM RX/TX pairs to facilitate
8391a752245SMarc Bonnici 	 * indirect messaging with SPs. Check if the Hypervisor has invoked this
8401a752245SMarc Bonnici 	 * ABI on behalf of a VM and reject it if this is the case.
8411a752245SMarc Bonnici 	 */
8421a752245SMarc Bonnici 	if (tx_address == 0 || rx_address == 0) {
8431a752245SMarc Bonnici 		WARN("Mapping RX/TX Buffers on behalf of VM not supported.\n");
8441a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
8451a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
8461a752245SMarc Bonnici 	}
8471a752245SMarc Bonnici 
8481a752245SMarc Bonnici 	/* Ensure the specified buffers are not the same. */
8491a752245SMarc Bonnici 	if (tx_address == rx_address) {
8501a752245SMarc Bonnici 		WARN("TX Buffer must not be the same as RX Buffer.\n");
8511a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
8521a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
8531a752245SMarc Bonnici 	}
8541a752245SMarc Bonnici 
8551a752245SMarc Bonnici 	/* Ensure the buffer size is not 0. */
8561a752245SMarc Bonnici 	if (buf_size == 0U) {
8571a752245SMarc Bonnici 		WARN("Buffer size must not be 0\n");
8581a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
8591a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
8601a752245SMarc Bonnici 	}
8611a752245SMarc Bonnici 
8621a752245SMarc Bonnici 	/*
8631a752245SMarc Bonnici 	 * Ensure the buffer size is a multiple of the translation granule size
8641a752245SMarc Bonnici 	 * in TF-A.
8651a752245SMarc Bonnici 	 */
8661a752245SMarc Bonnici 	if (buf_size % PAGE_SIZE != 0U) {
8671a752245SMarc Bonnici 		WARN("Buffer size must be aligned to translation granule.\n");
8681a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
8691a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
8701a752245SMarc Bonnici 	}
8711a752245SMarc Bonnici 
8721a752245SMarc Bonnici 	/* Obtain the RX/TX buffer pair descriptor. */
8731a752245SMarc Bonnici 	mbox = spmc_get_mbox_desc(secure_origin);
8741a752245SMarc Bonnici 
8751a752245SMarc Bonnici 	spin_lock(&mbox->lock);
8761a752245SMarc Bonnici 
8771a752245SMarc Bonnici 	/* Check if buffers have already been mapped. */
8781a752245SMarc Bonnici 	if (mbox->rx_buffer != 0 || mbox->tx_buffer != 0) {
8791a752245SMarc Bonnici 		WARN("RX/TX Buffers already mapped (%p/%p)\n",
8801a752245SMarc Bonnici 		     (void *) mbox->rx_buffer, (void *)mbox->tx_buffer);
8811a752245SMarc Bonnici 		error_code = FFA_ERROR_DENIED;
8821a752245SMarc Bonnici 		goto err;
8831a752245SMarc Bonnici 	}
8841a752245SMarc Bonnici 
8851a752245SMarc Bonnici 	/* memmap the TX buffer as read only. */
8861a752245SMarc Bonnici 	ret = mmap_add_dynamic_region(tx_address, /* PA */
8871a752245SMarc Bonnici 			tx_address, /* VA */
8881a752245SMarc Bonnici 			buf_size, /* size */
8891a752245SMarc Bonnici 			mem_atts | MT_RO_DATA); /* attrs */
8901a752245SMarc Bonnici 	if (ret != 0) {
8911a752245SMarc Bonnici 		/* Return the correct error code. */
8921a752245SMarc Bonnici 		error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
8931a752245SMarc Bonnici 						FFA_ERROR_INVALID_PARAMETER;
8941a752245SMarc Bonnici 		WARN("Unable to map TX buffer: %d\n", error_code);
8951a752245SMarc Bonnici 		goto err;
8961a752245SMarc Bonnici 	}
8971a752245SMarc Bonnici 
8981a752245SMarc Bonnici 	/* memmap the RX buffer as read write. */
8991a752245SMarc Bonnici 	ret = mmap_add_dynamic_region(rx_address, /* PA */
9001a752245SMarc Bonnici 			rx_address, /* VA */
9011a752245SMarc Bonnici 			buf_size, /* size */
9021a752245SMarc Bonnici 			mem_atts | MT_RW_DATA); /* attrs */
9031a752245SMarc Bonnici 
9041a752245SMarc Bonnici 	if (ret != 0) {
9051a752245SMarc Bonnici 		error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY :
9061a752245SMarc Bonnici 						FFA_ERROR_INVALID_PARAMETER;
9071a752245SMarc Bonnici 		WARN("Unable to map RX buffer: %d\n", error_code);
9081a752245SMarc Bonnici 		/* Unmap the TX buffer again. */
9091a752245SMarc Bonnici 		mmap_remove_dynamic_region(tx_address, buf_size);
9101a752245SMarc Bonnici 		goto err;
9111a752245SMarc Bonnici 	}
9121a752245SMarc Bonnici 
9131a752245SMarc Bonnici 	mbox->tx_buffer = (void *) tx_address;
9141a752245SMarc Bonnici 	mbox->rx_buffer = (void *) rx_address;
9151a752245SMarc Bonnici 	mbox->rxtx_page_count = page_count;
9161a752245SMarc Bonnici 	spin_unlock(&mbox->lock);
9171a752245SMarc Bonnici 
9181a752245SMarc Bonnici 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
9191a752245SMarc Bonnici 	/* Execution stops here. */
9201a752245SMarc Bonnici err:
9211a752245SMarc Bonnici 	spin_unlock(&mbox->lock);
9221a752245SMarc Bonnici 	return spmc_ffa_error_return(handle, error_code);
9231a752245SMarc Bonnici }
9241a752245SMarc Bonnici 
rxtx_unmap_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)9251a752245SMarc Bonnici static uint64_t rxtx_unmap_handler(uint32_t smc_fid,
9261a752245SMarc Bonnici 				   bool secure_origin,
9271a752245SMarc Bonnici 				   uint64_t x1,
9281a752245SMarc Bonnici 				   uint64_t x2,
9291a752245SMarc Bonnici 				   uint64_t x3,
9301a752245SMarc Bonnici 				   uint64_t x4,
9311a752245SMarc Bonnici 				   void *cookie,
9321a752245SMarc Bonnici 				   void *handle,
9331a752245SMarc Bonnici 				   uint64_t flags)
9341a752245SMarc Bonnici {
9351a752245SMarc Bonnici 	struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
9361a752245SMarc Bonnici 	uint32_t buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
9371a752245SMarc Bonnici 
9381a752245SMarc Bonnici 	/*
9391a752245SMarc Bonnici 	 * The SPMC does not support mapping of VM RX/TX pairs to facilitate
9401a752245SMarc Bonnici 	 * indirect messaging with SPs. Check if the Hypervisor has invoked this
9411a752245SMarc Bonnici 	 * ABI on behalf of a VM and reject it if this is the case.
9421a752245SMarc Bonnici 	 */
9431a752245SMarc Bonnici 	if (x1 != 0UL) {
9441a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
9451a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
9461a752245SMarc Bonnici 	}
9471a752245SMarc Bonnici 
9481a752245SMarc Bonnici 	spin_lock(&mbox->lock);
9491a752245SMarc Bonnici 
9501a752245SMarc Bonnici 	/* Check if buffers are currently mapped. */
9511a752245SMarc Bonnici 	if (mbox->rx_buffer == 0 || mbox->tx_buffer == 0) {
9521a752245SMarc Bonnici 		spin_unlock(&mbox->lock);
9531a752245SMarc Bonnici 		return spmc_ffa_error_return(handle,
9541a752245SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
9551a752245SMarc Bonnici 	}
9561a752245SMarc Bonnici 
9571a752245SMarc Bonnici 	/* Unmap RX Buffer */
9581a752245SMarc Bonnici 	if (mmap_remove_dynamic_region((uintptr_t) mbox->rx_buffer,
9591a752245SMarc Bonnici 				       buf_size) != 0) {
9601a752245SMarc Bonnici 		WARN("Unable to unmap RX buffer!\n");
9611a752245SMarc Bonnici 	}
9621a752245SMarc Bonnici 
9631a752245SMarc Bonnici 	mbox->rx_buffer = 0;
9641a752245SMarc Bonnici 
9651a752245SMarc Bonnici 	/* Unmap TX Buffer */
9661a752245SMarc Bonnici 	if (mmap_remove_dynamic_region((uintptr_t) mbox->tx_buffer,
9671a752245SMarc Bonnici 				       buf_size) != 0) {
9681a752245SMarc Bonnici 		WARN("Unable to unmap TX buffer!\n");
9691a752245SMarc Bonnici 	}
9701a752245SMarc Bonnici 
9711a752245SMarc Bonnici 	mbox->tx_buffer = 0;
9721a752245SMarc Bonnici 	mbox->rxtx_page_count = 0;
9731a752245SMarc Bonnici 
9741a752245SMarc Bonnici 	spin_unlock(&mbox->lock);
9751a752245SMarc Bonnici 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
9761a752245SMarc Bonnici }
9771a752245SMarc Bonnici 
978f74e2772SMarc Bonnici /*
97962cd8f31SMarc Bonnici  * Helper function to populate the properties field of a Partition Info Get
98062cd8f31SMarc Bonnici  * descriptor.
98162cd8f31SMarc Bonnici  */
98262cd8f31SMarc Bonnici static uint32_t
partition_info_get_populate_properties(uint32_t sp_properties,enum sp_execution_state sp_ec_state)98362cd8f31SMarc Bonnici partition_info_get_populate_properties(uint32_t sp_properties,
98462cd8f31SMarc Bonnici 				       enum sp_execution_state sp_ec_state)
98562cd8f31SMarc Bonnici {
98662cd8f31SMarc Bonnici 	uint32_t properties = sp_properties;
98762cd8f31SMarc Bonnici 	uint32_t ec_state;
98862cd8f31SMarc Bonnici 
98962cd8f31SMarc Bonnici 	/* Determine the execution state of the SP. */
99062cd8f31SMarc Bonnici 	ec_state = sp_ec_state == SP_STATE_AARCH64 ?
99162cd8f31SMarc Bonnici 		   FFA_PARTITION_INFO_GET_AARCH64_STATE :
99262cd8f31SMarc Bonnici 		   FFA_PARTITION_INFO_GET_AARCH32_STATE;
99362cd8f31SMarc Bonnici 
99462cd8f31SMarc Bonnici 	properties |= ec_state << FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT;
99562cd8f31SMarc Bonnici 
99662cd8f31SMarc Bonnici 	return properties;
99762cd8f31SMarc Bonnici }
99862cd8f31SMarc Bonnici 
99962cd8f31SMarc Bonnici /*
1000f74e2772SMarc Bonnici  * Collate the partition information in a v1.1 partition information
1001f74e2772SMarc Bonnici  * descriptor format, this will be converter later if required.
1002f74e2772SMarc Bonnici  */
partition_info_get_handler_v1_1(uint32_t * uuid,struct ffa_partition_info_v1_1 * partitions,uint32_t max_partitions,uint32_t * partition_count)1003f74e2772SMarc Bonnici static int partition_info_get_handler_v1_1(uint32_t *uuid,
1004f74e2772SMarc Bonnici 					   struct ffa_partition_info_v1_1
1005f74e2772SMarc Bonnici 						  *partitions,
1006f74e2772SMarc Bonnici 					   uint32_t max_partitions,
1007f74e2772SMarc Bonnici 					   uint32_t *partition_count)
1008f74e2772SMarc Bonnici {
1009f74e2772SMarc Bonnici 	uint32_t index;
1010f74e2772SMarc Bonnici 	struct ffa_partition_info_v1_1 *desc;
1011f74e2772SMarc Bonnici 	bool null_uuid = is_null_uuid(uuid);
1012f74e2772SMarc Bonnici 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
1013f74e2772SMarc Bonnici 
1014f74e2772SMarc Bonnici 	/* Deal with Logical Partitions. */
1015f74e2772SMarc Bonnici 	for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
1016f74e2772SMarc Bonnici 		if (null_uuid || uuid_match(uuid, el3_lp_descs[index].uuid)) {
1017f74e2772SMarc Bonnici 			/* Found a matching UUID, populate appropriately. */
1018f74e2772SMarc Bonnici 			if (*partition_count >= max_partitions) {
1019f74e2772SMarc Bonnici 				return FFA_ERROR_NO_MEMORY;
1020f74e2772SMarc Bonnici 			}
1021f74e2772SMarc Bonnici 
1022f74e2772SMarc Bonnici 			desc = &partitions[*partition_count];
1023f74e2772SMarc Bonnici 			desc->ep_id = el3_lp_descs[index].sp_id;
1024f74e2772SMarc Bonnici 			desc->execution_ctx_count = PLATFORM_CORE_COUNT;
102562cd8f31SMarc Bonnici 			/* LSPs must be AArch64. */
102662cd8f31SMarc Bonnici 			desc->properties =
102762cd8f31SMarc Bonnici 				partition_info_get_populate_properties(
102862cd8f31SMarc Bonnici 					el3_lp_descs[index].properties,
102962cd8f31SMarc Bonnici 					SP_STATE_AARCH64);
103062cd8f31SMarc Bonnici 
1031f74e2772SMarc Bonnici 			if (null_uuid) {
1032f74e2772SMarc Bonnici 				copy_uuid(desc->uuid, el3_lp_descs[index].uuid);
1033f74e2772SMarc Bonnici 			}
1034f74e2772SMarc Bonnici 			(*partition_count)++;
1035f74e2772SMarc Bonnici 		}
1036f74e2772SMarc Bonnici 	}
1037f74e2772SMarc Bonnici 
1038f74e2772SMarc Bonnici 	/* Deal with physical SP's. */
1039f74e2772SMarc Bonnici 	for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
1040*0322d7afSJay Monkman 		uint32_t uuid_index;
1041*0322d7afSJay Monkman 		uint32_t *sp_uuid;
1042*0322d7afSJay Monkman 
1043*0322d7afSJay Monkman 		for (uuid_index = 0; uuid_index < sp_desc[index].num_uuids;
1044*0322d7afSJay Monkman 		     uuid_index++) {
1045*0322d7afSJay Monkman 			sp_uuid = sp_desc[index].uuid_array[uuid_index].uuid;
1046*0322d7afSJay Monkman 
1047*0322d7afSJay Monkman 			if (null_uuid || uuid_match(uuid, sp_uuid)) {
1048f74e2772SMarc Bonnici 				/* Found a matching UUID, populate appropriately. */
1049*0322d7afSJay Monkman 
1050f74e2772SMarc Bonnici 				if (*partition_count >= max_partitions) {
1051f74e2772SMarc Bonnici 					return FFA_ERROR_NO_MEMORY;
1052f74e2772SMarc Bonnici 				}
1053f74e2772SMarc Bonnici 
1054f74e2772SMarc Bonnici 				desc = &partitions[*partition_count];
1055f74e2772SMarc Bonnici 				desc->ep_id = sp_desc[index].sp_id;
1056f74e2772SMarc Bonnici 				/*
1057f74e2772SMarc Bonnici 				 * Execution context count must match No. cores for
1058f74e2772SMarc Bonnici 				 * S-EL1 SPs.
1059f74e2772SMarc Bonnici 				 */
1060f74e2772SMarc Bonnici 				desc->execution_ctx_count = PLATFORM_CORE_COUNT;
106162cd8f31SMarc Bonnici 				desc->properties =
106262cd8f31SMarc Bonnici 					partition_info_get_populate_properties(
106362cd8f31SMarc Bonnici 						sp_desc[index].properties,
106462cd8f31SMarc Bonnici 						sp_desc[index].execution_state);
106562cd8f31SMarc Bonnici 
1066f74e2772SMarc Bonnici 				(*partition_count)++;
1067*0322d7afSJay Monkman 				if (null_uuid) {
1068*0322d7afSJay Monkman 					copy_uuid(desc->uuid, sp_uuid);
1069*0322d7afSJay Monkman 				} else {
1070*0322d7afSJay Monkman 					/* Found UUID in this SP, go to next SP */
1071*0322d7afSJay Monkman 					break;
1072*0322d7afSJay Monkman 				}
1073*0322d7afSJay Monkman 			}
1074f74e2772SMarc Bonnici 		}
1075f74e2772SMarc Bonnici 	}
1076f74e2772SMarc Bonnici 	return 0;
1077f74e2772SMarc Bonnici }
1078f74e2772SMarc Bonnici 
1079f74e2772SMarc Bonnici /*
1080f74e2772SMarc Bonnici  * Handle the case where that caller only wants the count of partitions
1081f74e2772SMarc Bonnici  * matching a given UUID and does not want the corresponding descriptors
1082f74e2772SMarc Bonnici  * populated.
1083f74e2772SMarc Bonnici  */
partition_info_get_handler_count_only(uint32_t * uuid)1084f74e2772SMarc Bonnici static uint32_t partition_info_get_handler_count_only(uint32_t *uuid)
1085f74e2772SMarc Bonnici {
1086f74e2772SMarc Bonnici 	uint32_t index = 0;
1087f74e2772SMarc Bonnici 	uint32_t partition_count = 0;
1088f74e2772SMarc Bonnici 	bool null_uuid = is_null_uuid(uuid);
1089f74e2772SMarc Bonnici 	struct el3_lp_desc *el3_lp_descs = get_el3_lp_array();
1090f74e2772SMarc Bonnici 
1091f74e2772SMarc Bonnici 	/* Deal with Logical Partitions. */
1092f74e2772SMarc Bonnici 	for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) {
1093f74e2772SMarc Bonnici 		if (null_uuid ||
1094f74e2772SMarc Bonnici 		    uuid_match(uuid, el3_lp_descs[index].uuid)) {
1095f74e2772SMarc Bonnici 			(partition_count)++;
1096f74e2772SMarc Bonnici 		}
1097f74e2772SMarc Bonnici 	}
1098f74e2772SMarc Bonnici 
1099f74e2772SMarc Bonnici 	/* Deal with physical SP's. */
1100f74e2772SMarc Bonnici 	for (index = 0U; index < SECURE_PARTITION_COUNT; index++) {
1101*0322d7afSJay Monkman 		uint32_t uuid_index;
1102*0322d7afSJay Monkman 
1103*0322d7afSJay Monkman 		for (uuid_index = 0; uuid_index < sp_desc[index].num_uuids;
1104*0322d7afSJay Monkman 		     uuid_index++) {
1105*0322d7afSJay Monkman 			uint32_t *sp_uuid =
1106*0322d7afSJay Monkman 				sp_desc[index].uuid_array[uuid_index].uuid;
1107*0322d7afSJay Monkman 
1108*0322d7afSJay Monkman 			if (null_uuid) {
1109f74e2772SMarc Bonnici 				(partition_count)++;
1110*0322d7afSJay Monkman 			} else if (uuid_match(uuid, sp_uuid)) {
1111*0322d7afSJay Monkman 				(partition_count)++;
1112*0322d7afSJay Monkman 				/* Found a match, go to next SP */
1113*0322d7afSJay Monkman 				break;
1114*0322d7afSJay Monkman 			}
1115f74e2772SMarc Bonnici 		}
1116f74e2772SMarc Bonnici 	}
1117f74e2772SMarc Bonnici 	return partition_count;
1118f74e2772SMarc Bonnici }
1119f74e2772SMarc Bonnici 
1120f74e2772SMarc Bonnici /*
1121f74e2772SMarc Bonnici  * If the caller of the PARTITION_INFO_GET ABI was a v1.0 caller, populate
112262cd8f31SMarc Bonnici  * the corresponding descriptor format from the v1.1 descriptor array.
1123f74e2772SMarc Bonnici  */
partition_info_populate_v1_0(struct ffa_partition_info_v1_1 * partitions,struct mailbox * mbox,int partition_count)1124f74e2772SMarc Bonnici static uint64_t partition_info_populate_v1_0(struct ffa_partition_info_v1_1
1125f74e2772SMarc Bonnici 					     *partitions,
1126f74e2772SMarc Bonnici 					     struct mailbox *mbox,
1127f74e2772SMarc Bonnici 					     int partition_count)
1128f74e2772SMarc Bonnici {
1129f74e2772SMarc Bonnici 	uint32_t index;
1130f74e2772SMarc Bonnici 	uint32_t buf_size;
1131f74e2772SMarc Bonnici 	uint32_t descriptor_size;
1132f74e2772SMarc Bonnici 	struct ffa_partition_info_v1_0 *v1_0_partitions =
1133f74e2772SMarc Bonnici 		(struct ffa_partition_info_v1_0 *) mbox->rx_buffer;
1134f74e2772SMarc Bonnici 
1135f74e2772SMarc Bonnici 	buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
1136f74e2772SMarc Bonnici 	descriptor_size = partition_count *
1137f74e2772SMarc Bonnici 			  sizeof(struct ffa_partition_info_v1_0);
1138f74e2772SMarc Bonnici 
1139f74e2772SMarc Bonnici 	if (descriptor_size > buf_size) {
1140f74e2772SMarc Bonnici 		return FFA_ERROR_NO_MEMORY;
1141f74e2772SMarc Bonnici 	}
1142f74e2772SMarc Bonnici 
1143f74e2772SMarc Bonnici 	for (index = 0U; index < partition_count; index++) {
1144f74e2772SMarc Bonnici 		v1_0_partitions[index].ep_id = partitions[index].ep_id;
1145f74e2772SMarc Bonnici 		v1_0_partitions[index].execution_ctx_count =
1146f74e2772SMarc Bonnici 			partitions[index].execution_ctx_count;
114762cd8f31SMarc Bonnici 		/* Only report v1.0 properties. */
1148f74e2772SMarc Bonnici 		v1_0_partitions[index].properties =
114962cd8f31SMarc Bonnici 			(partitions[index].properties &
115062cd8f31SMarc Bonnici 			FFA_PARTITION_INFO_GET_PROPERTIES_V1_0_MASK);
1151f74e2772SMarc Bonnici 	}
1152f74e2772SMarc Bonnici 	return 0;
1153f74e2772SMarc Bonnici }
1154f74e2772SMarc Bonnici 
1155f74e2772SMarc Bonnici /*
1156f74e2772SMarc Bonnici  * Main handler for FFA_PARTITION_INFO_GET which supports both FF-A v1.1 and
1157f74e2772SMarc Bonnici  * v1.0 implementations.
1158f74e2772SMarc Bonnici  */
partition_info_get_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)1159f74e2772SMarc Bonnici static uint64_t partition_info_get_handler(uint32_t smc_fid,
1160f74e2772SMarc Bonnici 					   bool secure_origin,
1161f74e2772SMarc Bonnici 					   uint64_t x1,
1162f74e2772SMarc Bonnici 					   uint64_t x2,
1163f74e2772SMarc Bonnici 					   uint64_t x3,
1164f74e2772SMarc Bonnici 					   uint64_t x4,
1165f74e2772SMarc Bonnici 					   void *cookie,
1166f74e2772SMarc Bonnici 					   void *handle,
1167f74e2772SMarc Bonnici 					   uint64_t flags)
1168f74e2772SMarc Bonnici {
1169f74e2772SMarc Bonnici 	int ret;
1170f74e2772SMarc Bonnici 	uint32_t partition_count = 0;
1171f74e2772SMarc Bonnici 	uint32_t size = 0;
1172f74e2772SMarc Bonnici 	uint32_t ffa_version = get_partition_ffa_version(secure_origin);
1173f74e2772SMarc Bonnici 	struct mailbox *mbox;
1174f74e2772SMarc Bonnici 	uint64_t info_get_flags;
1175f74e2772SMarc Bonnici 	bool count_only;
1176f74e2772SMarc Bonnici 	uint32_t uuid[4];
1177f74e2772SMarc Bonnici 
1178f74e2772SMarc Bonnici 	uuid[0] = x1;
1179f74e2772SMarc Bonnici 	uuid[1] = x2;
1180f74e2772SMarc Bonnici 	uuid[2] = x3;
1181f74e2772SMarc Bonnici 	uuid[3] = x4;
1182f74e2772SMarc Bonnici 
1183f74e2772SMarc Bonnici 	/* Determine if the Partition descriptors should be populated. */
1184f74e2772SMarc Bonnici 	info_get_flags = SMC_GET_GP(handle, CTX_GPREG_X5);
1185f74e2772SMarc Bonnici 	count_only = (info_get_flags & FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK);
1186f74e2772SMarc Bonnici 
1187f74e2772SMarc Bonnici 	/* Handle the case where we don't need to populate the descriptors. */
1188f74e2772SMarc Bonnici 	if (count_only) {
1189f74e2772SMarc Bonnici 		partition_count = partition_info_get_handler_count_only(uuid);
1190f74e2772SMarc Bonnici 		if (partition_count == 0) {
1191f74e2772SMarc Bonnici 			return spmc_ffa_error_return(handle,
1192f74e2772SMarc Bonnici 						FFA_ERROR_INVALID_PARAMETER);
1193f74e2772SMarc Bonnici 		}
1194f74e2772SMarc Bonnici 	} else {
1195*0322d7afSJay Monkman 		struct ffa_partition_info_v1_1
1196*0322d7afSJay Monkman 			partitions[MAX_SP_LP_PARTITIONS *
1197*0322d7afSJay Monkman 				   SPMC_AT_EL3_PARTITION_MAX_UUIDS];
1198f74e2772SMarc Bonnici 		/*
1199f74e2772SMarc Bonnici 		 * Handle the case where the partition descriptors are required,
1200f74e2772SMarc Bonnici 		 * check we have the buffers available and populate the
1201f74e2772SMarc Bonnici 		 * appropriate structure version.
1202f74e2772SMarc Bonnici 		 */
1203f74e2772SMarc Bonnici 
1204f74e2772SMarc Bonnici 		/* Obtain the v1.1 format of the descriptors. */
1205*0322d7afSJay Monkman 		ret = partition_info_get_handler_v1_1(
1206*0322d7afSJay Monkman 			uuid, partitions,
1207*0322d7afSJay Monkman 			(MAX_SP_LP_PARTITIONS *
1208*0322d7afSJay Monkman 			 SPMC_AT_EL3_PARTITION_MAX_UUIDS),
1209f74e2772SMarc Bonnici 			&partition_count);
1210f74e2772SMarc Bonnici 
1211f74e2772SMarc Bonnici 		/* Check if an error occurred during discovery. */
1212f74e2772SMarc Bonnici 		if (ret != 0) {
1213f74e2772SMarc Bonnici 			goto err;
1214f74e2772SMarc Bonnici 		}
1215f74e2772SMarc Bonnici 
1216f74e2772SMarc Bonnici 		/* If we didn't find any matches the UUID is unknown. */
1217f74e2772SMarc Bonnici 		if (partition_count == 0) {
1218f74e2772SMarc Bonnici 			ret = FFA_ERROR_INVALID_PARAMETER;
1219f74e2772SMarc Bonnici 			goto err;
1220f74e2772SMarc Bonnici 		}
1221f74e2772SMarc Bonnici 
1222f74e2772SMarc Bonnici 		/* Obtain the partition mailbox RX/TX buffer pair descriptor. */
1223f74e2772SMarc Bonnici 		mbox = spmc_get_mbox_desc(secure_origin);
1224f74e2772SMarc Bonnici 
1225f74e2772SMarc Bonnici 		/*
1226f74e2772SMarc Bonnici 		 * If the caller has not bothered registering its RX/TX pair
1227f74e2772SMarc Bonnici 		 * then return an error code.
1228f74e2772SMarc Bonnici 		 */
1229f74e2772SMarc Bonnici 		spin_lock(&mbox->lock);
1230f74e2772SMarc Bonnici 		if (mbox->rx_buffer == NULL) {
1231f74e2772SMarc Bonnici 			ret = FFA_ERROR_BUSY;
1232f74e2772SMarc Bonnici 			goto err_unlock;
1233f74e2772SMarc Bonnici 		}
1234f74e2772SMarc Bonnici 
1235f74e2772SMarc Bonnici 		/* Ensure the RX buffer is currently free. */
1236f74e2772SMarc Bonnici 		if (mbox->state != MAILBOX_STATE_EMPTY) {
1237f74e2772SMarc Bonnici 			ret = FFA_ERROR_BUSY;
1238f74e2772SMarc Bonnici 			goto err_unlock;
1239f74e2772SMarc Bonnici 		}
1240f74e2772SMarc Bonnici 
1241f74e2772SMarc Bonnici 		/* Zero the RX buffer before populating. */
1242f74e2772SMarc Bonnici 		(void)memset(mbox->rx_buffer, 0,
1243f74e2772SMarc Bonnici 			     mbox->rxtx_page_count * FFA_PAGE_SIZE);
1244f74e2772SMarc Bonnici 
1245f74e2772SMarc Bonnici 		/*
1246f74e2772SMarc Bonnici 		 * Depending on the FF-A version of the requesting partition
1247f74e2772SMarc Bonnici 		 * we may need to convert to a v1.0 format otherwise we can copy
1248f74e2772SMarc Bonnici 		 * directly.
1249f74e2772SMarc Bonnici 		 */
1250f74e2772SMarc Bonnici 		if (ffa_version == MAKE_FFA_VERSION(U(1), U(0))) {
1251f74e2772SMarc Bonnici 			ret = partition_info_populate_v1_0(partitions,
1252f74e2772SMarc Bonnici 							   mbox,
1253f74e2772SMarc Bonnici 							   partition_count);
1254f74e2772SMarc Bonnici 			if (ret != 0) {
1255f74e2772SMarc Bonnici 				goto err_unlock;
1256f74e2772SMarc Bonnici 			}
1257f74e2772SMarc Bonnici 		} else {
1258f74e2772SMarc Bonnici 			uint32_t buf_size = mbox->rxtx_page_count *
1259f74e2772SMarc Bonnici 					    FFA_PAGE_SIZE;
1260f74e2772SMarc Bonnici 
1261f74e2772SMarc Bonnici 			/* Ensure the descriptor will fit in the buffer. */
1262f74e2772SMarc Bonnici 			size = sizeof(struct ffa_partition_info_v1_1);
1263f74e2772SMarc Bonnici 			if (partition_count * size  > buf_size) {
1264f74e2772SMarc Bonnici 				ret = FFA_ERROR_NO_MEMORY;
1265f74e2772SMarc Bonnici 				goto err_unlock;
1266f74e2772SMarc Bonnici 			}
1267f74e2772SMarc Bonnici 			memcpy(mbox->rx_buffer, partitions,
1268f74e2772SMarc Bonnici 			       partition_count * size);
1269f74e2772SMarc Bonnici 		}
1270f74e2772SMarc Bonnici 
1271f74e2772SMarc Bonnici 		mbox->state = MAILBOX_STATE_FULL;
1272f74e2772SMarc Bonnici 		spin_unlock(&mbox->lock);
1273f74e2772SMarc Bonnici 	}
1274f74e2772SMarc Bonnici 	SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, partition_count, size);
1275f74e2772SMarc Bonnici 
1276f74e2772SMarc Bonnici err_unlock:
1277f74e2772SMarc Bonnici 	spin_unlock(&mbox->lock);
1278f74e2772SMarc Bonnici err:
1279f74e2772SMarc Bonnici 	return spmc_ffa_error_return(handle, ret);
1280f74e2772SMarc Bonnici }
1281f74e2772SMarc Bonnici 
ffa_feature_success(void * handle,uint32_t arg2)12820560b53eSMarc Bonnici static uint64_t ffa_feature_success(void *handle, uint32_t arg2)
12830560b53eSMarc Bonnici {
12840560b53eSMarc Bonnici 	SMC_RET3(handle, FFA_SUCCESS_SMC32, 0, arg2);
12850560b53eSMarc Bonnici }
12860560b53eSMarc Bonnici 
ffa_features_retrieve_request(bool secure_origin,uint32_t input_properties,void * handle)12870560b53eSMarc Bonnici static uint64_t ffa_features_retrieve_request(bool secure_origin,
12880560b53eSMarc Bonnici 					      uint32_t input_properties,
12890560b53eSMarc Bonnici 					      void *handle)
12900560b53eSMarc Bonnici {
12910560b53eSMarc Bonnici 	/*
12920560b53eSMarc Bonnici 	 * If we're called by the normal world we don't support any
12930560b53eSMarc Bonnici 	 * additional features.
12940560b53eSMarc Bonnici 	 */
12950560b53eSMarc Bonnici 	if (!secure_origin) {
12960560b53eSMarc Bonnici 		if ((input_properties & FFA_FEATURES_RET_REQ_NS_BIT) != 0U) {
12970560b53eSMarc Bonnici 			return spmc_ffa_error_return(handle,
12980560b53eSMarc Bonnici 						     FFA_ERROR_NOT_SUPPORTED);
12990560b53eSMarc Bonnici 		}
13000560b53eSMarc Bonnici 
13010560b53eSMarc Bonnici 	} else {
13020560b53eSMarc Bonnici 		struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
13030560b53eSMarc Bonnici 		/*
13043f1c63ddSJay Monkman 		 * If v1.1 or higher the NS bit must be set otherwise it is
13053f1c63ddSJay Monkman 		 * an invalid call. If v1.0 check and store whether the SP
13063f1c63ddSJay Monkman 		 * has requested the use of the NS bit.
13070560b53eSMarc Bonnici 		 */
13083f1c63ddSJay Monkman 		if (spmc_compatible_version(sp->ffa_version, 1, 1)) {
13090560b53eSMarc Bonnici 			if ((input_properties &
13100560b53eSMarc Bonnici 			     FFA_FEATURES_RET_REQ_NS_BIT) == 0U) {
13110560b53eSMarc Bonnici 				return spmc_ffa_error_return(handle,
13120560b53eSMarc Bonnici 						       FFA_ERROR_NOT_SUPPORTED);
13130560b53eSMarc Bonnici 			}
13140560b53eSMarc Bonnici 			return ffa_feature_success(handle,
13150560b53eSMarc Bonnici 						   FFA_FEATURES_RET_REQ_NS_BIT);
13160560b53eSMarc Bonnici 		} else {
13170560b53eSMarc Bonnici 			sp->ns_bit_requested = (input_properties &
13180560b53eSMarc Bonnici 					       FFA_FEATURES_RET_REQ_NS_BIT) !=
13190560b53eSMarc Bonnici 					       0U;
13200560b53eSMarc Bonnici 		}
13210560b53eSMarc Bonnici 		if (sp->ns_bit_requested) {
13220560b53eSMarc Bonnici 			return ffa_feature_success(handle,
13230560b53eSMarc Bonnici 						   FFA_FEATURES_RET_REQ_NS_BIT);
13240560b53eSMarc Bonnici 		}
13250560b53eSMarc Bonnici 	}
13260560b53eSMarc Bonnici 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
13270560b53eSMarc Bonnici }
13280560b53eSMarc Bonnici 
ffa_features_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)132955a29638SMarc Bonnici static uint64_t ffa_features_handler(uint32_t smc_fid,
133055a29638SMarc Bonnici 				     bool secure_origin,
133155a29638SMarc Bonnici 				     uint64_t x1,
133255a29638SMarc Bonnici 				     uint64_t x2,
133355a29638SMarc Bonnici 				     uint64_t x3,
133455a29638SMarc Bonnici 				     uint64_t x4,
133555a29638SMarc Bonnici 				     void *cookie,
133655a29638SMarc Bonnici 				     void *handle,
133755a29638SMarc Bonnici 				     uint64_t flags)
133855a29638SMarc Bonnici {
133955a29638SMarc Bonnici 	uint32_t function_id = (uint32_t) x1;
134055a29638SMarc Bonnici 	uint32_t input_properties = (uint32_t) x2;
134155a29638SMarc Bonnici 
134255a29638SMarc Bonnici 	/* Check if a Feature ID was requested. */
134355a29638SMarc Bonnici 	if ((function_id & FFA_FEATURES_BIT31_MASK) == 0U) {
134455a29638SMarc Bonnici 		/* We currently don't support any additional features. */
134555a29638SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
134655a29638SMarc Bonnici 	}
134755a29638SMarc Bonnici 
13480560b53eSMarc Bonnici 	/*
13490560b53eSMarc Bonnici 	 * Handle the cases where we have separate handlers due to additional
13500560b53eSMarc Bonnici 	 * properties.
13510560b53eSMarc Bonnici 	 */
13520560b53eSMarc Bonnici 	switch (function_id) {
13530560b53eSMarc Bonnici 	case FFA_MEM_RETRIEVE_REQ_SMC32:
13540560b53eSMarc Bonnici 	case FFA_MEM_RETRIEVE_REQ_SMC64:
13550560b53eSMarc Bonnici 		return ffa_features_retrieve_request(secure_origin,
13560560b53eSMarc Bonnici 						     input_properties,
13570560b53eSMarc Bonnici 						     handle);
13580560b53eSMarc Bonnici 	}
13590560b53eSMarc Bonnici 
13600560b53eSMarc Bonnici 	/*
13610560b53eSMarc Bonnici 	 * We don't currently support additional input properties for these
13620560b53eSMarc Bonnici 	 * other ABIs therefore ensure this value is set to 0.
13630560b53eSMarc Bonnici 	 */
13640560b53eSMarc Bonnici 	if (input_properties != 0U) {
13650560b53eSMarc Bonnici 		return spmc_ffa_error_return(handle,
13660560b53eSMarc Bonnici 					     FFA_ERROR_NOT_SUPPORTED);
13670560b53eSMarc Bonnici 	}
13680560b53eSMarc Bonnici 
13690560b53eSMarc Bonnici 	/* Report if any other FF-A ABI is supported. */
137055a29638SMarc Bonnici 	switch (function_id) {
137155a29638SMarc Bonnici 	/* Supported features from both worlds. */
137255a29638SMarc Bonnici 	case FFA_ERROR:
137355a29638SMarc Bonnici 	case FFA_SUCCESS_SMC32:
1374729d7793SAchin Gupta 	case FFA_INTERRUPT:
137546872e01SMarc Bonnici 	case FFA_SPM_ID_GET:
1376d5fe9235SMarc Bonnici 	case FFA_ID_GET:
137755a29638SMarc Bonnici 	case FFA_FEATURES:
137855a29638SMarc Bonnici 	case FFA_VERSION:
1379f0c25a08SMarc Bonnici 	case FFA_RX_RELEASE:
138055a29638SMarc Bonnici 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
138155a29638SMarc Bonnici 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
138209a580b7SLevi Yun 	case FFA_MSG_SEND_DIRECT_REQ2_SMC64:
138355a29638SMarc Bonnici 	case FFA_PARTITION_INFO_GET:
138455a29638SMarc Bonnici 	case FFA_RXTX_MAP_SMC32:
138555a29638SMarc Bonnici 	case FFA_RXTX_MAP_SMC64:
138655a29638SMarc Bonnici 	case FFA_RXTX_UNMAP:
1387e0b1a6d5SMarc Bonnici 	case FFA_MEM_FRAG_TX:
1388aad20c85SMarc Bonnici 	case FFA_MSG_RUN:
138955a29638SMarc Bonnici 
139055a29638SMarc Bonnici 		/*
139155a29638SMarc Bonnici 		 * We are relying on the fact that the other registers
139255a29638SMarc Bonnici 		 * will be set to 0 as these values align with the
139355a29638SMarc Bonnici 		 * currently implemented features of the SPMC. If this
139455a29638SMarc Bonnici 		 * changes this function must be extended to handle
139555a29638SMarc Bonnici 		 * reporting the additional functionality.
139655a29638SMarc Bonnici 		 */
139755a29638SMarc Bonnici 
139855a29638SMarc Bonnici 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
139955a29638SMarc Bonnici 		/* Execution stops here. */
140055a29638SMarc Bonnici 
140155a29638SMarc Bonnici 	/* Supported ABIs only from the secure world. */
1402d0ee0ec1SKarl Meakin 	case FFA_MEM_PERM_GET_SMC32:
1403d0ee0ec1SKarl Meakin 	case FFA_MEM_PERM_GET_SMC64:
1404d0ee0ec1SKarl Meakin 	case FFA_MEM_PERM_SET_SMC32:
1405d0ee0ec1SKarl Meakin 	case FFA_MEM_PERM_SET_SMC64:
1406d0ee0ec1SKarl Meakin 	/* these ABIs are only supported from S-EL0 SPs */
1407d0ee0ec1SKarl Meakin 	#if !(SPMC_AT_EL3_SEL0_SP)
1408d0ee0ec1SKarl Meakin 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
1409d0ee0ec1SKarl Meakin 	#endif
1410d0ee0ec1SKarl Meakin 	/* fall through */
1411d0ee0ec1SKarl Meakin 
141259bd2ad8SMarc Bonnici 	case FFA_SECONDARY_EP_REGISTER_SMC64:
141355a29638SMarc Bonnici 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
141455a29638SMarc Bonnici 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
141509a580b7SLevi Yun 	case FFA_MSG_SEND_DIRECT_RESP2_SMC64:
1416e0b1a6d5SMarc Bonnici 	case FFA_MEM_RELINQUISH:
141755a29638SMarc Bonnici 	case FFA_MSG_WAIT:
1418638a6f8eSShruti Gupta 	case FFA_CONSOLE_LOG_SMC32:
1419638a6f8eSShruti Gupta 	case FFA_CONSOLE_LOG_SMC64:
142055a29638SMarc Bonnici 		if (!secure_origin) {
142155a29638SMarc Bonnici 			return spmc_ffa_error_return(handle,
142255a29638SMarc Bonnici 				FFA_ERROR_NOT_SUPPORTED);
142355a29638SMarc Bonnici 		}
142455a29638SMarc Bonnici 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
142555a29638SMarc Bonnici 		/* Execution stops here. */
142655a29638SMarc Bonnici 
1427e0b1a6d5SMarc Bonnici 	/* Supported features only from the normal world. */
1428e0b1a6d5SMarc Bonnici 	case FFA_MEM_SHARE_SMC32:
1429e0b1a6d5SMarc Bonnici 	case FFA_MEM_SHARE_SMC64:
1430e0b1a6d5SMarc Bonnici 	case FFA_MEM_LEND_SMC32:
1431e0b1a6d5SMarc Bonnici 	case FFA_MEM_LEND_SMC64:
1432e0b1a6d5SMarc Bonnici 	case FFA_MEM_RECLAIM:
1433e0b1a6d5SMarc Bonnici 	case FFA_MEM_FRAG_RX:
1434e0b1a6d5SMarc Bonnici 
1435e0b1a6d5SMarc Bonnici 		if (secure_origin) {
1436e0b1a6d5SMarc Bonnici 			return spmc_ffa_error_return(handle,
1437e0b1a6d5SMarc Bonnici 					FFA_ERROR_NOT_SUPPORTED);
1438e0b1a6d5SMarc Bonnici 		}
1439e0b1a6d5SMarc Bonnici 		SMC_RET1(handle, FFA_SUCCESS_SMC32);
1440e0b1a6d5SMarc Bonnici 		/* Execution stops here. */
1441e0b1a6d5SMarc Bonnici 
144255a29638SMarc Bonnici 	default:
144355a29638SMarc Bonnici 		return spmc_ffa_error_return(handle,
144455a29638SMarc Bonnici 					FFA_ERROR_NOT_SUPPORTED);
144555a29638SMarc Bonnici 	}
144655a29638SMarc Bonnici }
144755a29638SMarc Bonnici 
ffa_id_get_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)1448d5fe9235SMarc Bonnici static uint64_t ffa_id_get_handler(uint32_t smc_fid,
1449d5fe9235SMarc Bonnici 				   bool secure_origin,
1450d5fe9235SMarc Bonnici 				   uint64_t x1,
1451d5fe9235SMarc Bonnici 				   uint64_t x2,
1452d5fe9235SMarc Bonnici 				   uint64_t x3,
1453d5fe9235SMarc Bonnici 				   uint64_t x4,
1454d5fe9235SMarc Bonnici 				   void *cookie,
1455d5fe9235SMarc Bonnici 				   void *handle,
1456d5fe9235SMarc Bonnici 				   uint64_t flags)
1457d5fe9235SMarc Bonnici {
1458d5fe9235SMarc Bonnici 	if (secure_origin) {
1459d5fe9235SMarc Bonnici 		SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
1460d5fe9235SMarc Bonnici 			 spmc_get_current_sp_ctx()->sp_id);
1461d5fe9235SMarc Bonnici 	} else {
1462d5fe9235SMarc Bonnici 		SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0,
1463d5fe9235SMarc Bonnici 			 spmc_get_hyp_ctx()->ns_ep_id);
1464d5fe9235SMarc Bonnici 	}
1465d5fe9235SMarc Bonnici }
1466d5fe9235SMarc Bonnici 
146746872e01SMarc Bonnici /*
146846872e01SMarc Bonnici  * Enable an SP to query the ID assigned to the SPMC.
146946872e01SMarc Bonnici  */
ffa_spm_id_get_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)147046872e01SMarc Bonnici static uint64_t ffa_spm_id_get_handler(uint32_t smc_fid,
147146872e01SMarc Bonnici 				       bool secure_origin,
147246872e01SMarc Bonnici 				       uint64_t x1,
147346872e01SMarc Bonnici 				       uint64_t x2,
147446872e01SMarc Bonnici 				       uint64_t x3,
147546872e01SMarc Bonnici 				       uint64_t x4,
147646872e01SMarc Bonnici 				       void *cookie,
147746872e01SMarc Bonnici 				       void *handle,
147846872e01SMarc Bonnici 				       uint64_t flags)
147946872e01SMarc Bonnici {
148046872e01SMarc Bonnici 	assert(x1 == 0UL);
148146872e01SMarc Bonnici 	assert(x2 == 0UL);
148246872e01SMarc Bonnici 	assert(x3 == 0UL);
148346872e01SMarc Bonnici 	assert(x4 == 0UL);
148446872e01SMarc Bonnici 	assert(SMC_GET_GP(handle, CTX_GPREG_X5) == 0UL);
148546872e01SMarc Bonnici 	assert(SMC_GET_GP(handle, CTX_GPREG_X6) == 0UL);
148646872e01SMarc Bonnici 	assert(SMC_GET_GP(handle, CTX_GPREG_X7) == 0UL);
148746872e01SMarc Bonnici 
148846872e01SMarc Bonnici 	SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0, FFA_SPMC_ID);
148946872e01SMarc Bonnici }
149046872e01SMarc Bonnici 
ffa_run_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)1491aad20c85SMarc Bonnici static uint64_t ffa_run_handler(uint32_t smc_fid,
1492aad20c85SMarc Bonnici 				bool secure_origin,
1493aad20c85SMarc Bonnici 				uint64_t x1,
1494aad20c85SMarc Bonnici 				uint64_t x2,
1495aad20c85SMarc Bonnici 				uint64_t x3,
1496aad20c85SMarc Bonnici 				uint64_t x4,
1497aad20c85SMarc Bonnici 				void *cookie,
1498aad20c85SMarc Bonnici 				void *handle,
1499aad20c85SMarc Bonnici 				uint64_t flags)
1500aad20c85SMarc Bonnici {
1501aad20c85SMarc Bonnici 	struct secure_partition_desc *sp;
1502aad20c85SMarc Bonnici 	uint16_t target_id = FFA_RUN_EP_ID(x1);
1503aad20c85SMarc Bonnici 	uint16_t vcpu_id = FFA_RUN_VCPU_ID(x1);
1504aad20c85SMarc Bonnici 	unsigned int idx;
1505aad20c85SMarc Bonnici 	unsigned int *rt_state;
1506aad20c85SMarc Bonnici 	unsigned int *rt_model;
1507aad20c85SMarc Bonnici 
1508aad20c85SMarc Bonnici 	/* Can only be called from the normal world. */
1509aad20c85SMarc Bonnici 	if (secure_origin) {
1510aad20c85SMarc Bonnici 		ERROR("FFA_RUN can only be called from NWd.\n");
1511aad20c85SMarc Bonnici 		return spmc_ffa_error_return(handle,
1512aad20c85SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
1513aad20c85SMarc Bonnici 	}
1514aad20c85SMarc Bonnici 
1515aad20c85SMarc Bonnici 	/* Cannot run a Normal world partition. */
1516aad20c85SMarc Bonnici 	if (ffa_is_normal_world_id(target_id)) {
1517aad20c85SMarc Bonnici 		ERROR("Cannot run a NWd partition (0x%x).\n", target_id);
1518aad20c85SMarc Bonnici 		return spmc_ffa_error_return(handle,
1519aad20c85SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
1520aad20c85SMarc Bonnici 	}
1521aad20c85SMarc Bonnici 
1522aad20c85SMarc Bonnici 	/* Check that the target SP exists. */
1523aad20c85SMarc Bonnici 	sp = spmc_get_sp_ctx(target_id);
1524aad20c85SMarc Bonnici 	if (sp == NULL) {
1525bbf28dc3SAndrei Homescu 		ERROR("Unknown partition ID (0x%x).\n", target_id);
1526aad20c85SMarc Bonnici 		return spmc_ffa_error_return(handle,
1527aad20c85SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
1528aad20c85SMarc Bonnici 	}
1529aad20c85SMarc Bonnici 
1530aad20c85SMarc Bonnici 	idx = get_ec_index(sp);
15315ed8e255SNishant Sharma 
1532aad20c85SMarc Bonnici 	if (idx != vcpu_id) {
1533aad20c85SMarc Bonnici 		ERROR("Cannot run vcpu %d != %d.\n", idx, vcpu_id);
1534aad20c85SMarc Bonnici 		return spmc_ffa_error_return(handle,
1535aad20c85SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
1536aad20c85SMarc Bonnici 	}
15375ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
15385ed8e255SNishant Sharma 		spin_lock(&sp->rt_state_lock);
15395ed8e255SNishant Sharma 	}
1540aad20c85SMarc Bonnici 	rt_state = &((sp->ec[idx]).rt_state);
1541aad20c85SMarc Bonnici 	rt_model = &((sp->ec[idx]).rt_model);
1542aad20c85SMarc Bonnici 	if (*rt_state == RT_STATE_RUNNING) {
15435ed8e255SNishant Sharma 		if (sp->runtime_el == S_EL0) {
15445ed8e255SNishant Sharma 			spin_unlock(&sp->rt_state_lock);
15455ed8e255SNishant Sharma 		}
1546aad20c85SMarc Bonnici 		ERROR("Partition (0x%x) is already running.\n", target_id);
1547aad20c85SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
1548aad20c85SMarc Bonnici 	}
1549aad20c85SMarc Bonnici 
1550aad20c85SMarc Bonnici 	/*
1551aad20c85SMarc Bonnici 	 * Sanity check that if the execution context was not waiting then it
1552aad20c85SMarc Bonnici 	 * was either in the direct request or the run partition runtime model.
1553aad20c85SMarc Bonnici 	 */
1554aad20c85SMarc Bonnici 	if (*rt_state == RT_STATE_PREEMPTED || *rt_state == RT_STATE_BLOCKED) {
1555aad20c85SMarc Bonnici 		assert(*rt_model == RT_MODEL_RUN ||
1556aad20c85SMarc Bonnici 		       *rt_model == RT_MODEL_DIR_REQ);
1557aad20c85SMarc Bonnici 	}
1558aad20c85SMarc Bonnici 
1559aad20c85SMarc Bonnici 	/*
1560aad20c85SMarc Bonnici 	 * If the context was waiting then update the partition runtime model.
1561aad20c85SMarc Bonnici 	 */
1562aad20c85SMarc Bonnici 	if (*rt_state == RT_STATE_WAITING) {
1563aad20c85SMarc Bonnici 		*rt_model = RT_MODEL_RUN;
1564aad20c85SMarc Bonnici 	}
1565aad20c85SMarc Bonnici 
1566aad20c85SMarc Bonnici 	/*
1567aad20c85SMarc Bonnici 	 * Forward the request to the correct SP vCPU after updating
1568aad20c85SMarc Bonnici 	 * its state.
1569aad20c85SMarc Bonnici 	 */
1570aad20c85SMarc Bonnici 	*rt_state = RT_STATE_RUNNING;
1571aad20c85SMarc Bonnici 
15725ed8e255SNishant Sharma 	if (sp->runtime_el == S_EL0) {
15735ed8e255SNishant Sharma 		spin_unlock(&sp->rt_state_lock);
15745ed8e255SNishant Sharma 	}
15755ed8e255SNishant Sharma 
1576aad20c85SMarc Bonnici 	return spmc_smc_return(smc_fid, secure_origin, x1, 0, 0, 0,
1577bb9fc8c0SJay Monkman 			       handle, cookie, flags, target_id, sp->ffa_version);
1578aad20c85SMarc Bonnici }
1579aad20c85SMarc Bonnici 
rx_release_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)1580f0c25a08SMarc Bonnici static uint64_t rx_release_handler(uint32_t smc_fid,
1581f0c25a08SMarc Bonnici 				   bool secure_origin,
1582f0c25a08SMarc Bonnici 				   uint64_t x1,
1583f0c25a08SMarc Bonnici 				   uint64_t x2,
1584f0c25a08SMarc Bonnici 				   uint64_t x3,
1585f0c25a08SMarc Bonnici 				   uint64_t x4,
1586f0c25a08SMarc Bonnici 				   void *cookie,
1587f0c25a08SMarc Bonnici 				   void *handle,
1588f0c25a08SMarc Bonnici 				   uint64_t flags)
1589f0c25a08SMarc Bonnici {
1590f0c25a08SMarc Bonnici 	struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
1591f0c25a08SMarc Bonnici 
1592f0c25a08SMarc Bonnici 	spin_lock(&mbox->lock);
1593f0c25a08SMarc Bonnici 
1594f0c25a08SMarc Bonnici 	if (mbox->state != MAILBOX_STATE_FULL) {
1595f0c25a08SMarc Bonnici 		spin_unlock(&mbox->lock);
1596f0c25a08SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
1597f0c25a08SMarc Bonnici 	}
1598f0c25a08SMarc Bonnici 
1599f0c25a08SMarc Bonnici 	mbox->state = MAILBOX_STATE_EMPTY;
1600f0c25a08SMarc Bonnici 	spin_unlock(&mbox->lock);
1601f0c25a08SMarc Bonnici 
1602f0c25a08SMarc Bonnici 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
1603f0c25a08SMarc Bonnici }
1604f0c25a08SMarc Bonnici 
spmc_ffa_console_log(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)1605638a6f8eSShruti Gupta static uint64_t spmc_ffa_console_log(uint32_t smc_fid,
1606638a6f8eSShruti Gupta 				     bool secure_origin,
1607638a6f8eSShruti Gupta 				     uint64_t x1,
1608638a6f8eSShruti Gupta 				     uint64_t x2,
1609638a6f8eSShruti Gupta 				     uint64_t x3,
1610638a6f8eSShruti Gupta 				     uint64_t x4,
1611638a6f8eSShruti Gupta 				     void *cookie,
1612638a6f8eSShruti Gupta 				     void *handle,
1613638a6f8eSShruti Gupta 				     uint64_t flags)
1614638a6f8eSShruti Gupta {
161583129bcdSKarl Meakin 	/* Maximum number of characters is 48: 6 registers of 8 bytes each. */
161683129bcdSKarl Meakin 	char chars[48] = {0};
1617638a6f8eSShruti Gupta 	size_t chars_max;
1618638a6f8eSShruti Gupta 	size_t chars_count = x1;
1619638a6f8eSShruti Gupta 
1620638a6f8eSShruti Gupta 	/* Does not support request from Nwd. */
1621638a6f8eSShruti Gupta 	if (!secure_origin) {
1622638a6f8eSShruti Gupta 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
1623638a6f8eSShruti Gupta 	}
1624638a6f8eSShruti Gupta 
1625638a6f8eSShruti Gupta 	assert(smc_fid == FFA_CONSOLE_LOG_SMC32 || smc_fid == FFA_CONSOLE_LOG_SMC64);
1626638a6f8eSShruti Gupta 	if (smc_fid == FFA_CONSOLE_LOG_SMC32) {
162783129bcdSKarl Meakin 		uint32_t *registers = (uint32_t *)chars;
162883129bcdSKarl Meakin 		registers[0] = (uint32_t)x2;
162983129bcdSKarl Meakin 		registers[1] = (uint32_t)x3;
163083129bcdSKarl Meakin 		registers[2] = (uint32_t)x4;
163183129bcdSKarl Meakin 		registers[3] = (uint32_t)SMC_GET_GP(handle, CTX_GPREG_X5);
163283129bcdSKarl Meakin 		registers[4] = (uint32_t)SMC_GET_GP(handle, CTX_GPREG_X6);
163383129bcdSKarl Meakin 		registers[5] = (uint32_t)SMC_GET_GP(handle, CTX_GPREG_X7);
163483129bcdSKarl Meakin 		chars_max = 6 * sizeof(uint32_t);
1635638a6f8eSShruti Gupta 	} else {
163683129bcdSKarl Meakin 		uint64_t *registers = (uint64_t *)chars;
163783129bcdSKarl Meakin 		registers[0] = x2;
163883129bcdSKarl Meakin 		registers[1] = x3;
163983129bcdSKarl Meakin 		registers[2] = x4;
164083129bcdSKarl Meakin 		registers[3] = SMC_GET_GP(handle, CTX_GPREG_X5);
164183129bcdSKarl Meakin 		registers[4] = SMC_GET_GP(handle, CTX_GPREG_X6);
164283129bcdSKarl Meakin 		registers[5] = SMC_GET_GP(handle, CTX_GPREG_X7);
164383129bcdSKarl Meakin 		chars_max = 6 * sizeof(uint64_t);
1644638a6f8eSShruti Gupta 	}
1645638a6f8eSShruti Gupta 
1646638a6f8eSShruti Gupta 	if ((chars_count == 0) || (chars_count > chars_max)) {
1647638a6f8eSShruti Gupta 		return spmc_ffa_error_return(handle, FFA_ERROR_INVALID_PARAMETER);
1648638a6f8eSShruti Gupta 	}
1649638a6f8eSShruti Gupta 
1650638a6f8eSShruti Gupta 	for (size_t i = 0; (i < chars_count) && (chars[i] != '\0'); i++) {
1651638a6f8eSShruti Gupta 		putchar(chars[i]);
1652638a6f8eSShruti Gupta 	}
1653638a6f8eSShruti Gupta 
1654638a6f8eSShruti Gupta 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
1655638a6f8eSShruti Gupta }
1656638a6f8eSShruti Gupta 
165759bd2ad8SMarc Bonnici /*
165859bd2ad8SMarc Bonnici  * Perform initial validation on the provided secondary entry point.
165959bd2ad8SMarc Bonnici  * For now ensure it does not lie within the BL31 Image or the SP's
166059bd2ad8SMarc Bonnici  * RX/TX buffers as these are mapped within EL3.
166159bd2ad8SMarc Bonnici  * TODO: perform validation for additional invalid memory regions.
166259bd2ad8SMarc Bonnici  */
validate_secondary_ep(uintptr_t ep,struct secure_partition_desc * sp)166359bd2ad8SMarc Bonnici static int validate_secondary_ep(uintptr_t ep, struct secure_partition_desc *sp)
166459bd2ad8SMarc Bonnici {
166559bd2ad8SMarc Bonnici 	struct mailbox *mb;
166659bd2ad8SMarc Bonnici 	uintptr_t buffer_size;
166759bd2ad8SMarc Bonnici 	uintptr_t sp_rx_buffer;
166859bd2ad8SMarc Bonnici 	uintptr_t sp_tx_buffer;
166959bd2ad8SMarc Bonnici 	uintptr_t sp_rx_buffer_limit;
167059bd2ad8SMarc Bonnici 	uintptr_t sp_tx_buffer_limit;
167159bd2ad8SMarc Bonnici 
167259bd2ad8SMarc Bonnici 	mb = &sp->mailbox;
167359bd2ad8SMarc Bonnici 	buffer_size = (uintptr_t) (mb->rxtx_page_count * FFA_PAGE_SIZE);
167459bd2ad8SMarc Bonnici 	sp_rx_buffer = (uintptr_t) mb->rx_buffer;
167559bd2ad8SMarc Bonnici 	sp_tx_buffer = (uintptr_t) mb->tx_buffer;
167659bd2ad8SMarc Bonnici 	sp_rx_buffer_limit = sp_rx_buffer + buffer_size;
167759bd2ad8SMarc Bonnici 	sp_tx_buffer_limit = sp_tx_buffer + buffer_size;
167859bd2ad8SMarc Bonnici 
167959bd2ad8SMarc Bonnici 	/*
168059bd2ad8SMarc Bonnici 	 * Check if the entry point lies within BL31, or the
168159bd2ad8SMarc Bonnici 	 * SP's RX or TX buffer.
168259bd2ad8SMarc Bonnici 	 */
168359bd2ad8SMarc Bonnici 	if ((ep >= BL31_BASE && ep < BL31_LIMIT) ||
168459bd2ad8SMarc Bonnici 	    (ep >= sp_rx_buffer && ep < sp_rx_buffer_limit) ||
168559bd2ad8SMarc Bonnici 	    (ep >= sp_tx_buffer && ep < sp_tx_buffer_limit)) {
168659bd2ad8SMarc Bonnici 		return -EINVAL;
168759bd2ad8SMarc Bonnici 	}
168859bd2ad8SMarc Bonnici 	return 0;
168959bd2ad8SMarc Bonnici }
169059bd2ad8SMarc Bonnici 
169159bd2ad8SMarc Bonnici /*******************************************************************************
169259bd2ad8SMarc Bonnici  * This function handles the FFA_SECONDARY_EP_REGISTER SMC to allow an SP to
169359bd2ad8SMarc Bonnici  *  register an entry point for initialization during a secondary cold boot.
169459bd2ad8SMarc Bonnici  ******************************************************************************/
ffa_sec_ep_register_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)169559bd2ad8SMarc Bonnici static uint64_t ffa_sec_ep_register_handler(uint32_t smc_fid,
169659bd2ad8SMarc Bonnici 					    bool secure_origin,
169759bd2ad8SMarc Bonnici 					    uint64_t x1,
169859bd2ad8SMarc Bonnici 					    uint64_t x2,
169959bd2ad8SMarc Bonnici 					    uint64_t x3,
170059bd2ad8SMarc Bonnici 					    uint64_t x4,
170159bd2ad8SMarc Bonnici 					    void *cookie,
170259bd2ad8SMarc Bonnici 					    void *handle,
170359bd2ad8SMarc Bonnici 					    uint64_t flags)
170459bd2ad8SMarc Bonnici {
170559bd2ad8SMarc Bonnici 	struct secure_partition_desc *sp;
170659bd2ad8SMarc Bonnici 	struct sp_exec_ctx *sp_ctx;
170759bd2ad8SMarc Bonnici 
170859bd2ad8SMarc Bonnici 	/* This request cannot originate from the Normal world. */
170959bd2ad8SMarc Bonnici 	if (!secure_origin) {
171059bd2ad8SMarc Bonnici 		WARN("%s: Can only be called from SWd.\n", __func__);
171159bd2ad8SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
171259bd2ad8SMarc Bonnici 	}
171359bd2ad8SMarc Bonnici 
171459bd2ad8SMarc Bonnici 	/* Get the context of the current SP. */
171559bd2ad8SMarc Bonnici 	sp = spmc_get_current_sp_ctx();
171659bd2ad8SMarc Bonnici 	if (sp == NULL) {
171759bd2ad8SMarc Bonnici 		WARN("%s: Cannot find SP context.\n", __func__);
171859bd2ad8SMarc Bonnici 		return spmc_ffa_error_return(handle,
171959bd2ad8SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
172059bd2ad8SMarc Bonnici 	}
172159bd2ad8SMarc Bonnici 
172259bd2ad8SMarc Bonnici 	/* Only an S-EL1 SP should be invoking this ABI. */
172359bd2ad8SMarc Bonnici 	if (sp->runtime_el != S_EL1) {
172459bd2ad8SMarc Bonnici 		WARN("%s: Can only be called for a S-EL1 SP.\n", __func__);
172559bd2ad8SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
172659bd2ad8SMarc Bonnici 	}
172759bd2ad8SMarc Bonnici 
172859bd2ad8SMarc Bonnici 	/* Ensure the SP is in its initialization state. */
172959bd2ad8SMarc Bonnici 	sp_ctx = spmc_get_sp_ec(sp);
173059bd2ad8SMarc Bonnici 	if (sp_ctx->rt_model != RT_MODEL_INIT) {
173159bd2ad8SMarc Bonnici 		WARN("%s: Can only be called during SP initialization.\n",
173259bd2ad8SMarc Bonnici 		     __func__);
173359bd2ad8SMarc Bonnici 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
173459bd2ad8SMarc Bonnici 	}
173559bd2ad8SMarc Bonnici 
173659bd2ad8SMarc Bonnici 	/* Perform initial validation of the secondary entry point. */
173759bd2ad8SMarc Bonnici 	if (validate_secondary_ep(x1, sp)) {
173859bd2ad8SMarc Bonnici 		WARN("%s: Invalid entry point provided (0x%lx).\n",
173959bd2ad8SMarc Bonnici 		     __func__, x1);
174059bd2ad8SMarc Bonnici 		return spmc_ffa_error_return(handle,
174159bd2ad8SMarc Bonnici 					     FFA_ERROR_INVALID_PARAMETER);
174259bd2ad8SMarc Bonnici 	}
174359bd2ad8SMarc Bonnici 
174459bd2ad8SMarc Bonnici 	/*
174559bd2ad8SMarc Bonnici 	 * Update the secondary entrypoint in SP context.
174659bd2ad8SMarc Bonnici 	 * We don't need a lock here as during partition initialization there
174759bd2ad8SMarc Bonnici 	 * will only be a single core online.
174859bd2ad8SMarc Bonnici 	 */
174959bd2ad8SMarc Bonnici 	sp->secondary_ep = x1;
175059bd2ad8SMarc Bonnici 	VERBOSE("%s: 0x%lx\n", __func__, sp->secondary_ep);
175159bd2ad8SMarc Bonnici 
175259bd2ad8SMarc Bonnici 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
175359bd2ad8SMarc Bonnici }
175459bd2ad8SMarc Bonnici 
1755c2b14343SMarc Bonnici /*******************************************************************************
17561f6b2b26SNishant Sharma  * Permissions are encoded using a different format in the FFA_MEM_PERM_* ABIs
17571f6b2b26SNishant Sharma  * than in the Trusted Firmware, where the mmap_attr_t enum type is used. This
17581f6b2b26SNishant Sharma  * function converts a permission value from the FF-A format to the mmap_attr_t
17591f6b2b26SNishant Sharma  * format by setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and
17601f6b2b26SNishant Sharma  * MT_EXECUTE/MT_EXECUTE_NEVER. The other fields are left as 0 because they are
17611f6b2b26SNishant Sharma  * ignored by the function xlat_change_mem_attributes_ctx().
17621f6b2b26SNishant Sharma  ******************************************************************************/
ffa_perm_to_mmap_perm(unsigned int perms)17631f6b2b26SNishant Sharma static unsigned int ffa_perm_to_mmap_perm(unsigned int perms)
17641f6b2b26SNishant Sharma {
17651f6b2b26SNishant Sharma 	unsigned int tf_attr = 0U;
17661f6b2b26SNishant Sharma 	unsigned int access;
17671f6b2b26SNishant Sharma 
17681f6b2b26SNishant Sharma 	/* Deal with data access permissions first. */
17691f6b2b26SNishant Sharma 	access = (perms & FFA_MEM_PERM_DATA_MASK) >> FFA_MEM_PERM_DATA_SHIFT;
17701f6b2b26SNishant Sharma 
17711f6b2b26SNishant Sharma 	switch (access) {
17721f6b2b26SNishant Sharma 	case FFA_MEM_PERM_DATA_RW:
17731f6b2b26SNishant Sharma 		/* Return 0 if the execute is set with RW. */
17741f6b2b26SNishant Sharma 		if ((perms & FFA_MEM_PERM_INST_NON_EXEC) != 0) {
17751f6b2b26SNishant Sharma 			tf_attr |= MT_RW | MT_USER | MT_EXECUTE_NEVER;
17761f6b2b26SNishant Sharma 		}
17771f6b2b26SNishant Sharma 		break;
17781f6b2b26SNishant Sharma 
17791f6b2b26SNishant Sharma 	case FFA_MEM_PERM_DATA_RO:
17801f6b2b26SNishant Sharma 		tf_attr |= MT_RO | MT_USER;
17811f6b2b26SNishant Sharma 		/* Deal with the instruction access permissions next. */
17821f6b2b26SNishant Sharma 		if ((perms & FFA_MEM_PERM_INST_NON_EXEC) == 0) {
17831f6b2b26SNishant Sharma 			tf_attr |= MT_EXECUTE;
17841f6b2b26SNishant Sharma 		} else {
17851f6b2b26SNishant Sharma 			tf_attr |= MT_EXECUTE_NEVER;
17861f6b2b26SNishant Sharma 		}
17871f6b2b26SNishant Sharma 		break;
17881f6b2b26SNishant Sharma 
17891f6b2b26SNishant Sharma 	case FFA_MEM_PERM_DATA_NA:
17901f6b2b26SNishant Sharma 	default:
17911f6b2b26SNishant Sharma 		return tf_attr;
17921f6b2b26SNishant Sharma 	}
17931f6b2b26SNishant Sharma 
17941f6b2b26SNishant Sharma 	return tf_attr;
17951f6b2b26SNishant Sharma }
17961f6b2b26SNishant Sharma 
17971f6b2b26SNishant Sharma /*******************************************************************************
17981f6b2b26SNishant Sharma  * Handler to set the permissions of a set of contiguous pages of a S-EL0 SP
17991f6b2b26SNishant Sharma  ******************************************************************************/
ffa_mem_perm_set_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)18001f6b2b26SNishant Sharma static uint64_t ffa_mem_perm_set_handler(uint32_t smc_fid,
18011f6b2b26SNishant Sharma 					 bool secure_origin,
18021f6b2b26SNishant Sharma 					 uint64_t x1,
18031f6b2b26SNishant Sharma 					 uint64_t x2,
18041f6b2b26SNishant Sharma 					 uint64_t x3,
18051f6b2b26SNishant Sharma 					 uint64_t x4,
18061f6b2b26SNishant Sharma 					 void *cookie,
18071f6b2b26SNishant Sharma 					 void *handle,
18081f6b2b26SNishant Sharma 					 uint64_t flags)
18091f6b2b26SNishant Sharma {
18101f6b2b26SNishant Sharma 	struct secure_partition_desc *sp;
18111f6b2b26SNishant Sharma 	unsigned int idx;
18121f6b2b26SNishant Sharma 	uintptr_t base_va = (uintptr_t) x1;
18131f6b2b26SNishant Sharma 	size_t size = (size_t)(x2 * PAGE_SIZE);
18141f6b2b26SNishant Sharma 	uint32_t tf_attr;
18151f6b2b26SNishant Sharma 	int ret;
18161f6b2b26SNishant Sharma 
18171f6b2b26SNishant Sharma 	/* This request cannot originate from the Normal world. */
18181f6b2b26SNishant Sharma 	if (!secure_origin) {
18191f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
18201f6b2b26SNishant Sharma 	}
18211f6b2b26SNishant Sharma 
18221f6b2b26SNishant Sharma 	if (size == 0) {
18231f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
18241f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
18251f6b2b26SNishant Sharma 	}
18261f6b2b26SNishant Sharma 
18271f6b2b26SNishant Sharma 	/* Get the context of the current SP. */
18281f6b2b26SNishant Sharma 	sp = spmc_get_current_sp_ctx();
18291f6b2b26SNishant Sharma 	if (sp == NULL) {
18301f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
18311f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
18321f6b2b26SNishant Sharma 	}
18331f6b2b26SNishant Sharma 
18341f6b2b26SNishant Sharma 	/* A S-EL1 SP has no business invoking this ABI. */
18351f6b2b26SNishant Sharma 	if (sp->runtime_el == S_EL1) {
18361f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
18371f6b2b26SNishant Sharma 	}
18381f6b2b26SNishant Sharma 
18391f6b2b26SNishant Sharma 	if ((x3 & ~((uint64_t)FFA_MEM_PERM_MASK)) != 0) {
18401f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
18411f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
18421f6b2b26SNishant Sharma 	}
18431f6b2b26SNishant Sharma 
18441f6b2b26SNishant Sharma 	/* Get the execution context of the calling SP. */
18451f6b2b26SNishant Sharma 	idx = get_ec_index(sp);
18461f6b2b26SNishant Sharma 
18471f6b2b26SNishant Sharma 	/*
18481f6b2b26SNishant Sharma 	 * Ensure that the S-EL0 SP is initialising itself. We do not need to
18491f6b2b26SNishant Sharma 	 * synchronise this operation through a spinlock since a S-EL0 SP is UP
18501f6b2b26SNishant Sharma 	 * and can only be initialising on this cpu.
18511f6b2b26SNishant Sharma 	 */
18521f6b2b26SNishant Sharma 	if (sp->ec[idx].rt_model != RT_MODEL_INIT) {
18531f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
18541f6b2b26SNishant Sharma 	}
18551f6b2b26SNishant Sharma 
18561f6b2b26SNishant Sharma 	VERBOSE("Setting memory permissions:\n");
18571f6b2b26SNishant Sharma 	VERBOSE("  Start address  : 0x%lx\n", base_va);
18581f6b2b26SNishant Sharma 	VERBOSE("  Number of pages: %lu (%zu bytes)\n", x2, size);
18591f6b2b26SNishant Sharma 	VERBOSE("  Attributes     : 0x%x\n", (uint32_t)x3);
18601f6b2b26SNishant Sharma 
18611f6b2b26SNishant Sharma 	/* Convert inbound permissions to TF-A permission attributes */
18621f6b2b26SNishant Sharma 	tf_attr = ffa_perm_to_mmap_perm((unsigned int)x3);
18631f6b2b26SNishant Sharma 	if (tf_attr == 0U) {
18641f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
18651f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
18661f6b2b26SNishant Sharma 	}
18671f6b2b26SNishant Sharma 
18681f6b2b26SNishant Sharma 	/* Request the change in permissions */
18691f6b2b26SNishant Sharma 	ret = xlat_change_mem_attributes_ctx(sp->xlat_ctx_handle,
18701f6b2b26SNishant Sharma 					     base_va, size, tf_attr);
18711f6b2b26SNishant Sharma 	if (ret != 0) {
18721f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
18731f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
18741f6b2b26SNishant Sharma 	}
18751f6b2b26SNishant Sharma 
18761f6b2b26SNishant Sharma 	SMC_RET1(handle, FFA_SUCCESS_SMC32);
18771f6b2b26SNishant Sharma }
18781f6b2b26SNishant Sharma 
18791f6b2b26SNishant Sharma /*******************************************************************************
18801f6b2b26SNishant Sharma  * Permissions are encoded using a different format in the FFA_MEM_PERM_* ABIs
18811f6b2b26SNishant Sharma  * than in the Trusted Firmware, where the mmap_attr_t enum type is used. This
18821f6b2b26SNishant Sharma  * function converts a permission value from the mmap_attr_t format to the FF-A
18831f6b2b26SNishant Sharma  * format.
18841f6b2b26SNishant Sharma  ******************************************************************************/
mmap_perm_to_ffa_perm(unsigned int attr)18851f6b2b26SNishant Sharma static unsigned int mmap_perm_to_ffa_perm(unsigned int attr)
18861f6b2b26SNishant Sharma {
18871f6b2b26SNishant Sharma 	unsigned int perms = 0U;
18881f6b2b26SNishant Sharma 	unsigned int data_access;
18891f6b2b26SNishant Sharma 
18901f6b2b26SNishant Sharma 	if ((attr & MT_USER) == 0) {
18911f6b2b26SNishant Sharma 		/* No access from EL0. */
18921f6b2b26SNishant Sharma 		data_access = FFA_MEM_PERM_DATA_NA;
18931f6b2b26SNishant Sharma 	} else {
18941f6b2b26SNishant Sharma 		if ((attr & MT_RW) != 0) {
18951f6b2b26SNishant Sharma 			data_access = FFA_MEM_PERM_DATA_RW;
18961f6b2b26SNishant Sharma 		} else {
18971f6b2b26SNishant Sharma 			data_access = FFA_MEM_PERM_DATA_RO;
18981f6b2b26SNishant Sharma 		}
18991f6b2b26SNishant Sharma 	}
19001f6b2b26SNishant Sharma 
19011f6b2b26SNishant Sharma 	perms |= (data_access & FFA_MEM_PERM_DATA_MASK)
19021f6b2b26SNishant Sharma 		<< FFA_MEM_PERM_DATA_SHIFT;
19031f6b2b26SNishant Sharma 
19041f6b2b26SNishant Sharma 	if ((attr & MT_EXECUTE_NEVER) != 0U) {
19051f6b2b26SNishant Sharma 		perms |= FFA_MEM_PERM_INST_NON_EXEC;
19061f6b2b26SNishant Sharma 	}
19071f6b2b26SNishant Sharma 
19081f6b2b26SNishant Sharma 	return perms;
19091f6b2b26SNishant Sharma }
19101f6b2b26SNishant Sharma 
19111f6b2b26SNishant Sharma /*******************************************************************************
19121f6b2b26SNishant Sharma  * Handler to get the permissions of a set of contiguous pages of a S-EL0 SP
19131f6b2b26SNishant Sharma  ******************************************************************************/
ffa_mem_perm_get_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)19141f6b2b26SNishant Sharma static uint64_t ffa_mem_perm_get_handler(uint32_t smc_fid,
19151f6b2b26SNishant Sharma 					 bool secure_origin,
19161f6b2b26SNishant Sharma 					 uint64_t x1,
19171f6b2b26SNishant Sharma 					 uint64_t x2,
19181f6b2b26SNishant Sharma 					 uint64_t x3,
19191f6b2b26SNishant Sharma 					 uint64_t x4,
19201f6b2b26SNishant Sharma 					 void *cookie,
19211f6b2b26SNishant Sharma 					 void *handle,
19221f6b2b26SNishant Sharma 					 uint64_t flags)
19231f6b2b26SNishant Sharma {
19241f6b2b26SNishant Sharma 	struct secure_partition_desc *sp;
19251f6b2b26SNishant Sharma 	unsigned int idx;
19261f6b2b26SNishant Sharma 	uintptr_t base_va = (uintptr_t)x1;
19279bfe78c2SLevi Yun 	uint64_t max_page_count = x2 + 1;
19289bfe78c2SLevi Yun 	uint64_t page_count = 0;
19299bfe78c2SLevi Yun 	uint32_t base_page_attr = 0;
19309bfe78c2SLevi Yun 	uint32_t page_attr = 0;
19319bfe78c2SLevi Yun 	unsigned int table_level;
19321f6b2b26SNishant Sharma 	int ret;
19331f6b2b26SNishant Sharma 
19341f6b2b26SNishant Sharma 	/* This request cannot originate from the Normal world. */
19351f6b2b26SNishant Sharma 	if (!secure_origin) {
19361f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
19371f6b2b26SNishant Sharma 	}
19381f6b2b26SNishant Sharma 
19391f6b2b26SNishant Sharma 	/* Get the context of the current SP. */
19401f6b2b26SNishant Sharma 	sp = spmc_get_current_sp_ctx();
19411f6b2b26SNishant Sharma 	if (sp == NULL) {
19421f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
19431f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
19441f6b2b26SNishant Sharma 	}
19451f6b2b26SNishant Sharma 
19461f6b2b26SNishant Sharma 	/* A S-EL1 SP has no business invoking this ABI. */
19471f6b2b26SNishant Sharma 	if (sp->runtime_el == S_EL1) {
19481f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
19491f6b2b26SNishant Sharma 	}
19501f6b2b26SNishant Sharma 
19511f6b2b26SNishant Sharma 	/* Get the execution context of the calling SP. */
19521f6b2b26SNishant Sharma 	idx = get_ec_index(sp);
19531f6b2b26SNishant Sharma 
19541f6b2b26SNishant Sharma 	/*
19551f6b2b26SNishant Sharma 	 * Ensure that the S-EL0 SP is initialising itself. We do not need to
19561f6b2b26SNishant Sharma 	 * synchronise this operation through a spinlock since a S-EL0 SP is UP
19571f6b2b26SNishant Sharma 	 * and can only be initialising on this cpu.
19581f6b2b26SNishant Sharma 	 */
19591f6b2b26SNishant Sharma 	if (sp->ec[idx].rt_model != RT_MODEL_INIT) {
19601f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
19611f6b2b26SNishant Sharma 	}
19621f6b2b26SNishant Sharma 
19639bfe78c2SLevi Yun 	base_va &= ~(PAGE_SIZE_MASK);
19649bfe78c2SLevi Yun 
19651f6b2b26SNishant Sharma 	/* Request the permissions */
19669bfe78c2SLevi Yun 	ret = xlat_get_mem_attributes_ctx(sp->xlat_ctx_handle, base_va,
19679bfe78c2SLevi Yun 			&base_page_attr, &table_level);
19681f6b2b26SNishant Sharma 	if (ret != 0) {
19691f6b2b26SNishant Sharma 		return spmc_ffa_error_return(handle,
19701f6b2b26SNishant Sharma 					     FFA_ERROR_INVALID_PARAMETER);
19711f6b2b26SNishant Sharma 	}
19721f6b2b26SNishant Sharma 
19739bfe78c2SLevi Yun 	/*
19749bfe78c2SLevi Yun 	 * Caculate how many pages in this block entry from base_va including
19759bfe78c2SLevi Yun 	 * its page.
19769bfe78c2SLevi Yun 	 */
19779bfe78c2SLevi Yun 	page_count = ((XLAT_BLOCK_SIZE(table_level) -
19789bfe78c2SLevi Yun 			(base_va & XLAT_BLOCK_MASK(table_level))) >> PAGE_SIZE_SHIFT);
19799bfe78c2SLevi Yun 	base_va += XLAT_BLOCK_SIZE(table_level);
19801f6b2b26SNishant Sharma 
19819bfe78c2SLevi Yun 	while ((page_count < max_page_count) && (base_va != 0x00)) {
19829bfe78c2SLevi Yun 		ret = xlat_get_mem_attributes_ctx(sp->xlat_ctx_handle, base_va,
19839bfe78c2SLevi Yun 				&page_attr, &table_level);
19849bfe78c2SLevi Yun 		if (ret != 0) {
19859bfe78c2SLevi Yun 			return spmc_ffa_error_return(handle,
19869bfe78c2SLevi Yun 						     FFA_ERROR_INVALID_PARAMETER);
19879bfe78c2SLevi Yun 		}
19889bfe78c2SLevi Yun 
19899bfe78c2SLevi Yun 		if (page_attr != base_page_attr) {
19909bfe78c2SLevi Yun 			break;
19919bfe78c2SLevi Yun 		}
19929bfe78c2SLevi Yun 
19939bfe78c2SLevi Yun 		base_va += XLAT_BLOCK_SIZE(table_level);
19949bfe78c2SLevi Yun 		page_count += (XLAT_BLOCK_SIZE(table_level) >> PAGE_SIZE_SHIFT);
19959bfe78c2SLevi Yun 	}
19969bfe78c2SLevi Yun 
19979bfe78c2SLevi Yun 	if (page_count > max_page_count) {
19989bfe78c2SLevi Yun 		page_count = max_page_count;
19999bfe78c2SLevi Yun 	}
20009bfe78c2SLevi Yun 
20019bfe78c2SLevi Yun 	/* Convert TF-A permission to FF-A permissions attributes. */
20029bfe78c2SLevi Yun 	x2 = mmap_perm_to_ffa_perm(base_page_attr);
20039bfe78c2SLevi Yun 
20049bfe78c2SLevi Yun 	/* x3 should be page count - 1 */
20059bfe78c2SLevi Yun 	SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, x2, --page_count);
20061f6b2b26SNishant Sharma }
20071f6b2b26SNishant Sharma 
20081f6b2b26SNishant Sharma /*******************************************************************************
20095096aeb2SMarc Bonnici  * This function will parse the Secure Partition Manifest. From manifest, it
20105096aeb2SMarc Bonnici  * will fetch details for preparing Secure partition image context and secure
20115096aeb2SMarc Bonnici  * partition image boot arguments if any.
20125096aeb2SMarc Bonnici  ******************************************************************************/
sp_manifest_parse(void * sp_manifest,int offset,struct secure_partition_desc * sp,entry_point_info_t * ep_info,int32_t * boot_info_reg)20135096aeb2SMarc Bonnici static int sp_manifest_parse(void *sp_manifest, int offset,
20145096aeb2SMarc Bonnici 			     struct secure_partition_desc *sp,
20152e219215SAchin Gupta 			     entry_point_info_t *ep_info,
20162e219215SAchin Gupta 			     int32_t *boot_info_reg)
20175096aeb2SMarc Bonnici {
20185096aeb2SMarc Bonnici 	int32_t ret, node;
20195096aeb2SMarc Bonnici 	uint32_t config_32;
2020*0322d7afSJay Monkman 	int uuid_size;
2021*0322d7afSJay Monkman 	const fdt32_t *prop;
20225096aeb2SMarc Bonnici 
20235096aeb2SMarc Bonnici 	/*
20245096aeb2SMarc Bonnici 	 * Look for the mandatory fields that are expected to be present in
20255096aeb2SMarc Bonnici 	 * the SP manifests.
20265096aeb2SMarc Bonnici 	 */
20275096aeb2SMarc Bonnici 	node = fdt_path_offset(sp_manifest, "/");
20285096aeb2SMarc Bonnici 	if (node < 0) {
20295096aeb2SMarc Bonnici 		ERROR("Did not find root node.\n");
20305096aeb2SMarc Bonnici 		return node;
20315096aeb2SMarc Bonnici 	}
20325096aeb2SMarc Bonnici 
2033*0322d7afSJay Monkman 	prop = fdt_getprop(sp_manifest, node, "uuid", &uuid_size);
2034*0322d7afSJay Monkman 	if (prop == NULL) {
2035*0322d7afSJay Monkman 		ERROR("Couldn't find property uuid in manifest\n");
2036*0322d7afSJay Monkman 		return -FDT_ERR_NOTFOUND;
2037*0322d7afSJay Monkman 	}
2038*0322d7afSJay Monkman 
2039*0322d7afSJay Monkman 	sp->num_uuids = (uint32_t)uuid_size / sizeof(struct ffa_uuid);
2040*0322d7afSJay Monkman 	if (sp->num_uuids > ARRAY_SIZE(sp->uuid_array)) {
2041*0322d7afSJay Monkman 		ERROR("Too many UUIDs (%d) in manifest, maximum is %zd\n",
2042*0322d7afSJay Monkman 		      sp->num_uuids, ARRAY_SIZE(sp->uuid_array));
2043*0322d7afSJay Monkman 		return -FDT_ERR_BADVALUE;
2044*0322d7afSJay Monkman 	}
2045*0322d7afSJay Monkman 
2046857f5790SMarc Bonnici 	ret = fdt_read_uint32_array(sp_manifest, node, "uuid",
2047*0322d7afSJay Monkman 				    (uuid_size / sizeof(uint32_t)),
2048*0322d7afSJay Monkman 				    sp->uuid_array[0].uuid);
2049857f5790SMarc Bonnici 	if (ret != 0) {
2050857f5790SMarc Bonnici 		ERROR("Missing Secure Partition UUID.\n");
2051857f5790SMarc Bonnici 		return ret;
2052857f5790SMarc Bonnici 	}
2053857f5790SMarc Bonnici 
2054*0322d7afSJay Monkman 	for (uint32_t i = 0; i < sp->num_uuids; i++) {
2055*0322d7afSJay Monkman 		for (uint32_t j = 0; j < i; j++) {
2056*0322d7afSJay Monkman 			if (memcmp(&sp->uuid_array[i], &sp->uuid_array[j],
2057*0322d7afSJay Monkman 				   sizeof(struct ffa_uuid)) == 0) {
2058*0322d7afSJay Monkman 				ERROR("Duplicate UUIDs in manifest: 0x%x 0x%x 0x%x 0x%x\n",
2059*0322d7afSJay Monkman 				      sp->uuid_array[i].uuid[0],
2060*0322d7afSJay Monkman 				      sp->uuid_array[i].uuid[1],
2061*0322d7afSJay Monkman 				      sp->uuid_array[i].uuid[2],
2062*0322d7afSJay Monkman 				      sp->uuid_array[i].uuid[3]);
2063*0322d7afSJay Monkman 				return -FDT_ERR_BADVALUE;
2064*0322d7afSJay Monkman 			}
2065*0322d7afSJay Monkman 		}
2066*0322d7afSJay Monkman 	}
2067*0322d7afSJay Monkman 
20685096aeb2SMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32);
20695096aeb2SMarc Bonnici 	if (ret != 0) {
20705096aeb2SMarc Bonnici 		ERROR("Missing SP Exception Level information.\n");
20715096aeb2SMarc Bonnici 		return ret;
20725096aeb2SMarc Bonnici 	}
20735096aeb2SMarc Bonnici 
20745096aeb2SMarc Bonnici 	sp->runtime_el = config_32;
20755096aeb2SMarc Bonnici 
20765096aeb2SMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node, "ffa-version", &config_32);
20775096aeb2SMarc Bonnici 	if (ret != 0) {
20785096aeb2SMarc Bonnici 		ERROR("Missing Secure Partition FF-A Version.\n");
20795096aeb2SMarc Bonnici 		return ret;
20805096aeb2SMarc Bonnici 	}
20815096aeb2SMarc Bonnici 
20825096aeb2SMarc Bonnici 	sp->ffa_version = config_32;
20835096aeb2SMarc Bonnici 
20845096aeb2SMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node, "execution-state", &config_32);
20855096aeb2SMarc Bonnici 	if (ret != 0) {
20865096aeb2SMarc Bonnici 		ERROR("Missing Secure Partition Execution State.\n");
20875096aeb2SMarc Bonnici 		return ret;
20885096aeb2SMarc Bonnici 	}
20895096aeb2SMarc Bonnici 
20905096aeb2SMarc Bonnici 	sp->execution_state = config_32;
20915096aeb2SMarc Bonnici 
20925b0219ddSMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node,
20933de378ffSMarc Bonnici 			      "messaging-method", &config_32);
20943de378ffSMarc Bonnici 	if (ret != 0) {
20953de378ffSMarc Bonnici 		ERROR("Missing Secure Partition messaging method.\n");
20963de378ffSMarc Bonnici 		return ret;
20973de378ffSMarc Bonnici 	}
20983de378ffSMarc Bonnici 
20993de378ffSMarc Bonnici 	/* Validate this entry, we currently only support direct messaging. */
21003de378ffSMarc Bonnici 	if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV |
210109a580b7SLevi Yun 			  FFA_PARTITION_DIRECT_REQ_SEND |
210209a580b7SLevi Yun 			  FFA_PARTITION_DIRECT_REQ2_RECV |
210309a580b7SLevi Yun 			  FFA_PARTITION_DIRECT_REQ2_SEND)) != 0U) {
21043de378ffSMarc Bonnici 		WARN("Invalid Secure Partition messaging method (0x%x)\n",
21053de378ffSMarc Bonnici 		     config_32);
21063de378ffSMarc Bonnici 		return -EINVAL;
21073de378ffSMarc Bonnici 	}
21083de378ffSMarc Bonnici 
21093de378ffSMarc Bonnici 	sp->properties = config_32;
21103de378ffSMarc Bonnici 
21113de378ffSMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node,
21125b0219ddSMarc Bonnici 			      "execution-ctx-count", &config_32);
21135b0219ddSMarc Bonnici 
21145b0219ddSMarc Bonnici 	if (ret != 0) {
21155b0219ddSMarc Bonnici 		ERROR("Missing SP Execution Context Count.\n");
21165b0219ddSMarc Bonnici 		return ret;
21175b0219ddSMarc Bonnici 	}
21185b0219ddSMarc Bonnici 
21195b0219ddSMarc Bonnici 	/*
21205b0219ddSMarc Bonnici 	 * Ensure this field is set correctly in the manifest however
21215b0219ddSMarc Bonnici 	 * since this is currently a hardcoded value for S-EL1 partitions
21225b0219ddSMarc Bonnici 	 * we don't need to save it here, just validate.
21235b0219ddSMarc Bonnici 	 */
212448db2b01SNishant Sharma 	if ((sp->runtime_el == S_EL1) && (config_32 != PLATFORM_CORE_COUNT)) {
21255b0219ddSMarc Bonnici 		ERROR("SP Execution Context Count (%u) must be %u.\n",
21265b0219ddSMarc Bonnici 			config_32, PLATFORM_CORE_COUNT);
21275b0219ddSMarc Bonnici 		return -EINVAL;
21285b0219ddSMarc Bonnici 	}
21295b0219ddSMarc Bonnici 
21305096aeb2SMarc Bonnici 	/*
21315096aeb2SMarc Bonnici 	 * Look for the optional fields that are expected to be present in
21325096aeb2SMarc Bonnici 	 * an SP manifest.
21335096aeb2SMarc Bonnici 	 */
21345096aeb2SMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node, "id", &config_32);
21355096aeb2SMarc Bonnici 	if (ret != 0) {
21365096aeb2SMarc Bonnici 		WARN("Missing Secure Partition ID.\n");
21375096aeb2SMarc Bonnici 	} else {
21385096aeb2SMarc Bonnici 		if (!is_ffa_secure_id_valid(config_32)) {
21395096aeb2SMarc Bonnici 			ERROR("Invalid Secure Partition ID (0x%x).\n",
21405096aeb2SMarc Bonnici 			      config_32);
21415096aeb2SMarc Bonnici 			return -EINVAL;
21425096aeb2SMarc Bonnici 		}
21435096aeb2SMarc Bonnici 		sp->sp_id = config_32;
21445096aeb2SMarc Bonnici 	}
21455096aeb2SMarc Bonnici 
214659bd2ad8SMarc Bonnici 	ret = fdt_read_uint32(sp_manifest, node,
214759bd2ad8SMarc Bonnici 			      "power-management-messages", &config_32);
214859bd2ad8SMarc Bonnici 	if (ret != 0) {
214959bd2ad8SMarc Bonnici 		WARN("Missing Power Management Messages entry.\n");
215059bd2ad8SMarc Bonnici 	} else {
215159173793SNishant Sharma 		if ((sp->runtime_el == S_EL0) && (config_32 != 0)) {
215259173793SNishant Sharma 			ERROR("Power messages not supported for S-EL0 SP\n");
215359173793SNishant Sharma 			return -EINVAL;
215459173793SNishant Sharma 		}
215559173793SNishant Sharma 
215659bd2ad8SMarc Bonnici 		/*
215759bd2ad8SMarc Bonnici 		 * Ensure only the currently supported power messages have
215859bd2ad8SMarc Bonnici 		 * been requested.
215959bd2ad8SMarc Bonnici 		 */
216059bd2ad8SMarc Bonnici 		if (config_32 & ~(FFA_PM_MSG_SUB_CPU_OFF |
216159bd2ad8SMarc Bonnici 				  FFA_PM_MSG_SUB_CPU_SUSPEND |
216259bd2ad8SMarc Bonnici 				  FFA_PM_MSG_SUB_CPU_SUSPEND_RESUME)) {
216359bd2ad8SMarc Bonnici 			ERROR("Requested unsupported PM messages (%x)\n",
216459bd2ad8SMarc Bonnici 			      config_32);
216559bd2ad8SMarc Bonnici 			return -EINVAL;
216659bd2ad8SMarc Bonnici 		}
216759bd2ad8SMarc Bonnici 		sp->pwr_mgmt_msgs = config_32;
216859bd2ad8SMarc Bonnici 	}
216959bd2ad8SMarc Bonnici 
21702e219215SAchin Gupta 	ret = fdt_read_uint32(sp_manifest, node,
21712e219215SAchin Gupta 			      "gp-register-num", &config_32);
21722e219215SAchin Gupta 	if (ret != 0) {
21732e219215SAchin Gupta 		WARN("Missing boot information register.\n");
21742e219215SAchin Gupta 	} else {
21752e219215SAchin Gupta 		/* Check if a register number between 0-3 is specified. */
21762e219215SAchin Gupta 		if (config_32 < 4) {
21772e219215SAchin Gupta 			*boot_info_reg = config_32;
21782e219215SAchin Gupta 		} else {
21792e219215SAchin Gupta 			WARN("Incorrect boot information register (%u).\n",
21802e219215SAchin Gupta 			     config_32);
21812e219215SAchin Gupta 		}
21822e219215SAchin Gupta 	}
21832e219215SAchin Gupta 
2184ce299f95SAndrei Homescu 	ret = fdt_read_uint32(sp_manifest, node,
2185ce299f95SAndrei Homescu 			      "vm-availability-messages", &config_32);
2186ce299f95SAndrei Homescu 	if (ret != 0) {
2187ce299f95SAndrei Homescu 		WARN("Missing VM availability messaging.\n");
2188ce299f95SAndrei Homescu 	} else if ((sp->properties & FFA_PARTITION_DIRECT_REQ_RECV) == 0) {
2189ce299f95SAndrei Homescu 		ERROR("VM availability messaging requested without "
2190ce299f95SAndrei Homescu 		      "direct message receive support.\n");
2191ce299f95SAndrei Homescu 		return -EINVAL;
2192ce299f95SAndrei Homescu 	} else {
2193ce299f95SAndrei Homescu 		/* Validate this entry. */
2194ce299f95SAndrei Homescu 		if ((config_32 & ~(FFA_VM_AVAILABILITY_CREATED |
2195ce299f95SAndrei Homescu 				  FFA_VM_AVAILABILITY_DESTROYED)) != 0U) {
2196ce299f95SAndrei Homescu 			WARN("Invalid VM availability messaging (0x%x)\n",
2197ce299f95SAndrei Homescu 			     config_32);
2198ce299f95SAndrei Homescu 			return -EINVAL;
2199ce299f95SAndrei Homescu 		}
2200ce299f95SAndrei Homescu 
2201ce299f95SAndrei Homescu 		if ((config_32 & FFA_VM_AVAILABILITY_CREATED) != 0U) {
2202ce299f95SAndrei Homescu 			sp->properties |= FFA_PARTITION_VM_CREATED;
2203ce299f95SAndrei Homescu 		}
2204ce299f95SAndrei Homescu 		if ((config_32 & FFA_VM_AVAILABILITY_DESTROYED) != 0U) {
2205ce299f95SAndrei Homescu 			sp->properties |= FFA_PARTITION_VM_DESTROYED;
2206ce299f95SAndrei Homescu 		}
2207ce299f95SAndrei Homescu 	}
2208ce299f95SAndrei Homescu 
22095096aeb2SMarc Bonnici 	return 0;
22105096aeb2SMarc Bonnici }
22115096aeb2SMarc Bonnici 
22125096aeb2SMarc Bonnici /*******************************************************************************
22135096aeb2SMarc Bonnici  * This function gets the Secure Partition Manifest base and maps the manifest
22145096aeb2SMarc Bonnici  * region.
22155096aeb2SMarc Bonnici  * Currently only one Secure Partition manifest is considered which is used to
22165096aeb2SMarc Bonnici  * prepare the context for the single Secure Partition.
22175096aeb2SMarc Bonnici  ******************************************************************************/
find_and_prepare_sp_context(void)22185096aeb2SMarc Bonnici static int find_and_prepare_sp_context(void)
22195096aeb2SMarc Bonnici {
22205096aeb2SMarc Bonnici 	void *sp_manifest;
22215096aeb2SMarc Bonnici 	uintptr_t manifest_base;
2222aae2370cSYeoreum Yun 	uintptr_t manifest_base_align __maybe_unused;
22235096aeb2SMarc Bonnici 	entry_point_info_t *next_image_ep_info;
22242e219215SAchin Gupta 	int32_t ret, boot_info_reg = -1;
22255096aeb2SMarc Bonnici 	struct secure_partition_desc *sp;
2226aae2370cSYeoreum Yun 	struct transfer_list_header *tl __maybe_unused;
2227aae2370cSYeoreum Yun 	struct transfer_list_entry *te __maybe_unused;
22285096aeb2SMarc Bonnici 
22295096aeb2SMarc Bonnici 	next_image_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
22305096aeb2SMarc Bonnici 	if (next_image_ep_info == NULL) {
22315096aeb2SMarc Bonnici 		WARN("No Secure Partition image provided by BL2.\n");
22325096aeb2SMarc Bonnici 		return -ENOENT;
22335096aeb2SMarc Bonnici 	}
22345096aeb2SMarc Bonnici 
2235aae2370cSYeoreum Yun 
2236aae2370cSYeoreum Yun #if TRANSFER_LIST && !RESET_TO_BL31
2237aae2370cSYeoreum Yun 	tl = (struct transfer_list_header *)next_image_ep_info->args.arg3;
2238aae2370cSYeoreum Yun 	te = transfer_list_find(tl, TL_TAG_DT_FFA_MANIFEST);
2239aae2370cSYeoreum Yun 	if (te == NULL) {
2240aae2370cSYeoreum Yun 		WARN("Secure Partition manifest absent.\n");
2241aae2370cSYeoreum Yun 		return -ENOENT;
2242aae2370cSYeoreum Yun 	}
2243aae2370cSYeoreum Yun 
2244aae2370cSYeoreum Yun 	sp_manifest = (void *)transfer_list_entry_data(te);
2245aae2370cSYeoreum Yun 	manifest_base = (uintptr_t)sp_manifest;
2246aae2370cSYeoreum Yun #else
22475096aeb2SMarc Bonnici 	sp_manifest = (void *)next_image_ep_info->args.arg0;
22485096aeb2SMarc Bonnici 	if (sp_manifest == NULL) {
22495096aeb2SMarc Bonnici 		WARN("Secure Partition manifest absent.\n");
22505096aeb2SMarc Bonnici 		return -ENOENT;
22515096aeb2SMarc Bonnici 	}
22525096aeb2SMarc Bonnici 
22535096aeb2SMarc Bonnici 	manifest_base = (uintptr_t)sp_manifest;
22545096aeb2SMarc Bonnici 	manifest_base_align = page_align(manifest_base, DOWN);
22555096aeb2SMarc Bonnici 
22565096aeb2SMarc Bonnici 	/*
22575096aeb2SMarc Bonnici 	 * Map the secure partition manifest region in the EL3 translation
22585096aeb2SMarc Bonnici 	 * regime.
22595096aeb2SMarc Bonnici 	 * Map an area equal to (2 * PAGE_SIZE) for now. During manifest base
22605096aeb2SMarc Bonnici 	 * alignment the region of 1 PAGE_SIZE from manifest align base may
22615096aeb2SMarc Bonnici 	 * not completely accommodate the secure partition manifest region.
22625096aeb2SMarc Bonnici 	 */
22635096aeb2SMarc Bonnici 	ret = mmap_add_dynamic_region((unsigned long long)manifest_base_align,
22645096aeb2SMarc Bonnici 				      manifest_base_align,
22655096aeb2SMarc Bonnici 				      PAGE_SIZE * 2,
22665096aeb2SMarc Bonnici 				      MT_RO_DATA);
22675096aeb2SMarc Bonnici 	if (ret != 0) {
22685096aeb2SMarc Bonnici 		ERROR("Error while mapping SP manifest (%d).\n", ret);
22695096aeb2SMarc Bonnici 		return ret;
22705096aeb2SMarc Bonnici 	}
2271aae2370cSYeoreum Yun #endif
22725096aeb2SMarc Bonnici 
22735096aeb2SMarc Bonnici 	ret = fdt_node_offset_by_compatible(sp_manifest, -1,
22745096aeb2SMarc Bonnici 					    "arm,ffa-manifest-1.0");
22755096aeb2SMarc Bonnici 	if (ret < 0) {
22765096aeb2SMarc Bonnici 		ERROR("Error happened in SP manifest reading.\n");
22775096aeb2SMarc Bonnici 		return -EINVAL;
22785096aeb2SMarc Bonnici 	}
22795096aeb2SMarc Bonnici 
22805096aeb2SMarc Bonnici 	/*
22815096aeb2SMarc Bonnici 	 * Store the size of the manifest so that it can be used later to pass
22825096aeb2SMarc Bonnici 	 * the manifest as boot information later.
22835096aeb2SMarc Bonnici 	 */
22845096aeb2SMarc Bonnici 	next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest);
228548db2b01SNishant Sharma 	INFO("Manifest adr = %lx , size = %lu bytes\n", manifest_base,
228648db2b01SNishant Sharma 	     next_image_ep_info->args.arg1);
22875096aeb2SMarc Bonnici 
22885096aeb2SMarc Bonnici 	/*
22895096aeb2SMarc Bonnici 	 * Select an SP descriptor for initialising the partition's execution
22905096aeb2SMarc Bonnici 	 * context on the primary CPU.
22915096aeb2SMarc Bonnici 	 */
22925096aeb2SMarc Bonnici 	sp = spmc_get_current_sp_ctx();
22935096aeb2SMarc Bonnici 
229448db2b01SNishant Sharma #if SPMC_AT_EL3_SEL0_SP
229548db2b01SNishant Sharma 	/* Assign translation tables context. */
229648db2b01SNishant Sharma 	sp_desc->xlat_ctx_handle = spm_get_sp_xlat_context();
229748db2b01SNishant Sharma 
229848db2b01SNishant Sharma #endif /* SPMC_AT_EL3_SEL0_SP */
22995096aeb2SMarc Bonnici 	/* Initialize entry point information for the SP */
23005096aeb2SMarc Bonnici 	SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1,
23015096aeb2SMarc Bonnici 		       SECURE | EP_ST_ENABLE);
23025096aeb2SMarc Bonnici 
23035096aeb2SMarc Bonnici 	/* Parse the SP manifest. */
23042e219215SAchin Gupta 	ret = sp_manifest_parse(sp_manifest, ret, sp, next_image_ep_info,
23052e219215SAchin Gupta 				&boot_info_reg);
23065096aeb2SMarc Bonnici 	if (ret != 0) {
23075096aeb2SMarc Bonnici 		ERROR("Error in Secure Partition manifest parsing.\n");
23085096aeb2SMarc Bonnici 		return ret;
23095096aeb2SMarc Bonnici 	}
23105096aeb2SMarc Bonnici 
23115096aeb2SMarc Bonnici 	/* Perform any common initialisation. */
23122e219215SAchin Gupta 	spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg);
23135096aeb2SMarc Bonnici 
23145096aeb2SMarc Bonnici 	/* Perform any initialisation specific to S-EL1 SPs. */
231548db2b01SNishant Sharma 	if (sp->runtime_el == S_EL1) {
23165096aeb2SMarc Bonnici 		spmc_el1_sp_setup(sp, next_image_ep_info);
23174053a647SLevi Yun 		spmc_sp_common_ep_commit(sp, next_image_ep_info);
231848db2b01SNishant Sharma 	}
231948db2b01SNishant Sharma #if SPMC_AT_EL3_SEL0_SP
23204053a647SLevi Yun 	/* Perform any initialisation specific to S-EL0 SPs. */
23214053a647SLevi Yun 	else if (sp->runtime_el == S_EL0) {
232248db2b01SNishant Sharma 		/* Setup spsr in endpoint info for common context management routine. */
232348db2b01SNishant Sharma 		spmc_el0_sp_spsr_setup(next_image_ep_info);
23245096aeb2SMarc Bonnici 
23255096aeb2SMarc Bonnici 		spmc_sp_common_ep_commit(sp, next_image_ep_info);
23265096aeb2SMarc Bonnici 
232748db2b01SNishant Sharma 		/*
232848db2b01SNishant Sharma 		 * Perform any initialisation specific to S-EL0 not set by common
232948db2b01SNishant Sharma 		 * context management routine.
233048db2b01SNishant Sharma 		 */
233183c3da77SNishant Sharma 		spmc_el0_sp_setup(sp, boot_info_reg, sp_manifest);
233248db2b01SNishant Sharma 	}
233348db2b01SNishant Sharma #endif /* SPMC_AT_EL3_SEL0_SP */
23344053a647SLevi Yun 	else {
23354053a647SLevi Yun 		ERROR("Unexpected runtime EL: %u\n", sp->runtime_el);
23364053a647SLevi Yun 		return -EINVAL;
23374053a647SLevi Yun 	}
23384053a647SLevi Yun 
23395096aeb2SMarc Bonnici 	return 0;
23405096aeb2SMarc Bonnici }
23415096aeb2SMarc Bonnici 
23425096aeb2SMarc Bonnici /*******************************************************************************
23435096aeb2SMarc Bonnici  * This function takes an SP context pointer and performs a synchronous entry
23445096aeb2SMarc Bonnici  * into it.
23455096aeb2SMarc Bonnici  ******************************************************************************/
logical_sp_init(void)23467affa25cSMarc Bonnici static int32_t logical_sp_init(void)
23477affa25cSMarc Bonnici {
23487affa25cSMarc Bonnici 	int32_t rc = 0;
23497affa25cSMarc Bonnici 	struct el3_lp_desc *el3_lp_descs;
23507affa25cSMarc Bonnici 
23517affa25cSMarc Bonnici 	/* Perform initial validation of the Logical Partitions. */
23527affa25cSMarc Bonnici 	rc = el3_sp_desc_validate();
23537affa25cSMarc Bonnici 	if (rc != 0) {
23547affa25cSMarc Bonnici 		ERROR("Logical Partition validation failed!\n");
23557affa25cSMarc Bonnici 		return rc;
23567affa25cSMarc Bonnici 	}
23577affa25cSMarc Bonnici 
23587affa25cSMarc Bonnici 	el3_lp_descs = get_el3_lp_array();
23597affa25cSMarc Bonnici 
23607affa25cSMarc Bonnici 	INFO("Logical Secure Partition init start.\n");
23617affa25cSMarc Bonnici 	for (unsigned int i = 0U; i < EL3_LP_DESCS_COUNT; i++) {
23627affa25cSMarc Bonnici 		rc = el3_lp_descs[i].init();
23637affa25cSMarc Bonnici 		if (rc != 0) {
23647affa25cSMarc Bonnici 			ERROR("Logical SP (0x%x) Failed to Initialize\n",
23657affa25cSMarc Bonnici 			      el3_lp_descs[i].sp_id);
23667affa25cSMarc Bonnici 			return rc;
23677affa25cSMarc Bonnici 		}
23687affa25cSMarc Bonnici 		VERBOSE("Logical SP (0x%x) Initialized\n",
23697affa25cSMarc Bonnici 			      el3_lp_descs[i].sp_id);
23707affa25cSMarc Bonnici 	}
23717affa25cSMarc Bonnici 
23727affa25cSMarc Bonnici 	INFO("Logical Secure Partition init completed.\n");
23737affa25cSMarc Bonnici 
23747affa25cSMarc Bonnici 	return rc;
23757affa25cSMarc Bonnici }
23767affa25cSMarc Bonnici 
spmc_sp_synchronous_entry(struct sp_exec_ctx * ec)23775096aeb2SMarc Bonnici uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec)
23785096aeb2SMarc Bonnici {
23795096aeb2SMarc Bonnici 	uint64_t rc;
23805096aeb2SMarc Bonnici 
23815096aeb2SMarc Bonnici 	assert(ec != NULL);
23825096aeb2SMarc Bonnici 
23835096aeb2SMarc Bonnici 	/* Assign the context of the SP to this CPU */
23845096aeb2SMarc Bonnici 	cm_set_context(&(ec->cpu_ctx), SECURE);
23855096aeb2SMarc Bonnici 
23865096aeb2SMarc Bonnici 	/* Restore the context assigned above */
23875096aeb2SMarc Bonnici 	cm_el1_sysregs_context_restore(SECURE);
23885096aeb2SMarc Bonnici 	cm_set_next_eret_context(SECURE);
23895096aeb2SMarc Bonnici 
23905096aeb2SMarc Bonnici 	/* Invalidate TLBs at EL1. */
23915096aeb2SMarc Bonnici 	tlbivmalle1();
23925096aeb2SMarc Bonnici 	dsbish();
23935096aeb2SMarc Bonnici 
23945096aeb2SMarc Bonnici 	/* Enter Secure Partition */
23955096aeb2SMarc Bonnici 	rc = spm_secure_partition_enter(&ec->c_rt_ctx);
23965096aeb2SMarc Bonnici 
23975096aeb2SMarc Bonnici 	/* Save secure state */
23985096aeb2SMarc Bonnici 	cm_el1_sysregs_context_save(SECURE);
23995096aeb2SMarc Bonnici 
24005096aeb2SMarc Bonnici 	return rc;
24015096aeb2SMarc Bonnici }
24025096aeb2SMarc Bonnici 
24035096aeb2SMarc Bonnici /*******************************************************************************
24045096aeb2SMarc Bonnici  * SPMC Helper Functions.
24055096aeb2SMarc Bonnici  ******************************************************************************/
sp_init(void)24065096aeb2SMarc Bonnici static int32_t sp_init(void)
24075096aeb2SMarc Bonnici {
24085096aeb2SMarc Bonnici 	uint64_t rc;
24095096aeb2SMarc Bonnici 	struct secure_partition_desc *sp;
24105096aeb2SMarc Bonnici 	struct sp_exec_ctx *ec;
24115096aeb2SMarc Bonnici 
24125096aeb2SMarc Bonnici 	sp = spmc_get_current_sp_ctx();
24135096aeb2SMarc Bonnici 	ec = spmc_get_sp_ec(sp);
24145096aeb2SMarc Bonnici 	ec->rt_model = RT_MODEL_INIT;
24155096aeb2SMarc Bonnici 	ec->rt_state = RT_STATE_RUNNING;
24165096aeb2SMarc Bonnici 
24175096aeb2SMarc Bonnici 	INFO("Secure Partition (0x%x) init start.\n", sp->sp_id);
24185096aeb2SMarc Bonnici 
24195096aeb2SMarc Bonnici 	rc = spmc_sp_synchronous_entry(ec);
24205096aeb2SMarc Bonnici 	if (rc != 0) {
24215096aeb2SMarc Bonnici 		/* Indicate SP init was not successful. */
24225096aeb2SMarc Bonnici 		ERROR("SP (0x%x) failed to initialize (%lu).\n",
24235096aeb2SMarc Bonnici 		      sp->sp_id, rc);
24245096aeb2SMarc Bonnici 		return 0;
24255096aeb2SMarc Bonnici 	}
24265096aeb2SMarc Bonnici 
24275096aeb2SMarc Bonnici 	ec->rt_state = RT_STATE_WAITING;
24285096aeb2SMarc Bonnici 	INFO("Secure Partition initialized.\n");
24295096aeb2SMarc Bonnici 
24305096aeb2SMarc Bonnici 	return 1;
24315096aeb2SMarc Bonnici }
24325096aeb2SMarc Bonnici 
initalize_sp_descs(void)24335096aeb2SMarc Bonnici static void initalize_sp_descs(void)
24345096aeb2SMarc Bonnici {
24355096aeb2SMarc Bonnici 	struct secure_partition_desc *sp;
24365096aeb2SMarc Bonnici 
24375096aeb2SMarc Bonnici 	for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
24385096aeb2SMarc Bonnici 		sp = &sp_desc[i];
24395096aeb2SMarc Bonnici 		sp->sp_id = INV_SP_ID;
2440e1df6008SMarc Bonnici 		sp->mailbox.rx_buffer = NULL;
2441e1df6008SMarc Bonnici 		sp->mailbox.tx_buffer = NULL;
2442e1df6008SMarc Bonnici 		sp->mailbox.state = MAILBOX_STATE_EMPTY;
24435096aeb2SMarc Bonnici 		sp->secondary_ep = 0;
24445096aeb2SMarc Bonnici 	}
24455096aeb2SMarc Bonnici }
24465096aeb2SMarc Bonnici 
initalize_ns_ep_descs(void)24475096aeb2SMarc Bonnici static void initalize_ns_ep_descs(void)
24485096aeb2SMarc Bonnici {
24495096aeb2SMarc Bonnici 	struct ns_endpoint_desc *ns_ep;
24505096aeb2SMarc Bonnici 
24515096aeb2SMarc Bonnici 	for (unsigned int i = 0U; i < NS_PARTITION_COUNT; i++) {
24525096aeb2SMarc Bonnici 		ns_ep = &ns_ep_desc[i];
24535096aeb2SMarc Bonnici 		/*
24545096aeb2SMarc Bonnici 		 * Clashes with the Hypervisor ID but will not be a
24555096aeb2SMarc Bonnici 		 * problem in practice.
24565096aeb2SMarc Bonnici 		 */
24575096aeb2SMarc Bonnici 		ns_ep->ns_ep_id = 0;
24585096aeb2SMarc Bonnici 		ns_ep->ffa_version = 0;
2459e1df6008SMarc Bonnici 		ns_ep->mailbox.rx_buffer = NULL;
2460e1df6008SMarc Bonnici 		ns_ep->mailbox.tx_buffer = NULL;
2461e1df6008SMarc Bonnici 		ns_ep->mailbox.state = MAILBOX_STATE_EMPTY;
24625096aeb2SMarc Bonnici 	}
24635096aeb2SMarc Bonnici }
24645096aeb2SMarc Bonnici 
24655096aeb2SMarc Bonnici /*******************************************************************************
24666da76075SMarc Bonnici  * Initialize SPMC attributes for the SPMD.
24676da76075SMarc Bonnici  ******************************************************************************/
spmc_populate_attrs(spmc_manifest_attribute_t * spmc_attrs)24686da76075SMarc Bonnici void spmc_populate_attrs(spmc_manifest_attribute_t *spmc_attrs)
24696da76075SMarc Bonnici {
2470dd87b735SJ-Alves 	spmc_attrs->major_version = FFA_VERSION_SPMC_MAJOR;
2471dd87b735SJ-Alves 	spmc_attrs->minor_version = FFA_VERSION_SPMC_MINOR;
24726da76075SMarc Bonnici 	spmc_attrs->exec_state = MODE_RW_64;
24736da76075SMarc Bonnici 	spmc_attrs->spmc_id = FFA_SPMC_ID;
24746da76075SMarc Bonnici }
24756da76075SMarc Bonnici 
24766da76075SMarc Bonnici /*******************************************************************************
24775096aeb2SMarc Bonnici  * Initialize contexts of all Secure Partitions.
24785096aeb2SMarc Bonnici  ******************************************************************************/
spmc_setup(void)24795096aeb2SMarc Bonnici int32_t spmc_setup(void)
24805096aeb2SMarc Bonnici {
24815096aeb2SMarc Bonnici 	int32_t ret;
2482729d7793SAchin Gupta 	uint32_t flags;
24835096aeb2SMarc Bonnici 
24845096aeb2SMarc Bonnici 	/* Initialize endpoint descriptors */
24855096aeb2SMarc Bonnici 	initalize_sp_descs();
24865096aeb2SMarc Bonnici 	initalize_ns_ep_descs();
24875096aeb2SMarc Bonnici 
2488e0b1a6d5SMarc Bonnici 	/*
2489e0b1a6d5SMarc Bonnici 	 * Retrieve the information of the datastore for tracking shared memory
2490e0b1a6d5SMarc Bonnici 	 * requests allocated by platform code and zero the region if available.
2491e0b1a6d5SMarc Bonnici 	 */
2492e0b1a6d5SMarc Bonnici 	ret = plat_spmc_shmem_datastore_get(&spmc_shmem_obj_state.data,
2493e0b1a6d5SMarc Bonnici 					    &spmc_shmem_obj_state.data_size);
2494e0b1a6d5SMarc Bonnici 	if (ret != 0) {
2495e0b1a6d5SMarc Bonnici 		ERROR("Failed to obtain memory descriptor backing store!\n");
2496e0b1a6d5SMarc Bonnici 		return ret;
2497e0b1a6d5SMarc Bonnici 	}
2498e0b1a6d5SMarc Bonnici 	memset(spmc_shmem_obj_state.data, 0, spmc_shmem_obj_state.data_size);
2499e0b1a6d5SMarc Bonnici 
25007affa25cSMarc Bonnici 	/* Setup logical SPs. */
25017affa25cSMarc Bonnici 	ret = logical_sp_init();
25027affa25cSMarc Bonnici 	if (ret != 0) {
25037affa25cSMarc Bonnici 		ERROR("Failed to initialize Logical Partitions.\n");
25047affa25cSMarc Bonnici 		return ret;
25057affa25cSMarc Bonnici 	}
25067affa25cSMarc Bonnici 
25075096aeb2SMarc Bonnici 	/* Perform physical SP setup. */
25085096aeb2SMarc Bonnici 
25095096aeb2SMarc Bonnici 	/* Disable MMU at EL1 (initialized by BL2) */
25105096aeb2SMarc Bonnici 	disable_mmu_icache_el1();
25115096aeb2SMarc Bonnici 
25125096aeb2SMarc Bonnici 	/* Initialize context of the SP */
25135096aeb2SMarc Bonnici 	INFO("Secure Partition context setup start.\n");
25145096aeb2SMarc Bonnici 
25155096aeb2SMarc Bonnici 	ret = find_and_prepare_sp_context();
25165096aeb2SMarc Bonnici 	if (ret != 0) {
25175096aeb2SMarc Bonnici 		ERROR("Error in SP finding and context preparation.\n");
25185096aeb2SMarc Bonnici 		return ret;
25195096aeb2SMarc Bonnici 	}
25205096aeb2SMarc Bonnici 
252159bd2ad8SMarc Bonnici 	/* Register power management hooks with PSCI */
252259bd2ad8SMarc Bonnici 	psci_register_spd_pm_hook(&spmc_pm);
252359bd2ad8SMarc Bonnici 
2524729d7793SAchin Gupta 	/*
2525729d7793SAchin Gupta 	 * Register an interrupt handler for S-EL1 interrupts
2526729d7793SAchin Gupta 	 * when generated during code executing in the
2527729d7793SAchin Gupta 	 * non-secure state.
2528729d7793SAchin Gupta 	 */
2529729d7793SAchin Gupta 	flags = 0;
2530729d7793SAchin Gupta 	set_interrupt_rm_flag(flags, NON_SECURE);
2531729d7793SAchin Gupta 	ret = register_interrupt_type_handler(INTR_TYPE_S_EL1,
2532729d7793SAchin Gupta 					      spmc_sp_interrupt_handler,
2533729d7793SAchin Gupta 					      flags);
2534729d7793SAchin Gupta 	if (ret != 0) {
2535729d7793SAchin Gupta 		ERROR("Failed to register interrupt handler! (%d)\n", ret);
2536729d7793SAchin Gupta 		panic();
2537729d7793SAchin Gupta 	}
2538729d7793SAchin Gupta 
25395096aeb2SMarc Bonnici 	/* Register init function for deferred init.  */
25405096aeb2SMarc Bonnici 	bl31_register_bl32_init(&sp_init);
25415096aeb2SMarc Bonnici 
25425096aeb2SMarc Bonnici 	INFO("Secure Partition setup done.\n");
25435096aeb2SMarc Bonnici 
25445096aeb2SMarc Bonnici 	return 0;
25455096aeb2SMarc Bonnici }
25465096aeb2SMarc Bonnici 
25475096aeb2SMarc Bonnici /*******************************************************************************
25485096aeb2SMarc Bonnici  * Secure Partition Manager SMC handler.
25495096aeb2SMarc Bonnici  ******************************************************************************/
spmc_smc_handler(uint32_t smc_fid,bool secure_origin,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)25505096aeb2SMarc Bonnici uint64_t spmc_smc_handler(uint32_t smc_fid,
25515096aeb2SMarc Bonnici 			  bool secure_origin,
25525096aeb2SMarc Bonnici 			  uint64_t x1,
25535096aeb2SMarc Bonnici 			  uint64_t x2,
25545096aeb2SMarc Bonnici 			  uint64_t x3,
25555096aeb2SMarc Bonnici 			  uint64_t x4,
25565096aeb2SMarc Bonnici 			  void *cookie,
25575096aeb2SMarc Bonnici 			  void *handle,
25585096aeb2SMarc Bonnici 			  uint64_t flags)
25595096aeb2SMarc Bonnici {
25605096aeb2SMarc Bonnici 	switch (smc_fid) {
25615096aeb2SMarc Bonnici 
25620c7707fdSMarc Bonnici 	case FFA_VERSION:
25630c7707fdSMarc Bonnici 		return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3,
25640c7707fdSMarc Bonnici 					   x4, cookie, handle, flags);
25650c7707fdSMarc Bonnici 
256646872e01SMarc Bonnici 	case FFA_SPM_ID_GET:
256746872e01SMarc Bonnici 		return ffa_spm_id_get_handler(smc_fid, secure_origin, x1, x2,
256846872e01SMarc Bonnici 					     x3, x4, cookie, handle, flags);
256946872e01SMarc Bonnici 
2570d5fe9235SMarc Bonnici 	case FFA_ID_GET:
2571d5fe9235SMarc Bonnici 		return ffa_id_get_handler(smc_fid, secure_origin, x1, x2, x3,
2572d5fe9235SMarc Bonnici 					  x4, cookie, handle, flags);
2573d5fe9235SMarc Bonnici 
257455a29638SMarc Bonnici 	case FFA_FEATURES:
257555a29638SMarc Bonnici 		return ffa_features_handler(smc_fid, secure_origin, x1, x2, x3,
257655a29638SMarc Bonnici 					    x4, cookie, handle, flags);
257755a29638SMarc Bonnici 
257859bd2ad8SMarc Bonnici 	case FFA_SECONDARY_EP_REGISTER_SMC64:
257959bd2ad8SMarc Bonnici 		return ffa_sec_ep_register_handler(smc_fid, secure_origin, x1,
258059bd2ad8SMarc Bonnici 						   x2, x3, x4, cookie, handle,
258159bd2ad8SMarc Bonnici 						   flags);
258259bd2ad8SMarc Bonnici 
25839741327dSMarc Bonnici 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
25849741327dSMarc Bonnici 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
258509a580b7SLevi Yun 	case FFA_MSG_SEND_DIRECT_REQ2_SMC64:
25869741327dSMarc Bonnici 		return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
25879741327dSMarc Bonnici 					      x3, x4, cookie, handle, flags);
25889741327dSMarc Bonnici 
25899741327dSMarc Bonnici 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
25909741327dSMarc Bonnici 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
259109a580b7SLevi Yun 	case FFA_MSG_SEND_DIRECT_RESP2_SMC64:
25929741327dSMarc Bonnici 		return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2,
25939741327dSMarc Bonnici 					       x3, x4, cookie, handle, flags);
25949741327dSMarc Bonnici 
25951a752245SMarc Bonnici 	case FFA_RXTX_MAP_SMC32:
25961a752245SMarc Bonnici 	case FFA_RXTX_MAP_SMC64:
25971a752245SMarc Bonnici 		return rxtx_map_handler(smc_fid, secure_origin, x1, x2, x3, x4,
25981a752245SMarc Bonnici 					cookie, handle, flags);
25991a752245SMarc Bonnici 
26001a752245SMarc Bonnici 	case FFA_RXTX_UNMAP:
26011a752245SMarc Bonnici 		return rxtx_unmap_handler(smc_fid, secure_origin, x1, x2, x3,
26021a752245SMarc Bonnici 					  x4, cookie, handle, flags);
26031a752245SMarc Bonnici 
2604f74e2772SMarc Bonnici 	case FFA_PARTITION_INFO_GET:
2605f74e2772SMarc Bonnici 		return partition_info_get_handler(smc_fid, secure_origin, x1,
2606f74e2772SMarc Bonnici 						  x2, x3, x4, cookie, handle,
2607f74e2772SMarc Bonnici 						  flags);
2608f74e2772SMarc Bonnici 
2609f0c25a08SMarc Bonnici 	case FFA_RX_RELEASE:
2610f0c25a08SMarc Bonnici 		return rx_release_handler(smc_fid, secure_origin, x1, x2, x3,
2611f0c25a08SMarc Bonnici 					  x4, cookie, handle, flags);
2612f0c25a08SMarc Bonnici 
2613c4db76f0SMarc Bonnici 	case FFA_MSG_WAIT:
2614c4db76f0SMarc Bonnici 		return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2615c4db76f0SMarc Bonnici 					cookie, handle, flags);
2616c4db76f0SMarc Bonnici 
2617d663fe7aSMarc Bonnici 	case FFA_ERROR:
2618d663fe7aSMarc Bonnici 		return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2619d663fe7aSMarc Bonnici 					cookie, handle, flags);
2620d663fe7aSMarc Bonnici 
2621aad20c85SMarc Bonnici 	case FFA_MSG_RUN:
2622aad20c85SMarc Bonnici 		return ffa_run_handler(smc_fid, secure_origin, x1, x2, x3, x4,
2623aad20c85SMarc Bonnici 				       cookie, handle, flags);
2624e0b1a6d5SMarc Bonnici 
2625e0b1a6d5SMarc Bonnici 	case FFA_MEM_SHARE_SMC32:
2626e0b1a6d5SMarc Bonnici 	case FFA_MEM_SHARE_SMC64:
2627e0b1a6d5SMarc Bonnici 	case FFA_MEM_LEND_SMC32:
2628e0b1a6d5SMarc Bonnici 	case FFA_MEM_LEND_SMC64:
2629e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_send(smc_fid, secure_origin, x1, x2, x3, x4,
2630e0b1a6d5SMarc Bonnici 					 cookie, handle, flags);
2631e0b1a6d5SMarc Bonnici 
2632e0b1a6d5SMarc Bonnici 	case FFA_MEM_FRAG_TX:
2633e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_frag_tx(smc_fid, secure_origin, x1, x2, x3,
2634e0b1a6d5SMarc Bonnici 					    x4, cookie, handle, flags);
2635e0b1a6d5SMarc Bonnici 
2636e0b1a6d5SMarc Bonnici 	case FFA_MEM_FRAG_RX:
2637e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_frag_rx(smc_fid, secure_origin, x1, x2, x3,
2638e0b1a6d5SMarc Bonnici 					    x4, cookie, handle, flags);
2639e0b1a6d5SMarc Bonnici 
2640e0b1a6d5SMarc Bonnici 	case FFA_MEM_RETRIEVE_REQ_SMC32:
2641e0b1a6d5SMarc Bonnici 	case FFA_MEM_RETRIEVE_REQ_SMC64:
2642e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_retrieve_req(smc_fid, secure_origin, x1, x2,
2643e0b1a6d5SMarc Bonnici 						 x3, x4, cookie, handle, flags);
2644e0b1a6d5SMarc Bonnici 
2645e0b1a6d5SMarc Bonnici 	case FFA_MEM_RELINQUISH:
2646e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_relinquish(smc_fid, secure_origin, x1, x2,
2647e0b1a6d5SMarc Bonnici 					       x3, x4, cookie, handle, flags);
2648e0b1a6d5SMarc Bonnici 
2649e0b1a6d5SMarc Bonnici 	case FFA_MEM_RECLAIM:
2650e0b1a6d5SMarc Bonnici 		return spmc_ffa_mem_reclaim(smc_fid, secure_origin, x1, x2, x3,
2651e0b1a6d5SMarc Bonnici 						x4, cookie, handle, flags);
2652638a6f8eSShruti Gupta 	case FFA_CONSOLE_LOG_SMC32:
2653638a6f8eSShruti Gupta 	case FFA_CONSOLE_LOG_SMC64:
2654638a6f8eSShruti Gupta 		return spmc_ffa_console_log(smc_fid, secure_origin, x1, x2, x3,
2655638a6f8eSShruti Gupta 						x4, cookie, handle, flags);
2656e0b1a6d5SMarc Bonnici 
2657ddf72e6aSLevi Yun 	case FFA_MEM_PERM_GET_SMC32:
2658ddf72e6aSLevi Yun 	case FFA_MEM_PERM_GET_SMC64:
26591f6b2b26SNishant Sharma 		return ffa_mem_perm_get_handler(smc_fid, secure_origin, x1, x2,
26601f6b2b26SNishant Sharma 						x3, x4, cookie, handle, flags);
26611f6b2b26SNishant Sharma 
2662ddf72e6aSLevi Yun 	case FFA_MEM_PERM_SET_SMC32:
2663ddf72e6aSLevi Yun 	case FFA_MEM_PERM_SET_SMC64:
26641f6b2b26SNishant Sharma 		return ffa_mem_perm_set_handler(smc_fid, secure_origin, x1, x2,
26651f6b2b26SNishant Sharma 						x3, x4, cookie, handle, flags);
26661f6b2b26SNishant Sharma 
26675096aeb2SMarc Bonnici 	default:
26685096aeb2SMarc Bonnici 		WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
26695096aeb2SMarc Bonnici 		break;
26705096aeb2SMarc Bonnici 	}
26715096aeb2SMarc Bonnici 	return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
26725096aeb2SMarc Bonnici }
2673729d7793SAchin Gupta 
2674729d7793SAchin Gupta /*******************************************************************************
2675729d7793SAchin Gupta  * This function is the handler registered for S-EL1 interrupts by the SPMC. It
2676729d7793SAchin Gupta  * validates the interrupt and upon success arranges entry into the SP for
2677729d7793SAchin Gupta  * handling the interrupt.
2678729d7793SAchin Gupta  ******************************************************************************/
spmc_sp_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)2679729d7793SAchin Gupta static uint64_t spmc_sp_interrupt_handler(uint32_t id,
2680729d7793SAchin Gupta 					  uint32_t flags,
2681729d7793SAchin Gupta 					  void *handle,
2682729d7793SAchin Gupta 					  void *cookie)
2683729d7793SAchin Gupta {
2684729d7793SAchin Gupta 	struct secure_partition_desc *sp = spmc_get_current_sp_ctx();
2685729d7793SAchin Gupta 	struct sp_exec_ctx *ec;
2686729d7793SAchin Gupta 	uint32_t linear_id = plat_my_core_pos();
2687729d7793SAchin Gupta 
2688729d7793SAchin Gupta 	/* Sanity check for a NULL pointer dereference. */
2689729d7793SAchin Gupta 	assert(sp != NULL);
2690729d7793SAchin Gupta 
2691729d7793SAchin Gupta 	/* Check the security state when the exception was generated. */
2692729d7793SAchin Gupta 	assert(get_interrupt_src_ss(flags) == NON_SECURE);
2693729d7793SAchin Gupta 
2694729d7793SAchin Gupta 	/* Panic if not an S-EL1 Partition. */
2695729d7793SAchin Gupta 	if (sp->runtime_el != S_EL1) {
2696729d7793SAchin Gupta 		ERROR("Interrupt received for a non S-EL1 SP on core%u.\n",
2697729d7793SAchin Gupta 		      linear_id);
2698729d7793SAchin Gupta 		panic();
2699729d7793SAchin Gupta 	}
2700729d7793SAchin Gupta 
2701729d7793SAchin Gupta 	/* Obtain a reference to the SP execution context. */
2702729d7793SAchin Gupta 	ec = spmc_get_sp_ec(sp);
2703729d7793SAchin Gupta 
2704729d7793SAchin Gupta 	/* Ensure that the execution context is in waiting state else panic. */
2705729d7793SAchin Gupta 	if (ec->rt_state != RT_STATE_WAITING) {
2706729d7793SAchin Gupta 		ERROR("SP EC on core%u is not waiting (%u), it is (%u).\n",
2707729d7793SAchin Gupta 		      linear_id, RT_STATE_WAITING, ec->rt_state);
2708729d7793SAchin Gupta 		panic();
2709729d7793SAchin Gupta 	}
2710729d7793SAchin Gupta 
2711729d7793SAchin Gupta 	/* Update the runtime model and state of the partition. */
2712729d7793SAchin Gupta 	ec->rt_model = RT_MODEL_INTR;
2713729d7793SAchin Gupta 	ec->rt_state = RT_STATE_RUNNING;
2714729d7793SAchin Gupta 
2715729d7793SAchin Gupta 	VERBOSE("SP (0x%x) interrupt start on core%u.\n", sp->sp_id, linear_id);
2716729d7793SAchin Gupta 
2717729d7793SAchin Gupta 	/*
2718729d7793SAchin Gupta 	 * Forward the interrupt to the S-EL1 SP. The interrupt ID is not
2719729d7793SAchin Gupta 	 * populated as the SP can determine this by itself.
2720c925867eSOlivier Deprez 	 * The flags field is forced to 0 mainly to pass the SVE hint bit
2721c925867eSOlivier Deprez 	 * cleared for consumption by the lower EL.
2722729d7793SAchin Gupta 	 */
2723729d7793SAchin Gupta 	return spmd_smc_switch_state(FFA_INTERRUPT, false,
2724729d7793SAchin Gupta 				     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
2725729d7793SAchin Gupta 				     FFA_PARAM_MBZ, FFA_PARAM_MBZ,
2726bb9fc8c0SJay Monkman 				     handle, 0ULL, sp->ffa_version);
2727729d7793SAchin Gupta }
2728