xref: /rk3399_ARM-atf/services/std_svc/spmd/spmd_logical_sp.c (revision 95f7f6d86a6aadc9d235684fd1aa57ddc4c56ea9)
1890b5088SRaghu Krishnamurthy /*
2890b5088SRaghu Krishnamurthy  * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
3890b5088SRaghu Krishnamurthy  *
4890b5088SRaghu Krishnamurthy  * SPDX-License-Identifier: BSD-3-Clause
5890b5088SRaghu Krishnamurthy  */
6890b5088SRaghu Krishnamurthy 
7890b5088SRaghu Krishnamurthy #include <assert.h>
8890b5088SRaghu Krishnamurthy #include <errno.h>
9890b5088SRaghu Krishnamurthy #include <string.h>
1066bdfd6eSRaghu Krishnamurthy #include "spmd_private.h"
11890b5088SRaghu Krishnamurthy 
12890b5088SRaghu Krishnamurthy #include <common/debug.h>
13*95f7f6d8SRaghu Krishnamurthy #include <common/uuid.h>
1466bdfd6eSRaghu Krishnamurthy #include <lib/el3_runtime/context_mgmt.h>
15890b5088SRaghu Krishnamurthy #include <services/el3_spmd_logical_sp.h>
1666bdfd6eSRaghu Krishnamurthy #include <services/spmc_svc.h>
17*95f7f6d8SRaghu Krishnamurthy #include <smccc_helpers.h>
1866bdfd6eSRaghu Krishnamurthy 
19890b5088SRaghu Krishnamurthy 
20*95f7f6d8SRaghu Krishnamurthy /*
21*95f7f6d8SRaghu Krishnamurthy  * Maximum ffa_partition_info entries that can be returned by an invocation
22*95f7f6d8SRaghu Krishnamurthy  * of FFA_PARTITION_INFO_GET_REGS_64 is size in bytes, of available
23*95f7f6d8SRaghu Krishnamurthy  * registers/args in struct ffa_value divided by size of struct
24*95f7f6d8SRaghu Krishnamurthy  * ffa_partition_info. For this ABI, arg3-arg17 in ffa_value can be used, i.e.
25*95f7f6d8SRaghu Krishnamurthy  * 15 uint64_t fields. For FF-A v1.1, this value should be 5.
26*95f7f6d8SRaghu Krishnamurthy  */
27*95f7f6d8SRaghu Krishnamurthy #define MAX_INFO_REGS_ENTRIES_PER_CALL \
28*95f7f6d8SRaghu Krishnamurthy 	(uint8_t)((15 * sizeof(uint64_t)) / \
29*95f7f6d8SRaghu Krishnamurthy 		  sizeof(struct ffa_partition_info_v1_1))
30*95f7f6d8SRaghu Krishnamurthy CASSERT(MAX_INFO_REGS_ENTRIES_PER_CALL == 5, assert_too_many_info_reg_entries);
31*95f7f6d8SRaghu Krishnamurthy 
32890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP
33890b5088SRaghu Krishnamurthy static bool is_spmd_lp_inited;
34890b5088SRaghu Krishnamurthy static bool is_spmc_inited;
35890b5088SRaghu Krishnamurthy 
36890b5088SRaghu Krishnamurthy /*
37890b5088SRaghu Krishnamurthy  * Helper function to obtain the array storing the EL3
38890b5088SRaghu Krishnamurthy  * SPMD Logical Partition descriptors.
39890b5088SRaghu Krishnamurthy  */
40890b5088SRaghu Krishnamurthy static struct spmd_lp_desc *get_spmd_el3_lp_array(void)
41890b5088SRaghu Krishnamurthy {
42890b5088SRaghu Krishnamurthy 	return (struct spmd_lp_desc *) SPMD_LP_DESCS_START;
43890b5088SRaghu Krishnamurthy }
44890b5088SRaghu Krishnamurthy 
45890b5088SRaghu Krishnamurthy /*******************************************************************************
46890b5088SRaghu Krishnamurthy  * Validate any logical partition descriptors before we initialize.
47890b5088SRaghu Krishnamurthy  * Initialization of said partitions will be taken care of during SPMD boot.
48890b5088SRaghu Krishnamurthy  ******************************************************************************/
49890b5088SRaghu Krishnamurthy static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array)
50890b5088SRaghu Krishnamurthy {
51890b5088SRaghu Krishnamurthy 	/* Check the array bounds are valid. */
52890b5088SRaghu Krishnamurthy 	assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START);
53890b5088SRaghu Krishnamurthy 
5466bdfd6eSRaghu Krishnamurthy 	/*
5566bdfd6eSRaghu Krishnamurthy 	 * No support for SPMD logical partitions when SPMC is at EL3.
5666bdfd6eSRaghu Krishnamurthy 	 */
5766bdfd6eSRaghu Krishnamurthy 	assert(!is_spmc_at_el3());
5866bdfd6eSRaghu Krishnamurthy 
59890b5088SRaghu Krishnamurthy 	/* If no SPMD logical partitions are implemented then simply bail out. */
60890b5088SRaghu Krishnamurthy 	if (SPMD_LP_DESCS_COUNT == 0U) {
61890b5088SRaghu Krishnamurthy 		return -1;
62890b5088SRaghu Krishnamurthy 	}
63890b5088SRaghu Krishnamurthy 
64890b5088SRaghu Krishnamurthy 	for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) {
65890b5088SRaghu Krishnamurthy 		struct spmd_lp_desc *lp_desc = &lp_array[index];
66890b5088SRaghu Krishnamurthy 
67890b5088SRaghu Krishnamurthy 		/* Validate our logical partition descriptors. */
68890b5088SRaghu Krishnamurthy 		if (lp_desc == NULL) {
69890b5088SRaghu Krishnamurthy 			ERROR("Invalid SPMD Logical SP Descriptor\n");
70890b5088SRaghu Krishnamurthy 			return -EINVAL;
71890b5088SRaghu Krishnamurthy 		}
72890b5088SRaghu Krishnamurthy 
73890b5088SRaghu Krishnamurthy 		/*
74890b5088SRaghu Krishnamurthy 		 * Ensure the ID follows the convention to indicate it resides
75890b5088SRaghu Krishnamurthy 		 * in the secure world.
76890b5088SRaghu Krishnamurthy 		 */
77890b5088SRaghu Krishnamurthy 		if (!ffa_is_secure_world_id(lp_desc->sp_id)) {
78890b5088SRaghu Krishnamurthy 			ERROR("Invalid SPMD Logical SP ID (0x%x)\n",
79890b5088SRaghu Krishnamurthy 			      lp_desc->sp_id);
80890b5088SRaghu Krishnamurthy 			return -EINVAL;
81890b5088SRaghu Krishnamurthy 		}
82890b5088SRaghu Krishnamurthy 
83890b5088SRaghu Krishnamurthy 		/* Ensure SPMD logical partition is in valid range. */
84890b5088SRaghu Krishnamurthy 		if (!is_spmd_lp_id(lp_desc->sp_id)) {
85890b5088SRaghu Krishnamurthy 			ERROR("Invalid SPMD Logical Partition ID (0x%x)\n",
86890b5088SRaghu Krishnamurthy 			      lp_desc->sp_id);
87890b5088SRaghu Krishnamurthy 			return -EINVAL;
88890b5088SRaghu Krishnamurthy 		}
89890b5088SRaghu Krishnamurthy 
90890b5088SRaghu Krishnamurthy 		/* Ensure the UUID is not the NULL UUID. */
91890b5088SRaghu Krishnamurthy 		if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 &&
92890b5088SRaghu Krishnamurthy 		    lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) {
93890b5088SRaghu Krishnamurthy 			ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n",
94890b5088SRaghu Krishnamurthy 			      lp_desc->sp_id);
95890b5088SRaghu Krishnamurthy 			return -EINVAL;
96890b5088SRaghu Krishnamurthy 		}
97890b5088SRaghu Krishnamurthy 
98890b5088SRaghu Krishnamurthy 		/* Ensure init function callback is registered. */
99890b5088SRaghu Krishnamurthy 		if (lp_desc->init == NULL) {
100890b5088SRaghu Krishnamurthy 			ERROR("Missing init function for Logical SP(0x%x)\n",
101890b5088SRaghu Krishnamurthy 			      lp_desc->sp_id);
102890b5088SRaghu Krishnamurthy 			return -EINVAL;
103890b5088SRaghu Krishnamurthy 		}
104890b5088SRaghu Krishnamurthy 
105890b5088SRaghu Krishnamurthy 		/* Ensure that SPMD LP only supports sending direct requests. */
106890b5088SRaghu Krishnamurthy 		if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) {
107890b5088SRaghu Krishnamurthy 			ERROR("Invalid SPMD logical partition properties (0x%x)\n",
108890b5088SRaghu Krishnamurthy 			      lp_desc->properties);
109890b5088SRaghu Krishnamurthy 			return -EINVAL;
110890b5088SRaghu Krishnamurthy 		}
111890b5088SRaghu Krishnamurthy 
112890b5088SRaghu Krishnamurthy 		/* Ensure that all partition IDs are unique. */
113890b5088SRaghu Krishnamurthy 		for (uint32_t inner_idx = index + 1;
114890b5088SRaghu Krishnamurthy 		     inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) {
115890b5088SRaghu Krishnamurthy 			if (lp_desc->sp_id == lp_array[inner_idx].sp_id) {
116890b5088SRaghu Krishnamurthy 				ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n",
117890b5088SRaghu Krishnamurthy 				      lp_desc->sp_id);
118890b5088SRaghu Krishnamurthy 				return -EINVAL;
119890b5088SRaghu Krishnamurthy 			}
120890b5088SRaghu Krishnamurthy 		}
121890b5088SRaghu Krishnamurthy 	}
122890b5088SRaghu Krishnamurthy 	return 0;
123890b5088SRaghu Krishnamurthy }
12466bdfd6eSRaghu Krishnamurthy 
12566bdfd6eSRaghu Krishnamurthy static void spmd_encode_ffa_error(struct ffa_value *retval, int32_t error_code)
12666bdfd6eSRaghu Krishnamurthy {
12766bdfd6eSRaghu Krishnamurthy 	retval->func = FFA_ERROR;
12866bdfd6eSRaghu Krishnamurthy 	retval->arg1 = FFA_TARGET_INFO_MBZ;
12966bdfd6eSRaghu Krishnamurthy 	retval->arg2 = (uint32_t)error_code;
13066bdfd6eSRaghu Krishnamurthy 	retval->arg3 = FFA_TARGET_INFO_MBZ;
13166bdfd6eSRaghu Krishnamurthy 	retval->arg4 = FFA_TARGET_INFO_MBZ;
13266bdfd6eSRaghu Krishnamurthy 	retval->arg5 = FFA_TARGET_INFO_MBZ;
13366bdfd6eSRaghu Krishnamurthy 	retval->arg6 = FFA_TARGET_INFO_MBZ;
13466bdfd6eSRaghu Krishnamurthy 	retval->arg7 = FFA_TARGET_INFO_MBZ;
13566bdfd6eSRaghu Krishnamurthy }
13666bdfd6eSRaghu Krishnamurthy 
13766bdfd6eSRaghu Krishnamurthy static void spmd_build_direct_message_req(spmd_spm_core_context_t *ctx,
13866bdfd6eSRaghu Krishnamurthy 					  uint64_t x1, uint64_t x2,
13966bdfd6eSRaghu Krishnamurthy 					  uint64_t x3, uint64_t x4)
14066bdfd6eSRaghu Krishnamurthy {
14166bdfd6eSRaghu Krishnamurthy 	gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
14266bdfd6eSRaghu Krishnamurthy 
14366bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
14466bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X1, x1);
14566bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X2, x2);
14666bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X3, x3);
14766bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X4, x4);
14866bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X5, 0U);
14966bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X6, 0U);
15066bdfd6eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X7, 0U);
15166bdfd6eSRaghu Krishnamurthy }
15266bdfd6eSRaghu Krishnamurthy 
15366bdfd6eSRaghu Krishnamurthy static void spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t *ctx,
15466bdfd6eSRaghu Krishnamurthy 					 struct ffa_value *retval)
15566bdfd6eSRaghu Krishnamurthy {
15666bdfd6eSRaghu Krishnamurthy 	gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
15766bdfd6eSRaghu Krishnamurthy 
15866bdfd6eSRaghu Krishnamurthy 	retval->func = read_ctx_reg(gpregs, CTX_GPREG_X0);
15966bdfd6eSRaghu Krishnamurthy 	retval->arg1 = read_ctx_reg(gpregs, CTX_GPREG_X1);
16066bdfd6eSRaghu Krishnamurthy 	retval->arg2 = read_ctx_reg(gpregs, CTX_GPREG_X2);
16166bdfd6eSRaghu Krishnamurthy 	retval->arg3 = read_ctx_reg(gpregs, CTX_GPREG_X3);
16266bdfd6eSRaghu Krishnamurthy 	retval->arg4 = read_ctx_reg(gpregs, CTX_GPREG_X4);
16366bdfd6eSRaghu Krishnamurthy 	retval->arg5 = read_ctx_reg(gpregs, CTX_GPREG_X5);
16466bdfd6eSRaghu Krishnamurthy 	retval->arg6 = read_ctx_reg(gpregs, CTX_GPREG_X6);
16566bdfd6eSRaghu Krishnamurthy 	retval->arg7 = read_ctx_reg(gpregs, CTX_GPREG_X7);
1660b850e9eSRaghu Krishnamurthy 	retval->arg8 = read_ctx_reg(gpregs, CTX_GPREG_X8);
1670b850e9eSRaghu Krishnamurthy 	retval->arg9 = read_ctx_reg(gpregs, CTX_GPREG_X9);
1680b850e9eSRaghu Krishnamurthy 	retval->arg10 = read_ctx_reg(gpregs, CTX_GPREG_X10);
1690b850e9eSRaghu Krishnamurthy 	retval->arg11 = read_ctx_reg(gpregs, CTX_GPREG_X11);
1700b850e9eSRaghu Krishnamurthy 	retval->arg12 = read_ctx_reg(gpregs, CTX_GPREG_X12);
1710b850e9eSRaghu Krishnamurthy 	retval->arg13 = read_ctx_reg(gpregs, CTX_GPREG_X13);
1720b850e9eSRaghu Krishnamurthy 	retval->arg14 = read_ctx_reg(gpregs, CTX_GPREG_X14);
1730b850e9eSRaghu Krishnamurthy 	retval->arg15 = read_ctx_reg(gpregs, CTX_GPREG_X15);
1740b850e9eSRaghu Krishnamurthy 	retval->arg16 = read_ctx_reg(gpregs, CTX_GPREG_X16);
1750b850e9eSRaghu Krishnamurthy 	retval->arg17 = read_ctx_reg(gpregs, CTX_GPREG_X17);
17666bdfd6eSRaghu Krishnamurthy }
17766bdfd6eSRaghu Krishnamurthy 
17866bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t *ctx)
17966bdfd6eSRaghu Krishnamurthy {
18066bdfd6eSRaghu Krishnamurthy 	ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_DIR_REQ_ONGOING;
18166bdfd6eSRaghu Krishnamurthy }
18266bdfd6eSRaghu Krishnamurthy 
18366bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t *ctx)
18466bdfd6eSRaghu Krishnamurthy {
18566bdfd6eSRaghu Krishnamurthy 	ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_DIR_REQ_ONGOING;
18666bdfd6eSRaghu Krishnamurthy }
18766bdfd6eSRaghu Krishnamurthy 
1880b850e9eSRaghu Krishnamurthy static void spmd_build_ffa_info_get_regs(spmd_spm_core_context_t *ctx,
1890b850e9eSRaghu Krishnamurthy 					 const uint32_t uuid[4],
1900b850e9eSRaghu Krishnamurthy 					 const uint16_t start_index,
1910b850e9eSRaghu Krishnamurthy 					 const uint16_t tag)
1920b850e9eSRaghu Krishnamurthy {
1930b850e9eSRaghu Krishnamurthy 	gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
1940b850e9eSRaghu Krishnamurthy 
1950b850e9eSRaghu Krishnamurthy 	uint64_t arg1 = (uint64_t)uuid[1] << 32 | uuid[0];
1960b850e9eSRaghu Krishnamurthy 	uint64_t arg2 = (uint64_t)uuid[3] << 32 | uuid[2];
1970b850e9eSRaghu Krishnamurthy 	uint64_t arg3 = start_index | (uint64_t)tag << 16;
1980b850e9eSRaghu Krishnamurthy 
1990b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_PARTITION_INFO_GET_REGS_SMC64);
2000b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X1, arg1);
2010b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X2, arg2);
2020b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X3, arg3);
2030b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X4, 0U);
2040b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X5, 0U);
2050b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X6, 0U);
2060b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X7, 0U);
2070b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X8, 0U);
2080b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X9, 0U);
2090b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X10, 0U);
2100b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X11, 0U);
2110b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X12, 0U);
2120b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X13, 0U);
2130b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X14, 0U);
2140b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X15, 0U);
2150b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X16, 0U);
2160b850e9eSRaghu Krishnamurthy 	write_ctx_reg(gpregs, CTX_GPREG_X17, 0U);
2170b850e9eSRaghu Krishnamurthy }
2180b850e9eSRaghu Krishnamurthy 
2190b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t *ctx)
2200b850e9eSRaghu Krishnamurthy {
2210b850e9eSRaghu Krishnamurthy 	ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_INFO_GET_REG_ONGOING;
2220b850e9eSRaghu Krishnamurthy }
2230b850e9eSRaghu Krishnamurthy 
2240b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_reset_info_regs_ongoing(
2250b850e9eSRaghu Krishnamurthy 		spmd_spm_core_context_t *ctx)
2260b850e9eSRaghu Krishnamurthy {
2270b850e9eSRaghu Krishnamurthy 	ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_INFO_GET_REG_ONGOING;
2280b850e9eSRaghu Krishnamurthy }
229*95f7f6d8SRaghu Krishnamurthy 
230*95f7f6d8SRaghu Krishnamurthy static void spmd_fill_lp_info_array(
231*95f7f6d8SRaghu Krishnamurthy 	struct ffa_partition_info_v1_1 (*partitions)[EL3_SPMD_MAX_NUM_LP],
232*95f7f6d8SRaghu Krishnamurthy 	uint32_t uuid[4], uint16_t *lp_count_out)
233*95f7f6d8SRaghu Krishnamurthy {
234*95f7f6d8SRaghu Krishnamurthy 	uint16_t lp_count = 0;
235*95f7f6d8SRaghu Krishnamurthy 	struct spmd_lp_desc *lp_array;
236*95f7f6d8SRaghu Krishnamurthy 	bool uuid_is_null = is_null_uuid(uuid);
237*95f7f6d8SRaghu Krishnamurthy 
238*95f7f6d8SRaghu Krishnamurthy 	if (SPMD_LP_DESCS_COUNT == 0U) {
239*95f7f6d8SRaghu Krishnamurthy 		*lp_count_out = 0;
240*95f7f6d8SRaghu Krishnamurthy 		return;
241*95f7f6d8SRaghu Krishnamurthy 	}
242*95f7f6d8SRaghu Krishnamurthy 
243*95f7f6d8SRaghu Krishnamurthy 	lp_array = get_spmd_el3_lp_array();
244*95f7f6d8SRaghu Krishnamurthy 	for (uint16_t index = 0; index < SPMD_LP_DESCS_COUNT; ++index) {
245*95f7f6d8SRaghu Krishnamurthy 		struct spmd_lp_desc *lp = &lp_array[index];
246*95f7f6d8SRaghu Krishnamurthy 
247*95f7f6d8SRaghu Krishnamurthy 		if (uuid_is_null || uuid_match(uuid, lp->uuid)) {
248*95f7f6d8SRaghu Krishnamurthy 			uint16_t array_index = lp_count;
249*95f7f6d8SRaghu Krishnamurthy 
250*95f7f6d8SRaghu Krishnamurthy 			++lp_count;
251*95f7f6d8SRaghu Krishnamurthy 
252*95f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].ep_id = lp->sp_id;
253*95f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].execution_ctx_count = 1;
254*95f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].properties = lp->properties;
255*95f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].properties |=
256*95f7f6d8SRaghu Krishnamurthy 				(FFA_PARTITION_INFO_GET_AARCH64_STATE <<
257*95f7f6d8SRaghu Krishnamurthy 				 FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT);
258*95f7f6d8SRaghu Krishnamurthy 			if (uuid_is_null) {
259*95f7f6d8SRaghu Krishnamurthy 				memcpy(&((*partitions)[array_index].uuid),
260*95f7f6d8SRaghu Krishnamurthy 					  &lp->uuid, sizeof(lp->uuid));
261*95f7f6d8SRaghu Krishnamurthy 			}
262*95f7f6d8SRaghu Krishnamurthy 		}
263*95f7f6d8SRaghu Krishnamurthy 	}
264*95f7f6d8SRaghu Krishnamurthy 
265*95f7f6d8SRaghu Krishnamurthy 	*lp_count_out = lp_count;
266*95f7f6d8SRaghu Krishnamurthy }
267*95f7f6d8SRaghu Krishnamurthy 
268*95f7f6d8SRaghu Krishnamurthy static inline void spmd_pack_lp_count_props(
269*95f7f6d8SRaghu Krishnamurthy 	uint64_t *xn, uint16_t ep_id, uint16_t vcpu_count,
270*95f7f6d8SRaghu Krishnamurthy 	uint32_t properties)
271*95f7f6d8SRaghu Krishnamurthy {
272*95f7f6d8SRaghu Krishnamurthy 	*xn = (uint64_t)ep_id;
273*95f7f6d8SRaghu Krishnamurthy 	*xn |= (uint64_t)vcpu_count << 16;
274*95f7f6d8SRaghu Krishnamurthy 	*xn |= (uint64_t)properties << 32;
275*95f7f6d8SRaghu Krishnamurthy }
276*95f7f6d8SRaghu Krishnamurthy 
277*95f7f6d8SRaghu Krishnamurthy static inline void spmd_pack_lp_uuid(uint64_t *xn_1, uint64_t *xn_2,
278*95f7f6d8SRaghu Krishnamurthy 				     uint32_t uuid[4])
279*95f7f6d8SRaghu Krishnamurthy {
280*95f7f6d8SRaghu Krishnamurthy 	*xn_1 = (uint64_t)uuid[0];
281*95f7f6d8SRaghu Krishnamurthy 	*xn_1 |= (uint64_t)uuid[1] << 32;
282*95f7f6d8SRaghu Krishnamurthy 	*xn_2 = (uint64_t)uuid[2];
283*95f7f6d8SRaghu Krishnamurthy 	*xn_2 |= (uint64_t)uuid[3] << 32;
284*95f7f6d8SRaghu Krishnamurthy }
285890b5088SRaghu Krishnamurthy #endif
286890b5088SRaghu Krishnamurthy 
287890b5088SRaghu Krishnamurthy /*
288890b5088SRaghu Krishnamurthy  * Initialize SPMD logical partitions. This function assumes that it is called
289890b5088SRaghu Krishnamurthy  * only after the SPMC has successfully initialized.
290890b5088SRaghu Krishnamurthy  */
291890b5088SRaghu Krishnamurthy int32_t spmd_logical_sp_init(void)
292890b5088SRaghu Krishnamurthy {
293890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP
294890b5088SRaghu Krishnamurthy 	int32_t rc = 0;
295890b5088SRaghu Krishnamurthy 	struct spmd_lp_desc *spmd_lp_descs;
296890b5088SRaghu Krishnamurthy 
297*95f7f6d8SRaghu Krishnamurthy 	assert(SPMD_LP_DESCS_COUNT <= EL3_SPMD_MAX_NUM_LP);
298*95f7f6d8SRaghu Krishnamurthy 
299890b5088SRaghu Krishnamurthy 	if (is_spmd_lp_inited == true) {
300890b5088SRaghu Krishnamurthy 		return 0;
301890b5088SRaghu Krishnamurthy 	}
302890b5088SRaghu Krishnamurthy 
303890b5088SRaghu Krishnamurthy 	if (is_spmc_inited == false) {
304890b5088SRaghu Krishnamurthy 		return -1;
305890b5088SRaghu Krishnamurthy 	}
306890b5088SRaghu Krishnamurthy 
307890b5088SRaghu Krishnamurthy 	spmd_lp_descs = get_spmd_el3_lp_array();
308890b5088SRaghu Krishnamurthy 
309890b5088SRaghu Krishnamurthy 	/* Perform initial validation of the SPMD Logical Partitions. */
310890b5088SRaghu Krishnamurthy 	rc = el3_spmd_sp_desc_validate(spmd_lp_descs);
311890b5088SRaghu Krishnamurthy 	if (rc != 0) {
312890b5088SRaghu Krishnamurthy 		ERROR("Logical SPMD Partition validation failed!\n");
313890b5088SRaghu Krishnamurthy 		return rc;
314890b5088SRaghu Krishnamurthy 	}
315890b5088SRaghu Krishnamurthy 
316890b5088SRaghu Krishnamurthy 	VERBOSE("SPMD Logical Secure Partition init start.\n");
317890b5088SRaghu Krishnamurthy 	for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) {
318890b5088SRaghu Krishnamurthy 		rc = spmd_lp_descs[i].init();
319890b5088SRaghu Krishnamurthy 		if (rc != 0) {
320890b5088SRaghu Krishnamurthy 			ERROR("SPMD Logical SP (0x%x) failed to initialize\n",
321890b5088SRaghu Krishnamurthy 			      spmd_lp_descs[i].sp_id);
322890b5088SRaghu Krishnamurthy 			return rc;
323890b5088SRaghu Krishnamurthy 		}
324890b5088SRaghu Krishnamurthy 		VERBOSE("SPMD Logical SP (0x%x) Initialized\n",
325890b5088SRaghu Krishnamurthy 			spmd_lp_descs[i].sp_id);
326890b5088SRaghu Krishnamurthy 	}
327890b5088SRaghu Krishnamurthy 
328890b5088SRaghu Krishnamurthy 	INFO("SPMD Logical Secure Partition init completed.\n");
329890b5088SRaghu Krishnamurthy 	if (rc == 0) {
330890b5088SRaghu Krishnamurthy 		is_spmd_lp_inited = true;
331890b5088SRaghu Krishnamurthy 	}
332890b5088SRaghu Krishnamurthy 	return rc;
333890b5088SRaghu Krishnamurthy #else
334890b5088SRaghu Krishnamurthy 	return 0;
335890b5088SRaghu Krishnamurthy #endif
336890b5088SRaghu Krishnamurthy }
337890b5088SRaghu Krishnamurthy 
338890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_initialized(void)
339890b5088SRaghu Krishnamurthy {
340890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP
341890b5088SRaghu Krishnamurthy 	is_spmc_inited = true;
342890b5088SRaghu Krishnamurthy #endif
343890b5088SRaghu Krishnamurthy }
344890b5088SRaghu Krishnamurthy 
345890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_failure(void)
346890b5088SRaghu Krishnamurthy {
347890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP
348890b5088SRaghu Krishnamurthy 	is_spmc_inited = false;
349890b5088SRaghu Krishnamurthy #endif
350890b5088SRaghu Krishnamurthy }
35166bdfd6eSRaghu Krishnamurthy 
3520b850e9eSRaghu Krishnamurthy /*
3530b850e9eSRaghu Krishnamurthy  * This function takes an ffa_value structure populated with partition
3540b850e9eSRaghu Krishnamurthy  * information from an FFA_PARTITION_INFO_GET_REGS ABI call, extracts
3550b850e9eSRaghu Krishnamurthy  * the values and writes it into a ffa_partition_info_v1_1 structure for
3560b850e9eSRaghu Krishnamurthy  * other code to consume.
3570b850e9eSRaghu Krishnamurthy  */
3580b850e9eSRaghu Krishnamurthy bool ffa_partition_info_regs_get_part_info(
3590b850e9eSRaghu Krishnamurthy 	struct ffa_value args, uint8_t idx,
3600b850e9eSRaghu Krishnamurthy 	struct ffa_partition_info_v1_1 *partition_info)
3610b850e9eSRaghu Krishnamurthy {
3620b850e9eSRaghu Krishnamurthy 	uint64_t *arg_ptrs;
3630b850e9eSRaghu Krishnamurthy 	uint64_t info, uuid_lo, uuid_high;
3640b850e9eSRaghu Krishnamurthy 
3650b850e9eSRaghu Krishnamurthy 	/*
3660b850e9eSRaghu Krishnamurthy 	 * Each partition information is encoded in 3 registers, so there can be
3670b850e9eSRaghu Krishnamurthy 	 * a maximum of 5 entries.
3680b850e9eSRaghu Krishnamurthy 	 */
3690b850e9eSRaghu Krishnamurthy 	if (idx >= 5 || partition_info == NULL) {
3700b850e9eSRaghu Krishnamurthy 		return false;
3710b850e9eSRaghu Krishnamurthy 	}
3720b850e9eSRaghu Krishnamurthy 
373*95f7f6d8SRaghu Krishnamurthy 	/*
374*95f7f6d8SRaghu Krishnamurthy 	 * List of pointers to args in return value. arg0/func encodes ff-a
375*95f7f6d8SRaghu Krishnamurthy 	 * function, arg1 is reserved, arg2 encodes indices. arg3 and greater
376*95f7f6d8SRaghu Krishnamurthy 	 * values reflect partition properties.
377*95f7f6d8SRaghu Krishnamurthy 	 */
3780b850e9eSRaghu Krishnamurthy 	arg_ptrs = (uint64_t *)&args + ((idx * 3) + 3);
3790b850e9eSRaghu Krishnamurthy 	info = *arg_ptrs;
3800b850e9eSRaghu Krishnamurthy 
3810b850e9eSRaghu Krishnamurthy 	arg_ptrs++;
3820b850e9eSRaghu Krishnamurthy 	uuid_lo = *arg_ptrs;
3830b850e9eSRaghu Krishnamurthy 
3840b850e9eSRaghu Krishnamurthy 	arg_ptrs++;
3850b850e9eSRaghu Krishnamurthy 	uuid_high = *arg_ptrs;
3860b850e9eSRaghu Krishnamurthy 
3870b850e9eSRaghu Krishnamurthy 	partition_info->ep_id = (uint16_t)(info & 0xFFFFU);
3880b850e9eSRaghu Krishnamurthy 	partition_info->execution_ctx_count = (uint16_t)((info >> 16) & 0xFFFFU);
3890b850e9eSRaghu Krishnamurthy 	partition_info->properties = (uint32_t)(info >> 32);
3900b850e9eSRaghu Krishnamurthy 	partition_info->uuid[0] = (uint32_t)(uuid_lo & 0xFFFFFFFFU);
3910b850e9eSRaghu Krishnamurthy 	partition_info->uuid[1] = (uint32_t)((uuid_lo >> 32) & 0xFFFFFFFFU);
3920b850e9eSRaghu Krishnamurthy 	partition_info->uuid[2] = (uint32_t)(uuid_high & 0xFFFFFFFFU);
3930b850e9eSRaghu Krishnamurthy 	partition_info->uuid[3] = (uint32_t)((uuid_high >> 32) & 0xFFFFFFFFU);
3940b850e9eSRaghu Krishnamurthy 
3950b850e9eSRaghu Krishnamurthy 	return true;
3960b850e9eSRaghu Krishnamurthy }
3970b850e9eSRaghu Krishnamurthy 
3980b850e9eSRaghu Krishnamurthy /*
399*95f7f6d8SRaghu Krishnamurthy  * This function is called by the SPMD in response to
400*95f7f6d8SRaghu Krishnamurthy  * an FFA_PARTITION_INFO_GET_REG ABI invocation by the SPMC. Secure partitions
401*95f7f6d8SRaghu Krishnamurthy  * are allowed to discover the presence of EL3 SPMD logical partitions by
402*95f7f6d8SRaghu Krishnamurthy  * invoking the aforementioned ABI and this function populates the required
403*95f7f6d8SRaghu Krishnamurthy  * information about EL3 SPMD logical partitions.
404*95f7f6d8SRaghu Krishnamurthy  */
405*95f7f6d8SRaghu Krishnamurthy uint64_t spmd_el3_populate_logical_partition_info(void *handle, uint64_t x1,
406*95f7f6d8SRaghu Krishnamurthy 						  uint64_t x2, uint64_t x3)
407*95f7f6d8SRaghu Krishnamurthy {
408*95f7f6d8SRaghu Krishnamurthy #if ENABLE_SPMD_LP
409*95f7f6d8SRaghu Krishnamurthy 	uint32_t target_uuid[4] = { 0 };
410*95f7f6d8SRaghu Krishnamurthy 	uint32_t w0;
411*95f7f6d8SRaghu Krishnamurthy 	uint32_t w1;
412*95f7f6d8SRaghu Krishnamurthy 	uint32_t w2;
413*95f7f6d8SRaghu Krishnamurthy 	uint32_t w3;
414*95f7f6d8SRaghu Krishnamurthy 	uint16_t start_index;
415*95f7f6d8SRaghu Krishnamurthy 	uint16_t tag;
416*95f7f6d8SRaghu Krishnamurthy 	static struct ffa_partition_info_v1_1 partitions[EL3_SPMD_MAX_NUM_LP];
417*95f7f6d8SRaghu Krishnamurthy 	uint16_t lp_count = 0;
418*95f7f6d8SRaghu Krishnamurthy 	uint16_t max_idx = 0;
419*95f7f6d8SRaghu Krishnamurthy 	uint16_t curr_idx = 0;
420*95f7f6d8SRaghu Krishnamurthy 	uint8_t num_entries_to_ret = 0;
421*95f7f6d8SRaghu Krishnamurthy 	struct ffa_value ret = { 0 };
422*95f7f6d8SRaghu Krishnamurthy 	uint64_t *arg_ptrs = (uint64_t *)&ret + 3;
423*95f7f6d8SRaghu Krishnamurthy 
424*95f7f6d8SRaghu Krishnamurthy 	w0 = (uint32_t)(x1 & 0xFFFFFFFFU);
425*95f7f6d8SRaghu Krishnamurthy 	w1 = (uint32_t)(x1 >> 32);
426*95f7f6d8SRaghu Krishnamurthy 	w2 = (uint32_t)(x2 & 0xFFFFFFFFU);
427*95f7f6d8SRaghu Krishnamurthy 	w3 = (uint32_t)(x2 >> 32);
428*95f7f6d8SRaghu Krishnamurthy 
429*95f7f6d8SRaghu Krishnamurthy 	target_uuid[0] = w0;
430*95f7f6d8SRaghu Krishnamurthy 	target_uuid[1] = w1;
431*95f7f6d8SRaghu Krishnamurthy 	target_uuid[2] = w2;
432*95f7f6d8SRaghu Krishnamurthy 	target_uuid[3] = w3;
433*95f7f6d8SRaghu Krishnamurthy 
434*95f7f6d8SRaghu Krishnamurthy 	start_index = (uint16_t)(x3 & 0xFFFFU);
435*95f7f6d8SRaghu Krishnamurthy 	tag = (uint16_t)((x3 >> 16) & 0xFFFFU);
436*95f7f6d8SRaghu Krishnamurthy 
437*95f7f6d8SRaghu Krishnamurthy 	assert(handle == cm_get_context(SECURE));
438*95f7f6d8SRaghu Krishnamurthy 
439*95f7f6d8SRaghu Krishnamurthy 	if (tag != 0) {
440*95f7f6d8SRaghu Krishnamurthy 		VERBOSE("Tag is not 0. Cannot return partition info.\n");
441*95f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle, FFA_ERROR_RETRY);
442*95f7f6d8SRaghu Krishnamurthy 	}
443*95f7f6d8SRaghu Krishnamurthy 
444*95f7f6d8SRaghu Krishnamurthy 	memset(&partitions, 0, sizeof(partitions));
445*95f7f6d8SRaghu Krishnamurthy 
446*95f7f6d8SRaghu Krishnamurthy 	spmd_fill_lp_info_array(&partitions, target_uuid, &lp_count);
447*95f7f6d8SRaghu Krishnamurthy 
448*95f7f6d8SRaghu Krishnamurthy 	if (lp_count == 0) {
449*95f7f6d8SRaghu Krishnamurthy 		VERBOSE("No SPDM EL3 logical partitions exist.\n");
450*95f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
451*95f7f6d8SRaghu Krishnamurthy 	}
452*95f7f6d8SRaghu Krishnamurthy 
453*95f7f6d8SRaghu Krishnamurthy 	if (start_index >= lp_count) {
454*95f7f6d8SRaghu Krishnamurthy 		VERBOSE("start_index = %d, lp_count = %d (start index must be"
455*95f7f6d8SRaghu Krishnamurthy 			" less than partition count.\n",
456*95f7f6d8SRaghu Krishnamurthy 			start_index, lp_count);
457*95f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle,
458*95f7f6d8SRaghu Krishnamurthy 					     FFA_ERROR_INVALID_PARAMETER);
459*95f7f6d8SRaghu Krishnamurthy 	}
460*95f7f6d8SRaghu Krishnamurthy 
461*95f7f6d8SRaghu Krishnamurthy 	max_idx = lp_count - 1;
462*95f7f6d8SRaghu Krishnamurthy 	num_entries_to_ret = (max_idx - start_index) + 1;
463*95f7f6d8SRaghu Krishnamurthy 	num_entries_to_ret =
464*95f7f6d8SRaghu Krishnamurthy 		MIN(num_entries_to_ret, MAX_INFO_REGS_ENTRIES_PER_CALL);
465*95f7f6d8SRaghu Krishnamurthy 	curr_idx = start_index + num_entries_to_ret - 1;
466*95f7f6d8SRaghu Krishnamurthy 	assert(curr_idx <= max_idx);
467*95f7f6d8SRaghu Krishnamurthy 
468*95f7f6d8SRaghu Krishnamurthy 	ret.func = FFA_SUCCESS_SMC64;
469*95f7f6d8SRaghu Krishnamurthy 	ret.arg2 = (uint64_t)((sizeof(struct ffa_partition_info_v1_1) & 0xFFFFU) << 48);
470*95f7f6d8SRaghu Krishnamurthy 	ret.arg2 |= (uint64_t)(curr_idx << 16);
471*95f7f6d8SRaghu Krishnamurthy 	ret.arg2 |= (uint64_t)max_idx;
472*95f7f6d8SRaghu Krishnamurthy 
473*95f7f6d8SRaghu Krishnamurthy 	for (uint16_t idx = start_index; idx <= curr_idx; ++idx) {
474*95f7f6d8SRaghu Krishnamurthy 		spmd_pack_lp_count_props(arg_ptrs, partitions[idx].ep_id,
475*95f7f6d8SRaghu Krishnamurthy 					 partitions[idx].execution_ctx_count,
476*95f7f6d8SRaghu Krishnamurthy 					 partitions[idx].properties);
477*95f7f6d8SRaghu Krishnamurthy 		arg_ptrs++;
478*95f7f6d8SRaghu Krishnamurthy 		if (is_null_uuid(target_uuid)) {
479*95f7f6d8SRaghu Krishnamurthy 			spmd_pack_lp_uuid(arg_ptrs, (arg_ptrs + 1),
480*95f7f6d8SRaghu Krishnamurthy 					  partitions[idx].uuid);
481*95f7f6d8SRaghu Krishnamurthy 		}
482*95f7f6d8SRaghu Krishnamurthy 		arg_ptrs += 2;
483*95f7f6d8SRaghu Krishnamurthy 	}
484*95f7f6d8SRaghu Krishnamurthy 
485*95f7f6d8SRaghu Krishnamurthy 	SMC_RET18(handle, ret.func, ret.arg1, ret.arg2, ret.arg3, ret.arg4,
486*95f7f6d8SRaghu Krishnamurthy 		  ret.arg5, ret.arg6, ret.arg7, ret.arg8, ret.arg9, ret.arg10,
487*95f7f6d8SRaghu Krishnamurthy 		  ret.arg11, ret.arg12, ret.arg13, ret.arg14, ret.arg15,
488*95f7f6d8SRaghu Krishnamurthy 		  ret.arg16, ret.arg17);
489*95f7f6d8SRaghu Krishnamurthy #else
490*95f7f6d8SRaghu Krishnamurthy 	return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
491*95f7f6d8SRaghu Krishnamurthy #endif
492*95f7f6d8SRaghu Krishnamurthy }
493*95f7f6d8SRaghu Krishnamurthy 
494*95f7f6d8SRaghu Krishnamurthy /* This function can be used by an SPMD logical partition to invoke the
4950b850e9eSRaghu Krishnamurthy  * FFA_PARTITION_INFO_GET_REGS ABI to the SPMC, to discover the secure
4960b850e9eSRaghu Krishnamurthy  * partitions in the system. The function takes a UUID, start index and
4970b850e9eSRaghu Krishnamurthy  * tag and the partition information are returned in an ffa_value structure
4980b850e9eSRaghu Krishnamurthy  * and can be consumed by using appropriate helper functions.
4990b850e9eSRaghu Krishnamurthy  */
5000b850e9eSRaghu Krishnamurthy bool spmd_el3_invoke_partition_info_get(
5010b850e9eSRaghu Krishnamurthy 				const uint32_t target_uuid[4],
5020b850e9eSRaghu Krishnamurthy 				const uint16_t start_index,
5030b850e9eSRaghu Krishnamurthy 				const uint16_t tag,
5040b850e9eSRaghu Krishnamurthy 				struct ffa_value *retval)
5050b850e9eSRaghu Krishnamurthy {
5060b850e9eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
5070b850e9eSRaghu Krishnamurthy 	uint64_t rc = UINT64_MAX;
5080b850e9eSRaghu Krishnamurthy 	spmd_spm_core_context_t *ctx = spmd_get_context();
5090b850e9eSRaghu Krishnamurthy 
5100b850e9eSRaghu Krishnamurthy 	if (retval == NULL) {
5110b850e9eSRaghu Krishnamurthy 		return false;
5120b850e9eSRaghu Krishnamurthy 	}
5130b850e9eSRaghu Krishnamurthy 
5140b850e9eSRaghu Krishnamurthy 	memset(retval, 0, sizeof(*retval));
5150b850e9eSRaghu Krishnamurthy 
5160b850e9eSRaghu Krishnamurthy 	if (!is_spmc_inited) {
5170b850e9eSRaghu Krishnamurthy 		VERBOSE("Cannot discover partition before,"
5180b850e9eSRaghu Krishnamurthy 			" SPMC is initialized.\n");
5190b850e9eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
5200b850e9eSRaghu Krishnamurthy 		return true;
5210b850e9eSRaghu Krishnamurthy 	}
5220b850e9eSRaghu Krishnamurthy 
5230b850e9eSRaghu Krishnamurthy 	if (tag != 0) {
5240b850e9eSRaghu Krishnamurthy 		VERBOSE("Tag must be zero. other tags unsupported\n");
5250b850e9eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
5260b850e9eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
5270b850e9eSRaghu Krishnamurthy 		return true;
5280b850e9eSRaghu Krishnamurthy 	}
5290b850e9eSRaghu Krishnamurthy 
5300b850e9eSRaghu Krishnamurthy 	/* Save the non-secure context before entering SPMC */
5310b850e9eSRaghu Krishnamurthy 	cm_el1_sysregs_context_save(NON_SECURE);
5320b850e9eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
5330b850e9eSRaghu Krishnamurthy 	cm_el2_sysregs_context_save(NON_SECURE);
5340b850e9eSRaghu Krishnamurthy #endif
5350b850e9eSRaghu Krishnamurthy 
5360b850e9eSRaghu Krishnamurthy 	spmd_build_ffa_info_get_regs(ctx, target_uuid, start_index, tag);
5370b850e9eSRaghu Krishnamurthy 	spmd_logical_sp_set_info_regs_ongoing(ctx);
5380b850e9eSRaghu Krishnamurthy 
5390b850e9eSRaghu Krishnamurthy 	rc = spmd_spm_core_sync_entry(ctx);
5400b850e9eSRaghu Krishnamurthy 	if (rc != 0ULL) {
5410b850e9eSRaghu Krishnamurthy 		ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
5420b850e9eSRaghu Krishnamurthy 		      plat_my_core_pos());
5430b850e9eSRaghu Krishnamurthy 		panic();
5440b850e9eSRaghu Krishnamurthy 	}
5450b850e9eSRaghu Krishnamurthy 
5460b850e9eSRaghu Krishnamurthy 	spmd_logical_sp_reset_info_regs_ongoing(ctx);
5470b850e9eSRaghu Krishnamurthy 	spmd_encode_ctx_to_ffa_value(ctx, retval);
5480b850e9eSRaghu Krishnamurthy 
5490b850e9eSRaghu Krishnamurthy 	assert(is_ffa_error(retval) || is_ffa_success(retval));
5500b850e9eSRaghu Krishnamurthy 
5510b850e9eSRaghu Krishnamurthy 	cm_el1_sysregs_context_restore(NON_SECURE);
5520b850e9eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
5530b850e9eSRaghu Krishnamurthy 	cm_el2_sysregs_context_restore(NON_SECURE);
5540b850e9eSRaghu Krishnamurthy #endif
5550b850e9eSRaghu Krishnamurthy 	cm_set_next_eret_context(NON_SECURE);
5560b850e9eSRaghu Krishnamurthy 	return true;
5570b850e9eSRaghu Krishnamurthy #else
5580b850e9eSRaghu Krishnamurthy 	return false;
5590b850e9eSRaghu Krishnamurthy #endif
5600b850e9eSRaghu Krishnamurthy }
5610b850e9eSRaghu Krishnamurthy 
56266bdfd6eSRaghu Krishnamurthy /*******************************************************************************
56366bdfd6eSRaghu Krishnamurthy  * This function sends an FF-A Direct Request from a partition in EL3 to a
56466bdfd6eSRaghu Krishnamurthy  * partition that may reside under an SPMC (only lower ELs supported). The main
56566bdfd6eSRaghu Krishnamurthy  * use of this API is for SPMD logical partitions.
56666bdfd6eSRaghu Krishnamurthy  * The API is expected to be used when there are platform specific SMCs that
56766bdfd6eSRaghu Krishnamurthy  * need to be routed to a secure partition that is FF-A compliant or when
56866bdfd6eSRaghu Krishnamurthy  * there are group 0 interrupts that need to be handled first in EL3 and then
56966bdfd6eSRaghu Krishnamurthy  * forwarded to an FF-A compliant secure partition. Therefore, it is expected
57066bdfd6eSRaghu Krishnamurthy  * that the handle to the context provided belongs to the non-secure context.
57166bdfd6eSRaghu Krishnamurthy  * This also means that interrupts/SMCs that trap to EL3 during secure execution
57266bdfd6eSRaghu Krishnamurthy  * cannot use this API.
57366bdfd6eSRaghu Krishnamurthy  * x1, x2, x3 and x4 are encoded as specified in the FF-A specification.
57466bdfd6eSRaghu Krishnamurthy  * retval is used to pass the direct response values to the caller.
57566bdfd6eSRaghu Krishnamurthy  * The function returns true if retval has valid values, and false otherwise.
57666bdfd6eSRaghu Krishnamurthy  ******************************************************************************/
57766bdfd6eSRaghu Krishnamurthy bool spmd_el3_ffa_msg_direct_req(uint64_t x1,
57866bdfd6eSRaghu Krishnamurthy 				 uint64_t x2,
57966bdfd6eSRaghu Krishnamurthy 				 uint64_t x3,
58066bdfd6eSRaghu Krishnamurthy 				 uint64_t x4,
58166bdfd6eSRaghu Krishnamurthy 				 void *handle,
58266bdfd6eSRaghu Krishnamurthy 				 struct ffa_value *retval)
58366bdfd6eSRaghu Krishnamurthy {
58466bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
58566bdfd6eSRaghu Krishnamurthy 
58666bdfd6eSRaghu Krishnamurthy 	uint64_t rc = UINT64_MAX;
58766bdfd6eSRaghu Krishnamurthy 	spmd_spm_core_context_t *ctx = spmd_get_context();
58866bdfd6eSRaghu Krishnamurthy 
58966bdfd6eSRaghu Krishnamurthy 	if (retval == NULL) {
59066bdfd6eSRaghu Krishnamurthy 		return false;
59166bdfd6eSRaghu Krishnamurthy 	}
59266bdfd6eSRaghu Krishnamurthy 
59366bdfd6eSRaghu Krishnamurthy 	memset(retval, 0, sizeof(*retval));
59466bdfd6eSRaghu Krishnamurthy 
59566bdfd6eSRaghu Krishnamurthy 	if (!is_spmd_lp_inited || !is_spmc_inited) {
59666bdfd6eSRaghu Krishnamurthy 		VERBOSE("Cannot send SPMD logical partition direct message,"
59766bdfd6eSRaghu Krishnamurthy 			" Partitions not initialized or SPMC not initialized.\n");
59866bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
59966bdfd6eSRaghu Krishnamurthy 		return true;
60066bdfd6eSRaghu Krishnamurthy 	}
60166bdfd6eSRaghu Krishnamurthy 
60266bdfd6eSRaghu Krishnamurthy 	/*
60366bdfd6eSRaghu Krishnamurthy 	 * x2 must be zero, since there is no support for framework message via
60466bdfd6eSRaghu Krishnamurthy 	 * an SPMD logical partition. This is sort of a useless check and it is
60566bdfd6eSRaghu Krishnamurthy 	 * possible to not take parameter. However, as the framework extends it
60666bdfd6eSRaghu Krishnamurthy 	 * may be useful to have x2 and extend this function later with
60766bdfd6eSRaghu Krishnamurthy 	 * functionality based on x2.
60866bdfd6eSRaghu Krishnamurthy 	 */
60966bdfd6eSRaghu Krishnamurthy 	if (x2 != 0) {
61066bdfd6eSRaghu Krishnamurthy 		VERBOSE("x2 must be zero. Cannot send framework message.\n");
61166bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
61266bdfd6eSRaghu Krishnamurthy 		return true;
61366bdfd6eSRaghu Krishnamurthy 	}
61466bdfd6eSRaghu Krishnamurthy 
61566bdfd6eSRaghu Krishnamurthy 	/*
61666bdfd6eSRaghu Krishnamurthy 	 * Current context must be non-secure. API is expected to be used
61766bdfd6eSRaghu Krishnamurthy 	 * when entry into EL3 and the SPMD logical partition is via an
61866bdfd6eSRaghu Krishnamurthy 	 * interrupt that occurs when execution is in normal world and
61966bdfd6eSRaghu Krishnamurthy 	 * SMCs from normal world. FF-A compliant SPMCs are expected to
62066bdfd6eSRaghu Krishnamurthy 	 * trap interrupts during secure execution in lower ELs since they
62166bdfd6eSRaghu Krishnamurthy 	 * are usually not re-entrant and SMCs from secure world can be
62266bdfd6eSRaghu Krishnamurthy 	 * handled synchronously. There is no known use case for an SPMD
62366bdfd6eSRaghu Krishnamurthy 	 * logical partition to send a direct message to another partition
62466bdfd6eSRaghu Krishnamurthy 	 * in response to a secure interrupt or SMCs from secure world.
62566bdfd6eSRaghu Krishnamurthy 	 */
62666bdfd6eSRaghu Krishnamurthy 	if (handle != cm_get_context(NON_SECURE)) {
62766bdfd6eSRaghu Krishnamurthy 		VERBOSE("Handle must be for the non-secure context.\n");
62866bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
62966bdfd6eSRaghu Krishnamurthy 		return true;
63066bdfd6eSRaghu Krishnamurthy 	}
63166bdfd6eSRaghu Krishnamurthy 
63266bdfd6eSRaghu Krishnamurthy 	if (!is_spmd_lp_id(ffa_endpoint_source(x1))) {
63366bdfd6eSRaghu Krishnamurthy 		VERBOSE("Source ID must be valid SPMD logical partition"
63466bdfd6eSRaghu Krishnamurthy 			" ID.\n");
63566bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
63666bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
63766bdfd6eSRaghu Krishnamurthy 		return true;
63866bdfd6eSRaghu Krishnamurthy 	}
63966bdfd6eSRaghu Krishnamurthy 
64066bdfd6eSRaghu Krishnamurthy 	if (is_spmd_lp_id(ffa_endpoint_destination(x1))) {
64166bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMD logical partition"
64266bdfd6eSRaghu Krishnamurthy 			" ID.\n");
64366bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
64466bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
64566bdfd6eSRaghu Krishnamurthy 		return true;
64666bdfd6eSRaghu Krishnamurthy 	}
64766bdfd6eSRaghu Krishnamurthy 
64866bdfd6eSRaghu Krishnamurthy 	if (!ffa_is_secure_world_id(ffa_endpoint_destination(x1))) {
64966bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must be secure world ID.\n");
65066bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
65166bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
65266bdfd6eSRaghu Krishnamurthy 		return true;
65366bdfd6eSRaghu Krishnamurthy 	}
65466bdfd6eSRaghu Krishnamurthy 
65566bdfd6eSRaghu Krishnamurthy 	if (ffa_endpoint_destination(x1) == SPMD_DIRECT_MSG_ENDPOINT_ID) {
65666bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMD ID.\n");
65766bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
65866bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
65966bdfd6eSRaghu Krishnamurthy 		return true;
66066bdfd6eSRaghu Krishnamurthy 	}
66166bdfd6eSRaghu Krishnamurthy 
66266bdfd6eSRaghu Krishnamurthy 	if (ffa_endpoint_destination(x1) == spmd_spmc_id_get()) {
66366bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMC ID.\n");
66466bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
66566bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
66666bdfd6eSRaghu Krishnamurthy 		return true;
66766bdfd6eSRaghu Krishnamurthy 	}
66866bdfd6eSRaghu Krishnamurthy 
66966bdfd6eSRaghu Krishnamurthy 	/* Save the non-secure context before entering SPMC */
67066bdfd6eSRaghu Krishnamurthy 	cm_el1_sysregs_context_save(NON_SECURE);
67166bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
67266bdfd6eSRaghu Krishnamurthy 	cm_el2_sysregs_context_save(NON_SECURE);
67366bdfd6eSRaghu Krishnamurthy #endif
67466bdfd6eSRaghu Krishnamurthy 
67566bdfd6eSRaghu Krishnamurthy 	/*
67666bdfd6eSRaghu Krishnamurthy 	 * Perform synchronous entry into the SPMC. Synchronous entry is
67766bdfd6eSRaghu Krishnamurthy 	 * required because the spec requires that a direct message request
67866bdfd6eSRaghu Krishnamurthy 	 * from an SPMD LP look like a function call from it's perspective.
67966bdfd6eSRaghu Krishnamurthy 	 */
68066bdfd6eSRaghu Krishnamurthy 	spmd_build_direct_message_req(ctx, x1, x2, x3, x4);
68166bdfd6eSRaghu Krishnamurthy 	spmd_logical_sp_set_dir_req_ongoing(ctx);
68266bdfd6eSRaghu Krishnamurthy 
68366bdfd6eSRaghu Krishnamurthy 	rc = spmd_spm_core_sync_entry(ctx);
68466bdfd6eSRaghu Krishnamurthy 
68566bdfd6eSRaghu Krishnamurthy 	spmd_logical_sp_reset_dir_req_ongoing(ctx);
68666bdfd6eSRaghu Krishnamurthy 
68766bdfd6eSRaghu Krishnamurthy 	if (rc != 0ULL) {
68866bdfd6eSRaghu Krishnamurthy 		ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
68966bdfd6eSRaghu Krishnamurthy 		      plat_my_core_pos());
69066bdfd6eSRaghu Krishnamurthy 		panic();
69166bdfd6eSRaghu Krishnamurthy 	} else {
69266bdfd6eSRaghu Krishnamurthy 		spmd_encode_ctx_to_ffa_value(ctx, retval);
69366bdfd6eSRaghu Krishnamurthy 
69466bdfd6eSRaghu Krishnamurthy 		/*
69566bdfd6eSRaghu Krishnamurthy 		 * Only expect error or direct response,
69666bdfd6eSRaghu Krishnamurthy 		 * spmd_spm_core_sync_exit should not be called on other paths.
69766bdfd6eSRaghu Krishnamurthy 		 * Checks are asserts since the LSP can fail gracefully if the
69866bdfd6eSRaghu Krishnamurthy 		 * source or destination ids are not the same. Panic'ing would
69966bdfd6eSRaghu Krishnamurthy 		 * not provide any benefit.
70066bdfd6eSRaghu Krishnamurthy 		 */
70166bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) || is_ffa_direct_msg_resp(retval));
70266bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) ||
70366bdfd6eSRaghu Krishnamurthy 			(ffa_endpoint_destination(retval->arg1) ==
70466bdfd6eSRaghu Krishnamurthy 				ffa_endpoint_source(x1)));
70566bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) ||
70666bdfd6eSRaghu Krishnamurthy 			(ffa_endpoint_source(retval->arg1) ==
70766bdfd6eSRaghu Krishnamurthy 				ffa_endpoint_destination(x1)));
70866bdfd6eSRaghu Krishnamurthy 	}
70966bdfd6eSRaghu Krishnamurthy 
71066bdfd6eSRaghu Krishnamurthy 	cm_el1_sysregs_context_restore(NON_SECURE);
71166bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
71266bdfd6eSRaghu Krishnamurthy 	cm_el2_sysregs_context_restore(NON_SECURE);
71366bdfd6eSRaghu Krishnamurthy #endif
71466bdfd6eSRaghu Krishnamurthy 	cm_set_next_eret_context(NON_SECURE);
71566bdfd6eSRaghu Krishnamurthy 
71666bdfd6eSRaghu Krishnamurthy 	return true;
71766bdfd6eSRaghu Krishnamurthy #else
71866bdfd6eSRaghu Krishnamurthy 	return false;
71966bdfd6eSRaghu Krishnamurthy #endif
72066bdfd6eSRaghu Krishnamurthy }
72166bdfd6eSRaghu Krishnamurthy 
7220b850e9eSRaghu Krishnamurthy bool is_spmd_logical_sp_info_regs_req_in_progress(
7230b850e9eSRaghu Krishnamurthy 		spmd_spm_core_context_t *ctx)
7240b850e9eSRaghu Krishnamurthy {
7250b850e9eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
7260b850e9eSRaghu Krishnamurthy 	return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_INFO_GET_REG_ONGOING)
7270b850e9eSRaghu Krishnamurthy 			== SPMD_LP_FFA_INFO_GET_REG_ONGOING);
7280b850e9eSRaghu Krishnamurthy #else
7290b850e9eSRaghu Krishnamurthy 	return false;
7300b850e9eSRaghu Krishnamurthy #endif
7310b850e9eSRaghu Krishnamurthy }
7320b850e9eSRaghu Krishnamurthy 
73366bdfd6eSRaghu Krishnamurthy bool is_spmd_logical_sp_dir_req_in_progress(
73466bdfd6eSRaghu Krishnamurthy 		spmd_spm_core_context_t *ctx)
73566bdfd6eSRaghu Krishnamurthy {
73666bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
73766bdfd6eSRaghu Krishnamurthy 	return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING)
73866bdfd6eSRaghu Krishnamurthy 		== SPMD_LP_FFA_DIR_REQ_ONGOING);
73966bdfd6eSRaghu Krishnamurthy #else
74066bdfd6eSRaghu Krishnamurthy 	return false;
74166bdfd6eSRaghu Krishnamurthy #endif
74266bdfd6eSRaghu Krishnamurthy }
743