xref: /rk3399_ARM-atf/services/std_svc/spmd/spmd_logical_sp.c (revision 4c23d62746dc74d2e34e3777b196bd8257f8b863)
1890b5088SRaghu Krishnamurthy /*
22d960a11SMadhukar Pappireddy  * Copyright (c) 2023-2024, 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>
1395f7f6d8SRaghu 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>
1795f7f6d8SRaghu Krishnamurthy #include <smccc_helpers.h>
1866bdfd6eSRaghu Krishnamurthy 
19890b5088SRaghu Krishnamurthy 
2095f7f6d8SRaghu Krishnamurthy /*
2195f7f6d8SRaghu Krishnamurthy  * Maximum ffa_partition_info entries that can be returned by an invocation
2295f7f6d8SRaghu Krishnamurthy  * of FFA_PARTITION_INFO_GET_REGS_64 is size in bytes, of available
2395f7f6d8SRaghu Krishnamurthy  * registers/args in struct ffa_value divided by size of struct
2495f7f6d8SRaghu Krishnamurthy  * ffa_partition_info. For this ABI, arg3-arg17 in ffa_value can be used, i.e.
2595f7f6d8SRaghu Krishnamurthy  * 15 uint64_t fields. For FF-A v1.1, this value should be 5.
2695f7f6d8SRaghu Krishnamurthy  */
2795f7f6d8SRaghu Krishnamurthy #define MAX_INFO_REGS_ENTRIES_PER_CALL \
2895f7f6d8SRaghu Krishnamurthy 	(uint8_t)((15 * sizeof(uint64_t)) / \
2995f7f6d8SRaghu Krishnamurthy 		  sizeof(struct ffa_partition_info_v1_1))
3095f7f6d8SRaghu Krishnamurthy CASSERT(MAX_INFO_REGS_ENTRIES_PER_CALL == 5, assert_too_many_info_reg_entries);
3195f7f6d8SRaghu 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  */
get_spmd_el3_lp_array(void)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  ******************************************************************************/
el3_spmd_sp_desc_validate(struct spmd_lp_desc * lp_array)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 
spmd_encode_ffa_error(struct ffa_value * retval,int32_t error_code)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 
spmd_build_direct_message_req(spmd_spm_core_context_t * ctx,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4)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 
spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t * ctx,struct ffa_value * retval)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 
spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t * ctx)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 
spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t * ctx)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 
spmd_build_ffa_info_get_regs(spmd_spm_core_context_t * ctx,const uint32_t uuid[4],const uint16_t start_index,const uint16_t tag)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 
spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t * ctx)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 
spmd_logical_sp_reset_info_regs_ongoing(spmd_spm_core_context_t * ctx)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 }
22995f7f6d8SRaghu Krishnamurthy 
spmd_fill_lp_info_array(struct ffa_partition_info_v1_1 (* partitions)[EL3_SPMD_MAX_NUM_LP],uint32_t uuid[4],uint16_t * lp_count_out)23095f7f6d8SRaghu Krishnamurthy static void spmd_fill_lp_info_array(
23195f7f6d8SRaghu Krishnamurthy 	struct ffa_partition_info_v1_1 (*partitions)[EL3_SPMD_MAX_NUM_LP],
23295f7f6d8SRaghu Krishnamurthy 	uint32_t uuid[4], uint16_t *lp_count_out)
23395f7f6d8SRaghu Krishnamurthy {
23495f7f6d8SRaghu Krishnamurthy 	uint16_t lp_count = 0;
23595f7f6d8SRaghu Krishnamurthy 	struct spmd_lp_desc *lp_array;
23695f7f6d8SRaghu Krishnamurthy 	bool uuid_is_null = is_null_uuid(uuid);
23795f7f6d8SRaghu Krishnamurthy 
23895f7f6d8SRaghu Krishnamurthy 	if (SPMD_LP_DESCS_COUNT == 0U) {
23995f7f6d8SRaghu Krishnamurthy 		*lp_count_out = 0;
24095f7f6d8SRaghu Krishnamurthy 		return;
24195f7f6d8SRaghu Krishnamurthy 	}
24295f7f6d8SRaghu Krishnamurthy 
24395f7f6d8SRaghu Krishnamurthy 	lp_array = get_spmd_el3_lp_array();
24495f7f6d8SRaghu Krishnamurthy 	for (uint16_t index = 0; index < SPMD_LP_DESCS_COUNT; ++index) {
24595f7f6d8SRaghu Krishnamurthy 		struct spmd_lp_desc *lp = &lp_array[index];
24695f7f6d8SRaghu Krishnamurthy 
24795f7f6d8SRaghu Krishnamurthy 		if (uuid_is_null || uuid_match(uuid, lp->uuid)) {
24895f7f6d8SRaghu Krishnamurthy 			uint16_t array_index = lp_count;
24995f7f6d8SRaghu Krishnamurthy 
25095f7f6d8SRaghu Krishnamurthy 			++lp_count;
25195f7f6d8SRaghu Krishnamurthy 
25295f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].ep_id = lp->sp_id;
25395f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].execution_ctx_count = 1;
25495f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].properties = lp->properties;
25595f7f6d8SRaghu Krishnamurthy 			(*partitions)[array_index].properties |=
25695f7f6d8SRaghu Krishnamurthy 				(FFA_PARTITION_INFO_GET_AARCH64_STATE <<
25795f7f6d8SRaghu Krishnamurthy 				 FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT);
25895f7f6d8SRaghu Krishnamurthy 			if (uuid_is_null) {
25995f7f6d8SRaghu Krishnamurthy 				memcpy(&((*partitions)[array_index].uuid),
26095f7f6d8SRaghu Krishnamurthy 					  &lp->uuid, sizeof(lp->uuid));
26195f7f6d8SRaghu Krishnamurthy 			}
26295f7f6d8SRaghu Krishnamurthy 		}
26395f7f6d8SRaghu Krishnamurthy 	}
26495f7f6d8SRaghu Krishnamurthy 
26595f7f6d8SRaghu Krishnamurthy 	*lp_count_out = lp_count;
26695f7f6d8SRaghu Krishnamurthy }
26795f7f6d8SRaghu Krishnamurthy 
spmd_pack_lp_count_props(uint64_t * xn,uint16_t ep_id,uint16_t vcpu_count,uint32_t properties)26895f7f6d8SRaghu Krishnamurthy static inline void spmd_pack_lp_count_props(
26995f7f6d8SRaghu Krishnamurthy 	uint64_t *xn, uint16_t ep_id, uint16_t vcpu_count,
27095f7f6d8SRaghu Krishnamurthy 	uint32_t properties)
27195f7f6d8SRaghu Krishnamurthy {
27295f7f6d8SRaghu Krishnamurthy 	*xn = (uint64_t)ep_id;
27395f7f6d8SRaghu Krishnamurthy 	*xn |= (uint64_t)vcpu_count << 16;
27495f7f6d8SRaghu Krishnamurthy 	*xn |= (uint64_t)properties << 32;
27595f7f6d8SRaghu Krishnamurthy }
27695f7f6d8SRaghu Krishnamurthy 
spmd_pack_lp_uuid(uint64_t * xn_1,uint64_t * xn_2,uint32_t uuid[4])27795f7f6d8SRaghu Krishnamurthy static inline void spmd_pack_lp_uuid(uint64_t *xn_1, uint64_t *xn_2,
27895f7f6d8SRaghu Krishnamurthy 				     uint32_t uuid[4])
27995f7f6d8SRaghu Krishnamurthy {
28095f7f6d8SRaghu Krishnamurthy 	*xn_1 = (uint64_t)uuid[0];
28195f7f6d8SRaghu Krishnamurthy 	*xn_1 |= (uint64_t)uuid[1] << 32;
28295f7f6d8SRaghu Krishnamurthy 	*xn_2 = (uint64_t)uuid[2];
28395f7f6d8SRaghu Krishnamurthy 	*xn_2 |= (uint64_t)uuid[3] << 32;
28495f7f6d8SRaghu 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  */
spmd_logical_sp_init(void)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 
29795f7f6d8SRaghu Krishnamurthy 	assert(SPMD_LP_DESCS_COUNT <= EL3_SPMD_MAX_NUM_LP);
29895f7f6d8SRaghu 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 
spmd_logical_sp_set_spmc_initialized(void)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 
spmd_logical_sp_set_spmc_failure(void)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  */
ffa_partition_info_regs_get_part_info(struct ffa_value * args,uint8_t idx,struct ffa_partition_info_v1_1 * partition_info)3580b850e9eSRaghu Krishnamurthy bool ffa_partition_info_regs_get_part_info(
359b04343f3SRaghu 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 
37395f7f6d8SRaghu Krishnamurthy 	/*
37495f7f6d8SRaghu Krishnamurthy 	 * List of pointers to args in return value. arg0/func encodes ff-a
37595f7f6d8SRaghu Krishnamurthy 	 * function, arg1 is reserved, arg2 encodes indices. arg3 and greater
37695f7f6d8SRaghu Krishnamurthy 	 * values reflect partition properties.
37795f7f6d8SRaghu Krishnamurthy 	 */
378b04343f3SRaghu 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 /*
39995f7f6d8SRaghu Krishnamurthy  * This function is called by the SPMD in response to
40095f7f6d8SRaghu Krishnamurthy  * an FFA_PARTITION_INFO_GET_REG ABI invocation by the SPMC. Secure partitions
40195f7f6d8SRaghu Krishnamurthy  * are allowed to discover the presence of EL3 SPMD logical partitions by
40295f7f6d8SRaghu Krishnamurthy  * invoking the aforementioned ABI and this function populates the required
40395f7f6d8SRaghu Krishnamurthy  * information about EL3 SPMD logical partitions.
40495f7f6d8SRaghu Krishnamurthy  */
spmd_el3_populate_logical_partition_info(void * handle,uint64_t x1,uint64_t x2,uint64_t x3)40595f7f6d8SRaghu Krishnamurthy uint64_t spmd_el3_populate_logical_partition_info(void *handle, uint64_t x1,
40695f7f6d8SRaghu Krishnamurthy 						  uint64_t x2, uint64_t x3)
40795f7f6d8SRaghu Krishnamurthy {
40895f7f6d8SRaghu Krishnamurthy #if ENABLE_SPMD_LP
40995f7f6d8SRaghu Krishnamurthy 	uint32_t target_uuid[4] = { 0 };
41095f7f6d8SRaghu Krishnamurthy 	uint32_t w0;
41195f7f6d8SRaghu Krishnamurthy 	uint32_t w1;
41295f7f6d8SRaghu Krishnamurthy 	uint32_t w2;
41395f7f6d8SRaghu Krishnamurthy 	uint32_t w3;
41495f7f6d8SRaghu Krishnamurthy 	uint16_t start_index;
41595f7f6d8SRaghu Krishnamurthy 	uint16_t tag;
41695f7f6d8SRaghu Krishnamurthy 	static struct ffa_partition_info_v1_1 partitions[EL3_SPMD_MAX_NUM_LP];
41795f7f6d8SRaghu Krishnamurthy 	uint16_t lp_count = 0;
41895f7f6d8SRaghu Krishnamurthy 	uint16_t max_idx = 0;
41995f7f6d8SRaghu Krishnamurthy 	uint16_t curr_idx = 0;
42095f7f6d8SRaghu Krishnamurthy 	uint8_t num_entries_to_ret = 0;
42195f7f6d8SRaghu Krishnamurthy 	struct ffa_value ret = { 0 };
42295f7f6d8SRaghu Krishnamurthy 	uint64_t *arg_ptrs = (uint64_t *)&ret + 3;
42395f7f6d8SRaghu Krishnamurthy 
42495f7f6d8SRaghu Krishnamurthy 	w0 = (uint32_t)(x1 & 0xFFFFFFFFU);
42595f7f6d8SRaghu Krishnamurthy 	w1 = (uint32_t)(x1 >> 32);
42695f7f6d8SRaghu Krishnamurthy 	w2 = (uint32_t)(x2 & 0xFFFFFFFFU);
42795f7f6d8SRaghu Krishnamurthy 	w3 = (uint32_t)(x2 >> 32);
42895f7f6d8SRaghu Krishnamurthy 
42995f7f6d8SRaghu Krishnamurthy 	target_uuid[0] = w0;
43095f7f6d8SRaghu Krishnamurthy 	target_uuid[1] = w1;
43195f7f6d8SRaghu Krishnamurthy 	target_uuid[2] = w2;
43295f7f6d8SRaghu Krishnamurthy 	target_uuid[3] = w3;
43395f7f6d8SRaghu Krishnamurthy 
43495f7f6d8SRaghu Krishnamurthy 	start_index = (uint16_t)(x3 & 0xFFFFU);
43595f7f6d8SRaghu Krishnamurthy 	tag = (uint16_t)((x3 >> 16) & 0xFFFFU);
43695f7f6d8SRaghu Krishnamurthy 
43795f7f6d8SRaghu Krishnamurthy 	assert(handle == cm_get_context(SECURE));
43895f7f6d8SRaghu Krishnamurthy 
43995f7f6d8SRaghu Krishnamurthy 	if (tag != 0) {
44095f7f6d8SRaghu Krishnamurthy 		VERBOSE("Tag is not 0. Cannot return partition info.\n");
44195f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle, FFA_ERROR_RETRY);
44295f7f6d8SRaghu Krishnamurthy 	}
44395f7f6d8SRaghu Krishnamurthy 
44495f7f6d8SRaghu Krishnamurthy 	memset(&partitions, 0, sizeof(partitions));
44595f7f6d8SRaghu Krishnamurthy 
44695f7f6d8SRaghu Krishnamurthy 	spmd_fill_lp_info_array(&partitions, target_uuid, &lp_count);
44795f7f6d8SRaghu Krishnamurthy 
44895f7f6d8SRaghu Krishnamurthy 	if (lp_count == 0) {
44995f7f6d8SRaghu Krishnamurthy 		VERBOSE("No SPDM EL3 logical partitions exist.\n");
45095f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
45195f7f6d8SRaghu Krishnamurthy 	}
45295f7f6d8SRaghu Krishnamurthy 
45395f7f6d8SRaghu Krishnamurthy 	if (start_index >= lp_count) {
45495f7f6d8SRaghu Krishnamurthy 		VERBOSE("start_index = %d, lp_count = %d (start index must be"
45595f7f6d8SRaghu Krishnamurthy 			" less than partition count.\n",
45695f7f6d8SRaghu Krishnamurthy 			start_index, lp_count);
45795f7f6d8SRaghu Krishnamurthy 		return spmd_ffa_error_return(handle,
45895f7f6d8SRaghu Krishnamurthy 					     FFA_ERROR_INVALID_PARAMETER);
45995f7f6d8SRaghu Krishnamurthy 	}
46095f7f6d8SRaghu Krishnamurthy 
46195f7f6d8SRaghu Krishnamurthy 	max_idx = lp_count - 1;
46295f7f6d8SRaghu Krishnamurthy 	num_entries_to_ret = (max_idx - start_index) + 1;
46395f7f6d8SRaghu Krishnamurthy 	num_entries_to_ret =
46495f7f6d8SRaghu Krishnamurthy 		MIN(num_entries_to_ret, MAX_INFO_REGS_ENTRIES_PER_CALL);
46595f7f6d8SRaghu Krishnamurthy 	curr_idx = start_index + num_entries_to_ret - 1;
46695f7f6d8SRaghu Krishnamurthy 	assert(curr_idx <= max_idx);
46795f7f6d8SRaghu Krishnamurthy 
46895f7f6d8SRaghu Krishnamurthy 	ret.func = FFA_SUCCESS_SMC64;
46995f7f6d8SRaghu Krishnamurthy 	ret.arg2 = (uint64_t)((sizeof(struct ffa_partition_info_v1_1) & 0xFFFFU) << 48);
47095f7f6d8SRaghu Krishnamurthy 	ret.arg2 |= (uint64_t)(curr_idx << 16);
47195f7f6d8SRaghu Krishnamurthy 	ret.arg2 |= (uint64_t)max_idx;
47295f7f6d8SRaghu Krishnamurthy 
47395f7f6d8SRaghu Krishnamurthy 	for (uint16_t idx = start_index; idx <= curr_idx; ++idx) {
47495f7f6d8SRaghu Krishnamurthy 		spmd_pack_lp_count_props(arg_ptrs, partitions[idx].ep_id,
47595f7f6d8SRaghu Krishnamurthy 					 partitions[idx].execution_ctx_count,
47695f7f6d8SRaghu Krishnamurthy 					 partitions[idx].properties);
47795f7f6d8SRaghu Krishnamurthy 		arg_ptrs++;
47895f7f6d8SRaghu Krishnamurthy 		if (is_null_uuid(target_uuid)) {
47995f7f6d8SRaghu Krishnamurthy 			spmd_pack_lp_uuid(arg_ptrs, (arg_ptrs + 1),
48095f7f6d8SRaghu Krishnamurthy 					  partitions[idx].uuid);
48195f7f6d8SRaghu Krishnamurthy 		}
48295f7f6d8SRaghu Krishnamurthy 		arg_ptrs += 2;
48395f7f6d8SRaghu Krishnamurthy 	}
48495f7f6d8SRaghu Krishnamurthy 
48595f7f6d8SRaghu Krishnamurthy 	SMC_RET18(handle, ret.func, ret.arg1, ret.arg2, ret.arg3, ret.arg4,
48695f7f6d8SRaghu Krishnamurthy 		  ret.arg5, ret.arg6, ret.arg7, ret.arg8, ret.arg9, ret.arg10,
48795f7f6d8SRaghu Krishnamurthy 		  ret.arg11, ret.arg12, ret.arg13, ret.arg14, ret.arg15,
48895f7f6d8SRaghu Krishnamurthy 		  ret.arg16, ret.arg17);
48995f7f6d8SRaghu Krishnamurthy #else
49095f7f6d8SRaghu Krishnamurthy 	return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
49195f7f6d8SRaghu Krishnamurthy #endif
49295f7f6d8SRaghu Krishnamurthy }
49395f7f6d8SRaghu Krishnamurthy 
49495f7f6d8SRaghu 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  */
spmd_el3_invoke_partition_info_get(const uint32_t target_uuid[4],const uint16_t start_index,const uint16_t tag,struct ffa_value * retval)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 #if SPMD_SPM_AT_SEL2
5320b850e9eSRaghu Krishnamurthy 	cm_el2_sysregs_context_save(NON_SECURE);
5332d960a11SMadhukar Pappireddy #else
5342d960a11SMadhukar Pappireddy 	cm_el1_sysregs_context_save(NON_SECURE);
5350b850e9eSRaghu Krishnamurthy #endif
5360b850e9eSRaghu Krishnamurthy 
5370b850e9eSRaghu Krishnamurthy 	spmd_build_ffa_info_get_regs(ctx, target_uuid, start_index, tag);
5380b850e9eSRaghu Krishnamurthy 	spmd_logical_sp_set_info_regs_ongoing(ctx);
5390b850e9eSRaghu Krishnamurthy 
5400b850e9eSRaghu Krishnamurthy 	rc = spmd_spm_core_sync_entry(ctx);
5410b850e9eSRaghu Krishnamurthy 	if (rc != 0ULL) {
5420b850e9eSRaghu Krishnamurthy 		ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
5430b850e9eSRaghu Krishnamurthy 		      plat_my_core_pos());
5440b850e9eSRaghu Krishnamurthy 		panic();
5450b850e9eSRaghu Krishnamurthy 	}
5460b850e9eSRaghu Krishnamurthy 
5470b850e9eSRaghu Krishnamurthy 	spmd_logical_sp_reset_info_regs_ongoing(ctx);
5480b850e9eSRaghu Krishnamurthy 	spmd_encode_ctx_to_ffa_value(ctx, retval);
5490b850e9eSRaghu Krishnamurthy 
5500b850e9eSRaghu Krishnamurthy 	assert(is_ffa_error(retval) || is_ffa_success(retval));
5510b850e9eSRaghu Krishnamurthy 
5520b850e9eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
5530b850e9eSRaghu Krishnamurthy 	cm_el2_sysregs_context_restore(NON_SECURE);
5542d960a11SMadhukar Pappireddy #else
5552d960a11SMadhukar Pappireddy 	cm_el1_sysregs_context_restore(NON_SECURE);
5560b850e9eSRaghu Krishnamurthy #endif
5570b850e9eSRaghu Krishnamurthy 	cm_set_next_eret_context(NON_SECURE);
5580b850e9eSRaghu Krishnamurthy 	return true;
5590b850e9eSRaghu Krishnamurthy #else
5600b850e9eSRaghu Krishnamurthy 	return false;
5610b850e9eSRaghu Krishnamurthy #endif
5620b850e9eSRaghu Krishnamurthy }
5630b850e9eSRaghu Krishnamurthy 
56466bdfd6eSRaghu Krishnamurthy /*******************************************************************************
56566bdfd6eSRaghu Krishnamurthy  * This function sends an FF-A Direct Request from a partition in EL3 to a
56666bdfd6eSRaghu Krishnamurthy  * partition that may reside under an SPMC (only lower ELs supported). The main
56766bdfd6eSRaghu Krishnamurthy  * use of this API is for SPMD logical partitions.
56866bdfd6eSRaghu Krishnamurthy  * The API is expected to be used when there are platform specific SMCs that
56966bdfd6eSRaghu Krishnamurthy  * need to be routed to a secure partition that is FF-A compliant or when
57066bdfd6eSRaghu Krishnamurthy  * there are group 0 interrupts that need to be handled first in EL3 and then
57166bdfd6eSRaghu Krishnamurthy  * forwarded to an FF-A compliant secure partition. Therefore, it is expected
57266bdfd6eSRaghu Krishnamurthy  * that the handle to the context provided belongs to the non-secure context.
57366bdfd6eSRaghu Krishnamurthy  * This also means that interrupts/SMCs that trap to EL3 during secure execution
57466bdfd6eSRaghu Krishnamurthy  * cannot use this API.
57566bdfd6eSRaghu Krishnamurthy  * x1, x2, x3 and x4 are encoded as specified in the FF-A specification.
57666bdfd6eSRaghu Krishnamurthy  * retval is used to pass the direct response values to the caller.
57766bdfd6eSRaghu Krishnamurthy  * The function returns true if retval has valid values, and false otherwise.
57866bdfd6eSRaghu Krishnamurthy  ******************************************************************************/
spmd_el3_ffa_msg_direct_req(uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * handle,struct ffa_value * retval)57966bdfd6eSRaghu Krishnamurthy bool spmd_el3_ffa_msg_direct_req(uint64_t x1,
58066bdfd6eSRaghu Krishnamurthy 				 uint64_t x2,
58166bdfd6eSRaghu Krishnamurthy 				 uint64_t x3,
58266bdfd6eSRaghu Krishnamurthy 				 uint64_t x4,
58366bdfd6eSRaghu Krishnamurthy 				 void *handle,
58466bdfd6eSRaghu Krishnamurthy 				 struct ffa_value *retval)
58566bdfd6eSRaghu Krishnamurthy {
58666bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
58766bdfd6eSRaghu Krishnamurthy 
58866bdfd6eSRaghu Krishnamurthy 	uint64_t rc = UINT64_MAX;
58966bdfd6eSRaghu Krishnamurthy 	spmd_spm_core_context_t *ctx = spmd_get_context();
59066bdfd6eSRaghu Krishnamurthy 
59166bdfd6eSRaghu Krishnamurthy 	if (retval == NULL) {
59266bdfd6eSRaghu Krishnamurthy 		return false;
59366bdfd6eSRaghu Krishnamurthy 	}
59466bdfd6eSRaghu Krishnamurthy 
59566bdfd6eSRaghu Krishnamurthy 	memset(retval, 0, sizeof(*retval));
59666bdfd6eSRaghu Krishnamurthy 
59766bdfd6eSRaghu Krishnamurthy 	if (!is_spmd_lp_inited || !is_spmc_inited) {
59866bdfd6eSRaghu Krishnamurthy 		VERBOSE("Cannot send SPMD logical partition direct message,"
59966bdfd6eSRaghu Krishnamurthy 			" Partitions not initialized or SPMC not initialized.\n");
60066bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
60166bdfd6eSRaghu Krishnamurthy 		return true;
60266bdfd6eSRaghu Krishnamurthy 	}
60366bdfd6eSRaghu Krishnamurthy 
60466bdfd6eSRaghu Krishnamurthy 	/*
60566bdfd6eSRaghu Krishnamurthy 	 * x2 must be zero, since there is no support for framework message via
60666bdfd6eSRaghu Krishnamurthy 	 * an SPMD logical partition. This is sort of a useless check and it is
60766bdfd6eSRaghu Krishnamurthy 	 * possible to not take parameter. However, as the framework extends it
60866bdfd6eSRaghu Krishnamurthy 	 * may be useful to have x2 and extend this function later with
60966bdfd6eSRaghu Krishnamurthy 	 * functionality based on x2.
61066bdfd6eSRaghu Krishnamurthy 	 */
61166bdfd6eSRaghu Krishnamurthy 	if (x2 != 0) {
61266bdfd6eSRaghu Krishnamurthy 		VERBOSE("x2 must be zero. Cannot send framework message.\n");
61366bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
61466bdfd6eSRaghu Krishnamurthy 		return true;
61566bdfd6eSRaghu Krishnamurthy 	}
61666bdfd6eSRaghu Krishnamurthy 
61766bdfd6eSRaghu Krishnamurthy 	/*
61866bdfd6eSRaghu Krishnamurthy 	 * Current context must be non-secure. API is expected to be used
61966bdfd6eSRaghu Krishnamurthy 	 * when entry into EL3 and the SPMD logical partition is via an
62066bdfd6eSRaghu Krishnamurthy 	 * interrupt that occurs when execution is in normal world and
62166bdfd6eSRaghu Krishnamurthy 	 * SMCs from normal world. FF-A compliant SPMCs are expected to
62266bdfd6eSRaghu Krishnamurthy 	 * trap interrupts during secure execution in lower ELs since they
62366bdfd6eSRaghu Krishnamurthy 	 * are usually not re-entrant and SMCs from secure world can be
62466bdfd6eSRaghu Krishnamurthy 	 * handled synchronously. There is no known use case for an SPMD
62566bdfd6eSRaghu Krishnamurthy 	 * logical partition to send a direct message to another partition
62666bdfd6eSRaghu Krishnamurthy 	 * in response to a secure interrupt or SMCs from secure world.
62766bdfd6eSRaghu Krishnamurthy 	 */
62866bdfd6eSRaghu Krishnamurthy 	if (handle != cm_get_context(NON_SECURE)) {
62966bdfd6eSRaghu Krishnamurthy 		VERBOSE("Handle must be for the non-secure context.\n");
63066bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
63166bdfd6eSRaghu Krishnamurthy 		return true;
63266bdfd6eSRaghu Krishnamurthy 	}
63366bdfd6eSRaghu Krishnamurthy 
63466bdfd6eSRaghu Krishnamurthy 	if (!is_spmd_lp_id(ffa_endpoint_source(x1))) {
63566bdfd6eSRaghu Krishnamurthy 		VERBOSE("Source ID must be valid SPMD logical partition"
63666bdfd6eSRaghu Krishnamurthy 			" ID.\n");
63766bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
63866bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
63966bdfd6eSRaghu Krishnamurthy 		return true;
64066bdfd6eSRaghu Krishnamurthy 	}
64166bdfd6eSRaghu Krishnamurthy 
64266bdfd6eSRaghu Krishnamurthy 	if (is_spmd_lp_id(ffa_endpoint_destination(x1))) {
64366bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMD logical partition"
64466bdfd6eSRaghu Krishnamurthy 			" ID.\n");
64566bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
64666bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
64766bdfd6eSRaghu Krishnamurthy 		return true;
64866bdfd6eSRaghu Krishnamurthy 	}
64966bdfd6eSRaghu Krishnamurthy 
65066bdfd6eSRaghu Krishnamurthy 	if (!ffa_is_secure_world_id(ffa_endpoint_destination(x1))) {
65166bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must be secure world ID.\n");
65266bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
65366bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
65466bdfd6eSRaghu Krishnamurthy 		return true;
65566bdfd6eSRaghu Krishnamurthy 	}
65666bdfd6eSRaghu Krishnamurthy 
65766bdfd6eSRaghu Krishnamurthy 	if (ffa_endpoint_destination(x1) == SPMD_DIRECT_MSG_ENDPOINT_ID) {
65866bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMD ID.\n");
65966bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
66066bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
66166bdfd6eSRaghu Krishnamurthy 		return true;
66266bdfd6eSRaghu Krishnamurthy 	}
66366bdfd6eSRaghu Krishnamurthy 
66466bdfd6eSRaghu Krishnamurthy 	if (ffa_endpoint_destination(x1) == spmd_spmc_id_get()) {
66566bdfd6eSRaghu Krishnamurthy 		VERBOSE("Destination ID must not be SPMC ID.\n");
66666bdfd6eSRaghu Krishnamurthy 			spmd_encode_ffa_error(retval,
66766bdfd6eSRaghu Krishnamurthy 					      FFA_ERROR_INVALID_PARAMETER);
66866bdfd6eSRaghu Krishnamurthy 		return true;
66966bdfd6eSRaghu Krishnamurthy 	}
67066bdfd6eSRaghu Krishnamurthy 
67166bdfd6eSRaghu Krishnamurthy 	/* Save the non-secure context before entering SPMC */
67266bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
67366bdfd6eSRaghu Krishnamurthy 	cm_el2_sysregs_context_save(NON_SECURE);
6742d960a11SMadhukar Pappireddy #else
6752d960a11SMadhukar Pappireddy 	cm_el1_sysregs_context_save(NON_SECURE);
67666bdfd6eSRaghu Krishnamurthy #endif
67766bdfd6eSRaghu Krishnamurthy 
67866bdfd6eSRaghu Krishnamurthy 	/*
67966bdfd6eSRaghu Krishnamurthy 	 * Perform synchronous entry into the SPMC. Synchronous entry is
68066bdfd6eSRaghu Krishnamurthy 	 * required because the spec requires that a direct message request
68166bdfd6eSRaghu Krishnamurthy 	 * from an SPMD LP look like a function call from it's perspective.
68266bdfd6eSRaghu Krishnamurthy 	 */
68366bdfd6eSRaghu Krishnamurthy 	spmd_build_direct_message_req(ctx, x1, x2, x3, x4);
68466bdfd6eSRaghu Krishnamurthy 	spmd_logical_sp_set_dir_req_ongoing(ctx);
68566bdfd6eSRaghu Krishnamurthy 
68666bdfd6eSRaghu Krishnamurthy 	rc = spmd_spm_core_sync_entry(ctx);
68766bdfd6eSRaghu Krishnamurthy 
68866bdfd6eSRaghu Krishnamurthy 	spmd_logical_sp_reset_dir_req_ongoing(ctx);
68966bdfd6eSRaghu Krishnamurthy 
69066bdfd6eSRaghu Krishnamurthy 	if (rc != 0ULL) {
69166bdfd6eSRaghu Krishnamurthy 		ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
69266bdfd6eSRaghu Krishnamurthy 		      plat_my_core_pos());
69366bdfd6eSRaghu Krishnamurthy 		panic();
69466bdfd6eSRaghu Krishnamurthy 	} else {
69566bdfd6eSRaghu Krishnamurthy 		spmd_encode_ctx_to_ffa_value(ctx, retval);
69666bdfd6eSRaghu Krishnamurthy 
69766bdfd6eSRaghu Krishnamurthy 		/*
69866bdfd6eSRaghu Krishnamurthy 		 * Only expect error or direct response,
69966bdfd6eSRaghu Krishnamurthy 		 * spmd_spm_core_sync_exit should not be called on other paths.
70066bdfd6eSRaghu Krishnamurthy 		 * Checks are asserts since the LSP can fail gracefully if the
70166bdfd6eSRaghu Krishnamurthy 		 * source or destination ids are not the same. Panic'ing would
70266bdfd6eSRaghu Krishnamurthy 		 * not provide any benefit.
70366bdfd6eSRaghu Krishnamurthy 		 */
70466bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) || is_ffa_direct_msg_resp(retval));
70566bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) ||
70666bdfd6eSRaghu Krishnamurthy 			(ffa_endpoint_destination(retval->arg1) ==
70766bdfd6eSRaghu Krishnamurthy 				ffa_endpoint_source(x1)));
70866bdfd6eSRaghu Krishnamurthy 		assert(is_ffa_error(retval) ||
70966bdfd6eSRaghu Krishnamurthy 			(ffa_endpoint_source(retval->arg1) ==
71066bdfd6eSRaghu Krishnamurthy 				ffa_endpoint_destination(x1)));
71166bdfd6eSRaghu Krishnamurthy 	}
71266bdfd6eSRaghu Krishnamurthy 
71366bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2
71466bdfd6eSRaghu Krishnamurthy 	cm_el2_sysregs_context_restore(NON_SECURE);
7152d960a11SMadhukar Pappireddy #else
7162d960a11SMadhukar Pappireddy 	cm_el1_sysregs_context_restore(NON_SECURE);
71766bdfd6eSRaghu Krishnamurthy #endif
71866bdfd6eSRaghu Krishnamurthy 	cm_set_next_eret_context(NON_SECURE);
71966bdfd6eSRaghu Krishnamurthy 
72066bdfd6eSRaghu Krishnamurthy 	return true;
72166bdfd6eSRaghu Krishnamurthy #else
72266bdfd6eSRaghu Krishnamurthy 	return false;
72366bdfd6eSRaghu Krishnamurthy #endif
72466bdfd6eSRaghu Krishnamurthy }
72566bdfd6eSRaghu Krishnamurthy 
726*a869e2dcSSudeep Holla bool
is_spmd_logical_sp_info_regs_req_in_progress(const spmd_spm_core_context_t * ctx)727*a869e2dcSSudeep Holla is_spmd_logical_sp_info_regs_req_in_progress(const spmd_spm_core_context_t *ctx)
7280b850e9eSRaghu Krishnamurthy {
7290b850e9eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
7300b850e9eSRaghu Krishnamurthy 	return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_INFO_GET_REG_ONGOING)
7310b850e9eSRaghu Krishnamurthy 			== SPMD_LP_FFA_INFO_GET_REG_ONGOING);
7320b850e9eSRaghu Krishnamurthy #else
7330b850e9eSRaghu Krishnamurthy 	return false;
7340b850e9eSRaghu Krishnamurthy #endif
7350b850e9eSRaghu Krishnamurthy }
7360b850e9eSRaghu Krishnamurthy 
is_spmd_logical_sp_dir_req_in_progress(const spmd_spm_core_context_t * ctx)737*a869e2dcSSudeep Holla bool is_spmd_logical_sp_dir_req_in_progress(const spmd_spm_core_context_t *ctx)
73866bdfd6eSRaghu Krishnamurthy {
73966bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP
74066bdfd6eSRaghu Krishnamurthy 	return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING)
74166bdfd6eSRaghu Krishnamurthy 		== SPMD_LP_FFA_DIR_REQ_ONGOING);
74266bdfd6eSRaghu Krishnamurthy #else
74366bdfd6eSRaghu Krishnamurthy 	return false;
74466bdfd6eSRaghu Krishnamurthy #endif
74566bdfd6eSRaghu Krishnamurthy }
746