1890b5088SRaghu Krishnamurthy /* 2*2d960a11SMadhukar 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 */ 40890b5088SRaghu Krishnamurthy static struct spmd_lp_desc *get_spmd_el3_lp_array(void) 41890b5088SRaghu Krishnamurthy { 42890b5088SRaghu Krishnamurthy return (struct spmd_lp_desc *) SPMD_LP_DESCS_START; 43890b5088SRaghu Krishnamurthy } 44890b5088SRaghu Krishnamurthy 45890b5088SRaghu Krishnamurthy /******************************************************************************* 46890b5088SRaghu Krishnamurthy * Validate any logical partition descriptors before we initialize. 47890b5088SRaghu Krishnamurthy * Initialization of said partitions will be taken care of during SPMD boot. 48890b5088SRaghu Krishnamurthy ******************************************************************************/ 49890b5088SRaghu Krishnamurthy static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array) 50890b5088SRaghu Krishnamurthy { 51890b5088SRaghu Krishnamurthy /* Check the array bounds are valid. */ 52890b5088SRaghu Krishnamurthy assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START); 53890b5088SRaghu Krishnamurthy 5466bdfd6eSRaghu Krishnamurthy /* 5566bdfd6eSRaghu Krishnamurthy * No support for SPMD logical partitions when SPMC is at EL3. 5666bdfd6eSRaghu Krishnamurthy */ 5766bdfd6eSRaghu Krishnamurthy assert(!is_spmc_at_el3()); 5866bdfd6eSRaghu Krishnamurthy 59890b5088SRaghu Krishnamurthy /* If no SPMD logical partitions are implemented then simply bail out. */ 60890b5088SRaghu Krishnamurthy if (SPMD_LP_DESCS_COUNT == 0U) { 61890b5088SRaghu Krishnamurthy return -1; 62890b5088SRaghu Krishnamurthy } 63890b5088SRaghu Krishnamurthy 64890b5088SRaghu Krishnamurthy for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) { 65890b5088SRaghu Krishnamurthy struct spmd_lp_desc *lp_desc = &lp_array[index]; 66890b5088SRaghu Krishnamurthy 67890b5088SRaghu Krishnamurthy /* Validate our logical partition descriptors. */ 68890b5088SRaghu Krishnamurthy if (lp_desc == NULL) { 69890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical SP Descriptor\n"); 70890b5088SRaghu Krishnamurthy return -EINVAL; 71890b5088SRaghu Krishnamurthy } 72890b5088SRaghu Krishnamurthy 73890b5088SRaghu Krishnamurthy /* 74890b5088SRaghu Krishnamurthy * Ensure the ID follows the convention to indicate it resides 75890b5088SRaghu Krishnamurthy * in the secure world. 76890b5088SRaghu Krishnamurthy */ 77890b5088SRaghu Krishnamurthy if (!ffa_is_secure_world_id(lp_desc->sp_id)) { 78890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical SP ID (0x%x)\n", 79890b5088SRaghu Krishnamurthy lp_desc->sp_id); 80890b5088SRaghu Krishnamurthy return -EINVAL; 81890b5088SRaghu Krishnamurthy } 82890b5088SRaghu Krishnamurthy 83890b5088SRaghu Krishnamurthy /* Ensure SPMD logical partition is in valid range. */ 84890b5088SRaghu Krishnamurthy if (!is_spmd_lp_id(lp_desc->sp_id)) { 85890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", 86890b5088SRaghu Krishnamurthy lp_desc->sp_id); 87890b5088SRaghu Krishnamurthy return -EINVAL; 88890b5088SRaghu Krishnamurthy } 89890b5088SRaghu Krishnamurthy 90890b5088SRaghu Krishnamurthy /* Ensure the UUID is not the NULL UUID. */ 91890b5088SRaghu Krishnamurthy if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 && 92890b5088SRaghu Krishnamurthy lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) { 93890b5088SRaghu Krishnamurthy ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n", 94890b5088SRaghu Krishnamurthy lp_desc->sp_id); 95890b5088SRaghu Krishnamurthy return -EINVAL; 96890b5088SRaghu Krishnamurthy } 97890b5088SRaghu Krishnamurthy 98890b5088SRaghu Krishnamurthy /* Ensure init function callback is registered. */ 99890b5088SRaghu Krishnamurthy if (lp_desc->init == NULL) { 100890b5088SRaghu Krishnamurthy ERROR("Missing init function for Logical SP(0x%x)\n", 101890b5088SRaghu Krishnamurthy lp_desc->sp_id); 102890b5088SRaghu Krishnamurthy return -EINVAL; 103890b5088SRaghu Krishnamurthy } 104890b5088SRaghu Krishnamurthy 105890b5088SRaghu Krishnamurthy /* Ensure that SPMD LP only supports sending direct requests. */ 106890b5088SRaghu Krishnamurthy if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) { 107890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD logical partition properties (0x%x)\n", 108890b5088SRaghu Krishnamurthy lp_desc->properties); 109890b5088SRaghu Krishnamurthy return -EINVAL; 110890b5088SRaghu Krishnamurthy } 111890b5088SRaghu Krishnamurthy 112890b5088SRaghu Krishnamurthy /* Ensure that all partition IDs are unique. */ 113890b5088SRaghu Krishnamurthy for (uint32_t inner_idx = index + 1; 114890b5088SRaghu Krishnamurthy inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) { 115890b5088SRaghu Krishnamurthy if (lp_desc->sp_id == lp_array[inner_idx].sp_id) { 116890b5088SRaghu Krishnamurthy ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n", 117890b5088SRaghu Krishnamurthy lp_desc->sp_id); 118890b5088SRaghu Krishnamurthy return -EINVAL; 119890b5088SRaghu Krishnamurthy } 120890b5088SRaghu Krishnamurthy } 121890b5088SRaghu Krishnamurthy } 122890b5088SRaghu Krishnamurthy return 0; 123890b5088SRaghu Krishnamurthy } 12466bdfd6eSRaghu Krishnamurthy 12566bdfd6eSRaghu Krishnamurthy static void spmd_encode_ffa_error(struct ffa_value *retval, int32_t error_code) 12666bdfd6eSRaghu Krishnamurthy { 12766bdfd6eSRaghu Krishnamurthy retval->func = FFA_ERROR; 12866bdfd6eSRaghu Krishnamurthy retval->arg1 = FFA_TARGET_INFO_MBZ; 12966bdfd6eSRaghu Krishnamurthy retval->arg2 = (uint32_t)error_code; 13066bdfd6eSRaghu Krishnamurthy retval->arg3 = FFA_TARGET_INFO_MBZ; 13166bdfd6eSRaghu Krishnamurthy retval->arg4 = FFA_TARGET_INFO_MBZ; 13266bdfd6eSRaghu Krishnamurthy retval->arg5 = FFA_TARGET_INFO_MBZ; 13366bdfd6eSRaghu Krishnamurthy retval->arg6 = FFA_TARGET_INFO_MBZ; 13466bdfd6eSRaghu Krishnamurthy retval->arg7 = FFA_TARGET_INFO_MBZ; 13566bdfd6eSRaghu Krishnamurthy } 13666bdfd6eSRaghu Krishnamurthy 13766bdfd6eSRaghu Krishnamurthy static void spmd_build_direct_message_req(spmd_spm_core_context_t *ctx, 13866bdfd6eSRaghu Krishnamurthy uint64_t x1, uint64_t x2, 13966bdfd6eSRaghu Krishnamurthy uint64_t x3, uint64_t x4) 14066bdfd6eSRaghu Krishnamurthy { 14166bdfd6eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 14266bdfd6eSRaghu Krishnamurthy 14366bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32); 14466bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X1, x1); 14566bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X2, x2); 14666bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X3, x3); 14766bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X4, x4); 14866bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); 14966bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); 15066bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); 15166bdfd6eSRaghu Krishnamurthy } 15266bdfd6eSRaghu Krishnamurthy 15366bdfd6eSRaghu Krishnamurthy static void spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t *ctx, 15466bdfd6eSRaghu Krishnamurthy struct ffa_value *retval) 15566bdfd6eSRaghu Krishnamurthy { 15666bdfd6eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 15766bdfd6eSRaghu Krishnamurthy 15866bdfd6eSRaghu Krishnamurthy retval->func = read_ctx_reg(gpregs, CTX_GPREG_X0); 15966bdfd6eSRaghu Krishnamurthy retval->arg1 = read_ctx_reg(gpregs, CTX_GPREG_X1); 16066bdfd6eSRaghu Krishnamurthy retval->arg2 = read_ctx_reg(gpregs, CTX_GPREG_X2); 16166bdfd6eSRaghu Krishnamurthy retval->arg3 = read_ctx_reg(gpregs, CTX_GPREG_X3); 16266bdfd6eSRaghu Krishnamurthy retval->arg4 = read_ctx_reg(gpregs, CTX_GPREG_X4); 16366bdfd6eSRaghu Krishnamurthy retval->arg5 = read_ctx_reg(gpregs, CTX_GPREG_X5); 16466bdfd6eSRaghu Krishnamurthy retval->arg6 = read_ctx_reg(gpregs, CTX_GPREG_X6); 16566bdfd6eSRaghu Krishnamurthy retval->arg7 = read_ctx_reg(gpregs, CTX_GPREG_X7); 1660b850e9eSRaghu Krishnamurthy retval->arg8 = read_ctx_reg(gpregs, CTX_GPREG_X8); 1670b850e9eSRaghu Krishnamurthy retval->arg9 = read_ctx_reg(gpregs, CTX_GPREG_X9); 1680b850e9eSRaghu Krishnamurthy retval->arg10 = read_ctx_reg(gpregs, CTX_GPREG_X10); 1690b850e9eSRaghu Krishnamurthy retval->arg11 = read_ctx_reg(gpregs, CTX_GPREG_X11); 1700b850e9eSRaghu Krishnamurthy retval->arg12 = read_ctx_reg(gpregs, CTX_GPREG_X12); 1710b850e9eSRaghu Krishnamurthy retval->arg13 = read_ctx_reg(gpregs, CTX_GPREG_X13); 1720b850e9eSRaghu Krishnamurthy retval->arg14 = read_ctx_reg(gpregs, CTX_GPREG_X14); 1730b850e9eSRaghu Krishnamurthy retval->arg15 = read_ctx_reg(gpregs, CTX_GPREG_X15); 1740b850e9eSRaghu Krishnamurthy retval->arg16 = read_ctx_reg(gpregs, CTX_GPREG_X16); 1750b850e9eSRaghu Krishnamurthy retval->arg17 = read_ctx_reg(gpregs, CTX_GPREG_X17); 17666bdfd6eSRaghu Krishnamurthy } 17766bdfd6eSRaghu Krishnamurthy 17866bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t *ctx) 17966bdfd6eSRaghu Krishnamurthy { 18066bdfd6eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_DIR_REQ_ONGOING; 18166bdfd6eSRaghu Krishnamurthy } 18266bdfd6eSRaghu Krishnamurthy 18366bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t *ctx) 18466bdfd6eSRaghu Krishnamurthy { 18566bdfd6eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_DIR_REQ_ONGOING; 18666bdfd6eSRaghu Krishnamurthy } 18766bdfd6eSRaghu Krishnamurthy 1880b850e9eSRaghu Krishnamurthy static void spmd_build_ffa_info_get_regs(spmd_spm_core_context_t *ctx, 1890b850e9eSRaghu Krishnamurthy const uint32_t uuid[4], 1900b850e9eSRaghu Krishnamurthy const uint16_t start_index, 1910b850e9eSRaghu Krishnamurthy const uint16_t tag) 1920b850e9eSRaghu Krishnamurthy { 1930b850e9eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 1940b850e9eSRaghu Krishnamurthy 1950b850e9eSRaghu Krishnamurthy uint64_t arg1 = (uint64_t)uuid[1] << 32 | uuid[0]; 1960b850e9eSRaghu Krishnamurthy uint64_t arg2 = (uint64_t)uuid[3] << 32 | uuid[2]; 1970b850e9eSRaghu Krishnamurthy uint64_t arg3 = start_index | (uint64_t)tag << 16; 1980b850e9eSRaghu Krishnamurthy 1990b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_PARTITION_INFO_GET_REGS_SMC64); 2000b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X1, arg1); 2010b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X2, arg2); 2020b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X3, arg3); 2030b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X4, 0U); 2040b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); 2050b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); 2060b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); 2070b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X8, 0U); 2080b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X9, 0U); 2090b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X10, 0U); 2100b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X11, 0U); 2110b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X12, 0U); 2120b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X13, 0U); 2130b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X14, 0U); 2140b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X15, 0U); 2150b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X16, 0U); 2160b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X17, 0U); 2170b850e9eSRaghu Krishnamurthy } 2180b850e9eSRaghu Krishnamurthy 2190b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t *ctx) 2200b850e9eSRaghu Krishnamurthy { 2210b850e9eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_INFO_GET_REG_ONGOING; 2220b850e9eSRaghu Krishnamurthy } 2230b850e9eSRaghu Krishnamurthy 2240b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_reset_info_regs_ongoing( 2250b850e9eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx) 2260b850e9eSRaghu Krishnamurthy { 2270b850e9eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_INFO_GET_REG_ONGOING; 2280b850e9eSRaghu Krishnamurthy } 22995f7f6d8SRaghu Krishnamurthy 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 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 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 */ 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 338890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_initialized(void) 339890b5088SRaghu Krishnamurthy { 340890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 341890b5088SRaghu Krishnamurthy is_spmc_inited = true; 342890b5088SRaghu Krishnamurthy #endif 343890b5088SRaghu Krishnamurthy } 344890b5088SRaghu Krishnamurthy 345890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_failure(void) 346890b5088SRaghu Krishnamurthy { 347890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 348890b5088SRaghu Krishnamurthy is_spmc_inited = false; 349890b5088SRaghu Krishnamurthy #endif 350890b5088SRaghu Krishnamurthy } 35166bdfd6eSRaghu Krishnamurthy 3520b850e9eSRaghu Krishnamurthy /* 3530b850e9eSRaghu Krishnamurthy * This function takes an ffa_value structure populated with partition 3540b850e9eSRaghu Krishnamurthy * information from an FFA_PARTITION_INFO_GET_REGS ABI call, extracts 3550b850e9eSRaghu Krishnamurthy * the values and writes it into a ffa_partition_info_v1_1 structure for 3560b850e9eSRaghu Krishnamurthy * other code to consume. 3570b850e9eSRaghu Krishnamurthy */ 3580b850e9eSRaghu Krishnamurthy bool ffa_partition_info_regs_get_part_info( 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 */ 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 */ 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); 533*2d960a11SMadhukar Pappireddy #else 534*2d960a11SMadhukar 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); 554*2d960a11SMadhukar Pappireddy #else 555*2d960a11SMadhukar 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 ******************************************************************************/ 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); 674*2d960a11SMadhukar Pappireddy #else 675*2d960a11SMadhukar 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); 715*2d960a11SMadhukar Pappireddy #else 716*2d960a11SMadhukar 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 7260b850e9eSRaghu Krishnamurthy bool is_spmd_logical_sp_info_regs_req_in_progress( 7270b850e9eSRaghu Krishnamurthy 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 73766bdfd6eSRaghu Krishnamurthy bool is_spmd_logical_sp_dir_req_in_progress( 73866bdfd6eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx) 73966bdfd6eSRaghu Krishnamurthy { 74066bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP 74166bdfd6eSRaghu Krishnamurthy return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING) 74266bdfd6eSRaghu Krishnamurthy == SPMD_LP_FFA_DIR_REQ_ONGOING); 74366bdfd6eSRaghu Krishnamurthy #else 74466bdfd6eSRaghu Krishnamurthy return false; 74566bdfd6eSRaghu Krishnamurthy #endif 74666bdfd6eSRaghu Krishnamurthy } 747