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