1890b5088SRaghu Krishnamurthy /* 2890b5088SRaghu Krishnamurthy * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved. 3890b5088SRaghu Krishnamurthy * 4890b5088SRaghu Krishnamurthy * SPDX-License-Identifier: BSD-3-Clause 5890b5088SRaghu Krishnamurthy */ 6890b5088SRaghu Krishnamurthy 7890b5088SRaghu Krishnamurthy #include <assert.h> 8890b5088SRaghu Krishnamurthy #include <errno.h> 9890b5088SRaghu Krishnamurthy #include <string.h> 1066bdfd6eSRaghu Krishnamurthy #include "spmd_private.h" 11890b5088SRaghu Krishnamurthy 12890b5088SRaghu Krishnamurthy #include <common/debug.h> 1366bdfd6eSRaghu Krishnamurthy #include <lib/el3_runtime/context_mgmt.h> 14890b5088SRaghu Krishnamurthy #include <services/el3_spmd_logical_sp.h> 1566bdfd6eSRaghu Krishnamurthy #include <services/spmc_svc.h> 1666bdfd6eSRaghu Krishnamurthy 17890b5088SRaghu Krishnamurthy 18890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 19890b5088SRaghu Krishnamurthy static bool is_spmd_lp_inited; 20890b5088SRaghu Krishnamurthy static bool is_spmc_inited; 21890b5088SRaghu Krishnamurthy 22890b5088SRaghu Krishnamurthy /* 23890b5088SRaghu Krishnamurthy * Helper function to obtain the array storing the EL3 24890b5088SRaghu Krishnamurthy * SPMD Logical Partition descriptors. 25890b5088SRaghu Krishnamurthy */ 26890b5088SRaghu Krishnamurthy static struct spmd_lp_desc *get_spmd_el3_lp_array(void) 27890b5088SRaghu Krishnamurthy { 28890b5088SRaghu Krishnamurthy return (struct spmd_lp_desc *) SPMD_LP_DESCS_START; 29890b5088SRaghu Krishnamurthy } 30890b5088SRaghu Krishnamurthy 31890b5088SRaghu Krishnamurthy /******************************************************************************* 32890b5088SRaghu Krishnamurthy * Validate any logical partition descriptors before we initialize. 33890b5088SRaghu Krishnamurthy * Initialization of said partitions will be taken care of during SPMD boot. 34890b5088SRaghu Krishnamurthy ******************************************************************************/ 35890b5088SRaghu Krishnamurthy static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array) 36890b5088SRaghu Krishnamurthy { 37890b5088SRaghu Krishnamurthy /* Check the array bounds are valid. */ 38890b5088SRaghu Krishnamurthy assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START); 39890b5088SRaghu Krishnamurthy 4066bdfd6eSRaghu Krishnamurthy /* 4166bdfd6eSRaghu Krishnamurthy * No support for SPMD logical partitions when SPMC is at EL3. 4266bdfd6eSRaghu Krishnamurthy */ 4366bdfd6eSRaghu Krishnamurthy assert(!is_spmc_at_el3()); 4466bdfd6eSRaghu Krishnamurthy 45890b5088SRaghu Krishnamurthy /* If no SPMD logical partitions are implemented then simply bail out. */ 46890b5088SRaghu Krishnamurthy if (SPMD_LP_DESCS_COUNT == 0U) { 47890b5088SRaghu Krishnamurthy return -1; 48890b5088SRaghu Krishnamurthy } 49890b5088SRaghu Krishnamurthy 50890b5088SRaghu Krishnamurthy for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) { 51890b5088SRaghu Krishnamurthy struct spmd_lp_desc *lp_desc = &lp_array[index]; 52890b5088SRaghu Krishnamurthy 53890b5088SRaghu Krishnamurthy /* Validate our logical partition descriptors. */ 54890b5088SRaghu Krishnamurthy if (lp_desc == NULL) { 55890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical SP Descriptor\n"); 56890b5088SRaghu Krishnamurthy return -EINVAL; 57890b5088SRaghu Krishnamurthy } 58890b5088SRaghu Krishnamurthy 59890b5088SRaghu Krishnamurthy /* 60890b5088SRaghu Krishnamurthy * Ensure the ID follows the convention to indicate it resides 61890b5088SRaghu Krishnamurthy * in the secure world. 62890b5088SRaghu Krishnamurthy */ 63890b5088SRaghu Krishnamurthy if (!ffa_is_secure_world_id(lp_desc->sp_id)) { 64890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical SP ID (0x%x)\n", 65890b5088SRaghu Krishnamurthy lp_desc->sp_id); 66890b5088SRaghu Krishnamurthy return -EINVAL; 67890b5088SRaghu Krishnamurthy } 68890b5088SRaghu Krishnamurthy 69890b5088SRaghu Krishnamurthy /* Ensure SPMD logical partition is in valid range. */ 70890b5088SRaghu Krishnamurthy if (!is_spmd_lp_id(lp_desc->sp_id)) { 71890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", 72890b5088SRaghu Krishnamurthy lp_desc->sp_id); 73890b5088SRaghu Krishnamurthy return -EINVAL; 74890b5088SRaghu Krishnamurthy } 75890b5088SRaghu Krishnamurthy 76890b5088SRaghu Krishnamurthy /* Ensure the UUID is not the NULL UUID. */ 77890b5088SRaghu Krishnamurthy if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 && 78890b5088SRaghu Krishnamurthy lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) { 79890b5088SRaghu Krishnamurthy ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n", 80890b5088SRaghu Krishnamurthy lp_desc->sp_id); 81890b5088SRaghu Krishnamurthy return -EINVAL; 82890b5088SRaghu Krishnamurthy } 83890b5088SRaghu Krishnamurthy 84890b5088SRaghu Krishnamurthy /* Ensure init function callback is registered. */ 85890b5088SRaghu Krishnamurthy if (lp_desc->init == NULL) { 86890b5088SRaghu Krishnamurthy ERROR("Missing init function for Logical SP(0x%x)\n", 87890b5088SRaghu Krishnamurthy lp_desc->sp_id); 88890b5088SRaghu Krishnamurthy return -EINVAL; 89890b5088SRaghu Krishnamurthy } 90890b5088SRaghu Krishnamurthy 91890b5088SRaghu Krishnamurthy /* Ensure that SPMD LP only supports sending direct requests. */ 92890b5088SRaghu Krishnamurthy if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) { 93890b5088SRaghu Krishnamurthy ERROR("Invalid SPMD logical partition properties (0x%x)\n", 94890b5088SRaghu Krishnamurthy lp_desc->properties); 95890b5088SRaghu Krishnamurthy return -EINVAL; 96890b5088SRaghu Krishnamurthy } 97890b5088SRaghu Krishnamurthy 98890b5088SRaghu Krishnamurthy /* Ensure that all partition IDs are unique. */ 99890b5088SRaghu Krishnamurthy for (uint32_t inner_idx = index + 1; 100890b5088SRaghu Krishnamurthy inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) { 101890b5088SRaghu Krishnamurthy if (lp_desc->sp_id == lp_array[inner_idx].sp_id) { 102890b5088SRaghu Krishnamurthy ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n", 103890b5088SRaghu Krishnamurthy lp_desc->sp_id); 104890b5088SRaghu Krishnamurthy return -EINVAL; 105890b5088SRaghu Krishnamurthy } 106890b5088SRaghu Krishnamurthy } 107890b5088SRaghu Krishnamurthy } 108890b5088SRaghu Krishnamurthy return 0; 109890b5088SRaghu Krishnamurthy } 11066bdfd6eSRaghu Krishnamurthy 11166bdfd6eSRaghu Krishnamurthy static void spmd_encode_ffa_error(struct ffa_value *retval, int32_t error_code) 11266bdfd6eSRaghu Krishnamurthy { 11366bdfd6eSRaghu Krishnamurthy retval->func = FFA_ERROR; 11466bdfd6eSRaghu Krishnamurthy retval->arg1 = FFA_TARGET_INFO_MBZ; 11566bdfd6eSRaghu Krishnamurthy retval->arg2 = (uint32_t)error_code; 11666bdfd6eSRaghu Krishnamurthy retval->arg3 = FFA_TARGET_INFO_MBZ; 11766bdfd6eSRaghu Krishnamurthy retval->arg4 = FFA_TARGET_INFO_MBZ; 11866bdfd6eSRaghu Krishnamurthy retval->arg5 = FFA_TARGET_INFO_MBZ; 11966bdfd6eSRaghu Krishnamurthy retval->arg6 = FFA_TARGET_INFO_MBZ; 12066bdfd6eSRaghu Krishnamurthy retval->arg7 = FFA_TARGET_INFO_MBZ; 12166bdfd6eSRaghu Krishnamurthy } 12266bdfd6eSRaghu Krishnamurthy 12366bdfd6eSRaghu Krishnamurthy static void spmd_build_direct_message_req(spmd_spm_core_context_t *ctx, 12466bdfd6eSRaghu Krishnamurthy uint64_t x1, uint64_t x2, 12566bdfd6eSRaghu Krishnamurthy uint64_t x3, uint64_t x4) 12666bdfd6eSRaghu Krishnamurthy { 12766bdfd6eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 12866bdfd6eSRaghu Krishnamurthy 12966bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32); 13066bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X1, x1); 13166bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X2, x2); 13266bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X3, x3); 13366bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X4, x4); 13466bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); 13566bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); 13666bdfd6eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); 13766bdfd6eSRaghu Krishnamurthy } 13866bdfd6eSRaghu Krishnamurthy 13966bdfd6eSRaghu Krishnamurthy static void spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t *ctx, 14066bdfd6eSRaghu Krishnamurthy struct ffa_value *retval) 14166bdfd6eSRaghu Krishnamurthy { 14266bdfd6eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 14366bdfd6eSRaghu Krishnamurthy 14466bdfd6eSRaghu Krishnamurthy retval->func = read_ctx_reg(gpregs, CTX_GPREG_X0); 14566bdfd6eSRaghu Krishnamurthy retval->arg1 = read_ctx_reg(gpregs, CTX_GPREG_X1); 14666bdfd6eSRaghu Krishnamurthy retval->arg2 = read_ctx_reg(gpregs, CTX_GPREG_X2); 14766bdfd6eSRaghu Krishnamurthy retval->arg3 = read_ctx_reg(gpregs, CTX_GPREG_X3); 14866bdfd6eSRaghu Krishnamurthy retval->arg4 = read_ctx_reg(gpregs, CTX_GPREG_X4); 14966bdfd6eSRaghu Krishnamurthy retval->arg5 = read_ctx_reg(gpregs, CTX_GPREG_X5); 15066bdfd6eSRaghu Krishnamurthy retval->arg6 = read_ctx_reg(gpregs, CTX_GPREG_X6); 15166bdfd6eSRaghu Krishnamurthy retval->arg7 = read_ctx_reg(gpregs, CTX_GPREG_X7); 152*0b850e9eSRaghu Krishnamurthy retval->arg8 = read_ctx_reg(gpregs, CTX_GPREG_X8); 153*0b850e9eSRaghu Krishnamurthy retval->arg9 = read_ctx_reg(gpregs, CTX_GPREG_X9); 154*0b850e9eSRaghu Krishnamurthy retval->arg10 = read_ctx_reg(gpregs, CTX_GPREG_X10); 155*0b850e9eSRaghu Krishnamurthy retval->arg11 = read_ctx_reg(gpregs, CTX_GPREG_X11); 156*0b850e9eSRaghu Krishnamurthy retval->arg12 = read_ctx_reg(gpregs, CTX_GPREG_X12); 157*0b850e9eSRaghu Krishnamurthy retval->arg13 = read_ctx_reg(gpregs, CTX_GPREG_X13); 158*0b850e9eSRaghu Krishnamurthy retval->arg14 = read_ctx_reg(gpregs, CTX_GPREG_X14); 159*0b850e9eSRaghu Krishnamurthy retval->arg15 = read_ctx_reg(gpregs, CTX_GPREG_X15); 160*0b850e9eSRaghu Krishnamurthy retval->arg16 = read_ctx_reg(gpregs, CTX_GPREG_X16); 161*0b850e9eSRaghu Krishnamurthy retval->arg17 = read_ctx_reg(gpregs, CTX_GPREG_X17); 16266bdfd6eSRaghu Krishnamurthy } 16366bdfd6eSRaghu Krishnamurthy 16466bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t *ctx) 16566bdfd6eSRaghu Krishnamurthy { 16666bdfd6eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_DIR_REQ_ONGOING; 16766bdfd6eSRaghu Krishnamurthy } 16866bdfd6eSRaghu Krishnamurthy 16966bdfd6eSRaghu Krishnamurthy static void spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t *ctx) 17066bdfd6eSRaghu Krishnamurthy { 17166bdfd6eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_DIR_REQ_ONGOING; 17266bdfd6eSRaghu Krishnamurthy } 17366bdfd6eSRaghu Krishnamurthy 174*0b850e9eSRaghu Krishnamurthy static void spmd_build_ffa_info_get_regs(spmd_spm_core_context_t *ctx, 175*0b850e9eSRaghu Krishnamurthy const uint32_t uuid[4], 176*0b850e9eSRaghu Krishnamurthy const uint16_t start_index, 177*0b850e9eSRaghu Krishnamurthy const uint16_t tag) 178*0b850e9eSRaghu Krishnamurthy { 179*0b850e9eSRaghu Krishnamurthy gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); 180*0b850e9eSRaghu Krishnamurthy 181*0b850e9eSRaghu Krishnamurthy uint64_t arg1 = (uint64_t)uuid[1] << 32 | uuid[0]; 182*0b850e9eSRaghu Krishnamurthy uint64_t arg2 = (uint64_t)uuid[3] << 32 | uuid[2]; 183*0b850e9eSRaghu Krishnamurthy uint64_t arg3 = start_index | (uint64_t)tag << 16; 184*0b850e9eSRaghu Krishnamurthy 185*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_PARTITION_INFO_GET_REGS_SMC64); 186*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X1, arg1); 187*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X2, arg2); 188*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X3, arg3); 189*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X4, 0U); 190*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); 191*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); 192*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); 193*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X8, 0U); 194*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X9, 0U); 195*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X10, 0U); 196*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X11, 0U); 197*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X12, 0U); 198*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X13, 0U); 199*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X14, 0U); 200*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X15, 0U); 201*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X16, 0U); 202*0b850e9eSRaghu Krishnamurthy write_ctx_reg(gpregs, CTX_GPREG_X17, 0U); 203*0b850e9eSRaghu Krishnamurthy } 204*0b850e9eSRaghu Krishnamurthy 205*0b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t *ctx) 206*0b850e9eSRaghu Krishnamurthy { 207*0b850e9eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_INFO_GET_REG_ONGOING; 208*0b850e9eSRaghu Krishnamurthy } 209*0b850e9eSRaghu Krishnamurthy 210*0b850e9eSRaghu Krishnamurthy static void spmd_logical_sp_reset_info_regs_ongoing( 211*0b850e9eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx) 212*0b850e9eSRaghu Krishnamurthy { 213*0b850e9eSRaghu Krishnamurthy ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_INFO_GET_REG_ONGOING; 214*0b850e9eSRaghu Krishnamurthy } 215890b5088SRaghu Krishnamurthy #endif 216890b5088SRaghu Krishnamurthy 217890b5088SRaghu Krishnamurthy /* 218890b5088SRaghu Krishnamurthy * Initialize SPMD logical partitions. This function assumes that it is called 219890b5088SRaghu Krishnamurthy * only after the SPMC has successfully initialized. 220890b5088SRaghu Krishnamurthy */ 221890b5088SRaghu Krishnamurthy int32_t spmd_logical_sp_init(void) 222890b5088SRaghu Krishnamurthy { 223890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 224890b5088SRaghu Krishnamurthy int32_t rc = 0; 225890b5088SRaghu Krishnamurthy struct spmd_lp_desc *spmd_lp_descs; 226890b5088SRaghu Krishnamurthy 227890b5088SRaghu Krishnamurthy if (is_spmd_lp_inited == true) { 228890b5088SRaghu Krishnamurthy return 0; 229890b5088SRaghu Krishnamurthy } 230890b5088SRaghu Krishnamurthy 231890b5088SRaghu Krishnamurthy if (is_spmc_inited == false) { 232890b5088SRaghu Krishnamurthy return -1; 233890b5088SRaghu Krishnamurthy } 234890b5088SRaghu Krishnamurthy 235890b5088SRaghu Krishnamurthy spmd_lp_descs = get_spmd_el3_lp_array(); 236890b5088SRaghu Krishnamurthy 237890b5088SRaghu Krishnamurthy /* Perform initial validation of the SPMD Logical Partitions. */ 238890b5088SRaghu Krishnamurthy rc = el3_spmd_sp_desc_validate(spmd_lp_descs); 239890b5088SRaghu Krishnamurthy if (rc != 0) { 240890b5088SRaghu Krishnamurthy ERROR("Logical SPMD Partition validation failed!\n"); 241890b5088SRaghu Krishnamurthy return rc; 242890b5088SRaghu Krishnamurthy } 243890b5088SRaghu Krishnamurthy 244890b5088SRaghu Krishnamurthy VERBOSE("SPMD Logical Secure Partition init start.\n"); 245890b5088SRaghu Krishnamurthy for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) { 246890b5088SRaghu Krishnamurthy rc = spmd_lp_descs[i].init(); 247890b5088SRaghu Krishnamurthy if (rc != 0) { 248890b5088SRaghu Krishnamurthy ERROR("SPMD Logical SP (0x%x) failed to initialize\n", 249890b5088SRaghu Krishnamurthy spmd_lp_descs[i].sp_id); 250890b5088SRaghu Krishnamurthy return rc; 251890b5088SRaghu Krishnamurthy } 252890b5088SRaghu Krishnamurthy VERBOSE("SPMD Logical SP (0x%x) Initialized\n", 253890b5088SRaghu Krishnamurthy spmd_lp_descs[i].sp_id); 254890b5088SRaghu Krishnamurthy } 255890b5088SRaghu Krishnamurthy 256890b5088SRaghu Krishnamurthy INFO("SPMD Logical Secure Partition init completed.\n"); 257890b5088SRaghu Krishnamurthy if (rc == 0) { 258890b5088SRaghu Krishnamurthy is_spmd_lp_inited = true; 259890b5088SRaghu Krishnamurthy } 260890b5088SRaghu Krishnamurthy return rc; 261890b5088SRaghu Krishnamurthy #else 262890b5088SRaghu Krishnamurthy return 0; 263890b5088SRaghu Krishnamurthy #endif 264890b5088SRaghu Krishnamurthy } 265890b5088SRaghu Krishnamurthy 266890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_initialized(void) 267890b5088SRaghu Krishnamurthy { 268890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 269890b5088SRaghu Krishnamurthy is_spmc_inited = true; 270890b5088SRaghu Krishnamurthy #endif 271890b5088SRaghu Krishnamurthy } 272890b5088SRaghu Krishnamurthy 273890b5088SRaghu Krishnamurthy void spmd_logical_sp_set_spmc_failure(void) 274890b5088SRaghu Krishnamurthy { 275890b5088SRaghu Krishnamurthy #if ENABLE_SPMD_LP 276890b5088SRaghu Krishnamurthy is_spmc_inited = false; 277890b5088SRaghu Krishnamurthy #endif 278890b5088SRaghu Krishnamurthy } 27966bdfd6eSRaghu Krishnamurthy 280*0b850e9eSRaghu Krishnamurthy /* 281*0b850e9eSRaghu Krishnamurthy * This function takes an ffa_value structure populated with partition 282*0b850e9eSRaghu Krishnamurthy * information from an FFA_PARTITION_INFO_GET_REGS ABI call, extracts 283*0b850e9eSRaghu Krishnamurthy * the values and writes it into a ffa_partition_info_v1_1 structure for 284*0b850e9eSRaghu Krishnamurthy * other code to consume. 285*0b850e9eSRaghu Krishnamurthy */ 286*0b850e9eSRaghu Krishnamurthy bool ffa_partition_info_regs_get_part_info( 287*0b850e9eSRaghu Krishnamurthy struct ffa_value args, uint8_t idx, 288*0b850e9eSRaghu Krishnamurthy struct ffa_partition_info_v1_1 *partition_info) 289*0b850e9eSRaghu Krishnamurthy { 290*0b850e9eSRaghu Krishnamurthy uint64_t *arg_ptrs; 291*0b850e9eSRaghu Krishnamurthy uint64_t info, uuid_lo, uuid_high; 292*0b850e9eSRaghu Krishnamurthy 293*0b850e9eSRaghu Krishnamurthy /* 294*0b850e9eSRaghu Krishnamurthy * Each partition information is encoded in 3 registers, so there can be 295*0b850e9eSRaghu Krishnamurthy * a maximum of 5 entries. 296*0b850e9eSRaghu Krishnamurthy */ 297*0b850e9eSRaghu Krishnamurthy if (idx >= 5 || partition_info == NULL) { 298*0b850e9eSRaghu Krishnamurthy return false; 299*0b850e9eSRaghu Krishnamurthy } 300*0b850e9eSRaghu Krishnamurthy 301*0b850e9eSRaghu Krishnamurthy /* List of pointers to args in return value. */ 302*0b850e9eSRaghu Krishnamurthy arg_ptrs = (uint64_t *)&args + ((idx * 3) + 3); 303*0b850e9eSRaghu Krishnamurthy info = *arg_ptrs; 304*0b850e9eSRaghu Krishnamurthy 305*0b850e9eSRaghu Krishnamurthy arg_ptrs++; 306*0b850e9eSRaghu Krishnamurthy uuid_lo = *arg_ptrs; 307*0b850e9eSRaghu Krishnamurthy 308*0b850e9eSRaghu Krishnamurthy arg_ptrs++; 309*0b850e9eSRaghu Krishnamurthy uuid_high = *arg_ptrs; 310*0b850e9eSRaghu Krishnamurthy 311*0b850e9eSRaghu Krishnamurthy partition_info->ep_id = (uint16_t)(info & 0xFFFFU); 312*0b850e9eSRaghu Krishnamurthy partition_info->execution_ctx_count = (uint16_t)((info >> 16) & 0xFFFFU); 313*0b850e9eSRaghu Krishnamurthy partition_info->properties = (uint32_t)(info >> 32); 314*0b850e9eSRaghu Krishnamurthy partition_info->uuid[0] = (uint32_t)(uuid_lo & 0xFFFFFFFFU); 315*0b850e9eSRaghu Krishnamurthy partition_info->uuid[1] = (uint32_t)((uuid_lo >> 32) & 0xFFFFFFFFU); 316*0b850e9eSRaghu Krishnamurthy partition_info->uuid[2] = (uint32_t)(uuid_high & 0xFFFFFFFFU); 317*0b850e9eSRaghu Krishnamurthy partition_info->uuid[3] = (uint32_t)((uuid_high >> 32) & 0xFFFFFFFFU); 318*0b850e9eSRaghu Krishnamurthy 319*0b850e9eSRaghu Krishnamurthy return true; 320*0b850e9eSRaghu Krishnamurthy } 321*0b850e9eSRaghu Krishnamurthy 322*0b850e9eSRaghu Krishnamurthy /* 323*0b850e9eSRaghu Krishnamurthy * This function can be used by an SPMD logical partition to invoke the 324*0b850e9eSRaghu Krishnamurthy * FFA_PARTITION_INFO_GET_REGS ABI to the SPMC, to discover the secure 325*0b850e9eSRaghu Krishnamurthy * partitions in the system. The function takes a UUID, start index and 326*0b850e9eSRaghu Krishnamurthy * tag and the partition information are returned in an ffa_value structure 327*0b850e9eSRaghu Krishnamurthy * and can be consumed by using appropriate helper functions. 328*0b850e9eSRaghu Krishnamurthy */ 329*0b850e9eSRaghu Krishnamurthy bool spmd_el3_invoke_partition_info_get( 330*0b850e9eSRaghu Krishnamurthy const uint32_t target_uuid[4], 331*0b850e9eSRaghu Krishnamurthy const uint16_t start_index, 332*0b850e9eSRaghu Krishnamurthy const uint16_t tag, 333*0b850e9eSRaghu Krishnamurthy struct ffa_value *retval) 334*0b850e9eSRaghu Krishnamurthy { 335*0b850e9eSRaghu Krishnamurthy #if ENABLE_SPMD_LP 336*0b850e9eSRaghu Krishnamurthy uint64_t rc = UINT64_MAX; 337*0b850e9eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx = spmd_get_context(); 338*0b850e9eSRaghu Krishnamurthy 339*0b850e9eSRaghu Krishnamurthy if (retval == NULL) { 340*0b850e9eSRaghu Krishnamurthy return false; 341*0b850e9eSRaghu Krishnamurthy } 342*0b850e9eSRaghu Krishnamurthy 343*0b850e9eSRaghu Krishnamurthy memset(retval, 0, sizeof(*retval)); 344*0b850e9eSRaghu Krishnamurthy 345*0b850e9eSRaghu Krishnamurthy if (!is_spmc_inited) { 346*0b850e9eSRaghu Krishnamurthy VERBOSE("Cannot discover partition before," 347*0b850e9eSRaghu Krishnamurthy " SPMC is initialized.\n"); 348*0b850e9eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); 349*0b850e9eSRaghu Krishnamurthy return true; 350*0b850e9eSRaghu Krishnamurthy } 351*0b850e9eSRaghu Krishnamurthy 352*0b850e9eSRaghu Krishnamurthy if (tag != 0) { 353*0b850e9eSRaghu Krishnamurthy VERBOSE("Tag must be zero. other tags unsupported\n"); 354*0b850e9eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 355*0b850e9eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 356*0b850e9eSRaghu Krishnamurthy return true; 357*0b850e9eSRaghu Krishnamurthy } 358*0b850e9eSRaghu Krishnamurthy 359*0b850e9eSRaghu Krishnamurthy /* Save the non-secure context before entering SPMC */ 360*0b850e9eSRaghu Krishnamurthy cm_el1_sysregs_context_save(NON_SECURE); 361*0b850e9eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2 362*0b850e9eSRaghu Krishnamurthy cm_el2_sysregs_context_save(NON_SECURE); 363*0b850e9eSRaghu Krishnamurthy #endif 364*0b850e9eSRaghu Krishnamurthy 365*0b850e9eSRaghu Krishnamurthy spmd_build_ffa_info_get_regs(ctx, target_uuid, start_index, tag); 366*0b850e9eSRaghu Krishnamurthy spmd_logical_sp_set_info_regs_ongoing(ctx); 367*0b850e9eSRaghu Krishnamurthy 368*0b850e9eSRaghu Krishnamurthy rc = spmd_spm_core_sync_entry(ctx); 369*0b850e9eSRaghu Krishnamurthy if (rc != 0ULL) { 370*0b850e9eSRaghu Krishnamurthy ERROR("%s failed (%lx) on CPU%u\n", __func__, rc, 371*0b850e9eSRaghu Krishnamurthy plat_my_core_pos()); 372*0b850e9eSRaghu Krishnamurthy panic(); 373*0b850e9eSRaghu Krishnamurthy } 374*0b850e9eSRaghu Krishnamurthy 375*0b850e9eSRaghu Krishnamurthy spmd_logical_sp_reset_info_regs_ongoing(ctx); 376*0b850e9eSRaghu Krishnamurthy spmd_encode_ctx_to_ffa_value(ctx, retval); 377*0b850e9eSRaghu Krishnamurthy 378*0b850e9eSRaghu Krishnamurthy assert(is_ffa_error(retval) || is_ffa_success(retval)); 379*0b850e9eSRaghu Krishnamurthy 380*0b850e9eSRaghu Krishnamurthy cm_el1_sysregs_context_restore(NON_SECURE); 381*0b850e9eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2 382*0b850e9eSRaghu Krishnamurthy cm_el2_sysregs_context_restore(NON_SECURE); 383*0b850e9eSRaghu Krishnamurthy #endif 384*0b850e9eSRaghu Krishnamurthy cm_set_next_eret_context(NON_SECURE); 385*0b850e9eSRaghu Krishnamurthy return true; 386*0b850e9eSRaghu Krishnamurthy #else 387*0b850e9eSRaghu Krishnamurthy return false; 388*0b850e9eSRaghu Krishnamurthy #endif 389*0b850e9eSRaghu Krishnamurthy } 390*0b850e9eSRaghu Krishnamurthy 39166bdfd6eSRaghu Krishnamurthy /******************************************************************************* 39266bdfd6eSRaghu Krishnamurthy * This function sends an FF-A Direct Request from a partition in EL3 to a 39366bdfd6eSRaghu Krishnamurthy * partition that may reside under an SPMC (only lower ELs supported). The main 39466bdfd6eSRaghu Krishnamurthy * use of this API is for SPMD logical partitions. 39566bdfd6eSRaghu Krishnamurthy * The API is expected to be used when there are platform specific SMCs that 39666bdfd6eSRaghu Krishnamurthy * need to be routed to a secure partition that is FF-A compliant or when 39766bdfd6eSRaghu Krishnamurthy * there are group 0 interrupts that need to be handled first in EL3 and then 39866bdfd6eSRaghu Krishnamurthy * forwarded to an FF-A compliant secure partition. Therefore, it is expected 39966bdfd6eSRaghu Krishnamurthy * that the handle to the context provided belongs to the non-secure context. 40066bdfd6eSRaghu Krishnamurthy * This also means that interrupts/SMCs that trap to EL3 during secure execution 40166bdfd6eSRaghu Krishnamurthy * cannot use this API. 40266bdfd6eSRaghu Krishnamurthy * x1, x2, x3 and x4 are encoded as specified in the FF-A specification. 40366bdfd6eSRaghu Krishnamurthy * retval is used to pass the direct response values to the caller. 40466bdfd6eSRaghu Krishnamurthy * The function returns true if retval has valid values, and false otherwise. 40566bdfd6eSRaghu Krishnamurthy ******************************************************************************/ 40666bdfd6eSRaghu Krishnamurthy bool spmd_el3_ffa_msg_direct_req(uint64_t x1, 40766bdfd6eSRaghu Krishnamurthy uint64_t x2, 40866bdfd6eSRaghu Krishnamurthy uint64_t x3, 40966bdfd6eSRaghu Krishnamurthy uint64_t x4, 41066bdfd6eSRaghu Krishnamurthy void *handle, 41166bdfd6eSRaghu Krishnamurthy struct ffa_value *retval) 41266bdfd6eSRaghu Krishnamurthy { 41366bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP 41466bdfd6eSRaghu Krishnamurthy 41566bdfd6eSRaghu Krishnamurthy uint64_t rc = UINT64_MAX; 41666bdfd6eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx = spmd_get_context(); 41766bdfd6eSRaghu Krishnamurthy 41866bdfd6eSRaghu Krishnamurthy if (retval == NULL) { 41966bdfd6eSRaghu Krishnamurthy return false; 42066bdfd6eSRaghu Krishnamurthy } 42166bdfd6eSRaghu Krishnamurthy 42266bdfd6eSRaghu Krishnamurthy memset(retval, 0, sizeof(*retval)); 42366bdfd6eSRaghu Krishnamurthy 42466bdfd6eSRaghu Krishnamurthy if (!is_spmd_lp_inited || !is_spmc_inited) { 42566bdfd6eSRaghu Krishnamurthy VERBOSE("Cannot send SPMD logical partition direct message," 42666bdfd6eSRaghu Krishnamurthy " Partitions not initialized or SPMC not initialized.\n"); 42766bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); 42866bdfd6eSRaghu Krishnamurthy return true; 42966bdfd6eSRaghu Krishnamurthy } 43066bdfd6eSRaghu Krishnamurthy 43166bdfd6eSRaghu Krishnamurthy /* 43266bdfd6eSRaghu Krishnamurthy * x2 must be zero, since there is no support for framework message via 43366bdfd6eSRaghu Krishnamurthy * an SPMD logical partition. This is sort of a useless check and it is 43466bdfd6eSRaghu Krishnamurthy * possible to not take parameter. However, as the framework extends it 43566bdfd6eSRaghu Krishnamurthy * may be useful to have x2 and extend this function later with 43666bdfd6eSRaghu Krishnamurthy * functionality based on x2. 43766bdfd6eSRaghu Krishnamurthy */ 43866bdfd6eSRaghu Krishnamurthy if (x2 != 0) { 43966bdfd6eSRaghu Krishnamurthy VERBOSE("x2 must be zero. Cannot send framework message.\n"); 44066bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); 44166bdfd6eSRaghu Krishnamurthy return true; 44266bdfd6eSRaghu Krishnamurthy } 44366bdfd6eSRaghu Krishnamurthy 44466bdfd6eSRaghu Krishnamurthy /* 44566bdfd6eSRaghu Krishnamurthy * Current context must be non-secure. API is expected to be used 44666bdfd6eSRaghu Krishnamurthy * when entry into EL3 and the SPMD logical partition is via an 44766bdfd6eSRaghu Krishnamurthy * interrupt that occurs when execution is in normal world and 44866bdfd6eSRaghu Krishnamurthy * SMCs from normal world. FF-A compliant SPMCs are expected to 44966bdfd6eSRaghu Krishnamurthy * trap interrupts during secure execution in lower ELs since they 45066bdfd6eSRaghu Krishnamurthy * are usually not re-entrant and SMCs from secure world can be 45166bdfd6eSRaghu Krishnamurthy * handled synchronously. There is no known use case for an SPMD 45266bdfd6eSRaghu Krishnamurthy * logical partition to send a direct message to another partition 45366bdfd6eSRaghu Krishnamurthy * in response to a secure interrupt or SMCs from secure world. 45466bdfd6eSRaghu Krishnamurthy */ 45566bdfd6eSRaghu Krishnamurthy if (handle != cm_get_context(NON_SECURE)) { 45666bdfd6eSRaghu Krishnamurthy VERBOSE("Handle must be for the non-secure context.\n"); 45766bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); 45866bdfd6eSRaghu Krishnamurthy return true; 45966bdfd6eSRaghu Krishnamurthy } 46066bdfd6eSRaghu Krishnamurthy 46166bdfd6eSRaghu Krishnamurthy if (!is_spmd_lp_id(ffa_endpoint_source(x1))) { 46266bdfd6eSRaghu Krishnamurthy VERBOSE("Source ID must be valid SPMD logical partition" 46366bdfd6eSRaghu Krishnamurthy " ID.\n"); 46466bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 46566bdfd6eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 46666bdfd6eSRaghu Krishnamurthy return true; 46766bdfd6eSRaghu Krishnamurthy } 46866bdfd6eSRaghu Krishnamurthy 46966bdfd6eSRaghu Krishnamurthy if (is_spmd_lp_id(ffa_endpoint_destination(x1))) { 47066bdfd6eSRaghu Krishnamurthy VERBOSE("Destination ID must not be SPMD logical partition" 47166bdfd6eSRaghu Krishnamurthy " ID.\n"); 47266bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 47366bdfd6eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 47466bdfd6eSRaghu Krishnamurthy return true; 47566bdfd6eSRaghu Krishnamurthy } 47666bdfd6eSRaghu Krishnamurthy 47766bdfd6eSRaghu Krishnamurthy if (!ffa_is_secure_world_id(ffa_endpoint_destination(x1))) { 47866bdfd6eSRaghu Krishnamurthy VERBOSE("Destination ID must be secure world ID.\n"); 47966bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 48066bdfd6eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 48166bdfd6eSRaghu Krishnamurthy return true; 48266bdfd6eSRaghu Krishnamurthy } 48366bdfd6eSRaghu Krishnamurthy 48466bdfd6eSRaghu Krishnamurthy if (ffa_endpoint_destination(x1) == SPMD_DIRECT_MSG_ENDPOINT_ID) { 48566bdfd6eSRaghu Krishnamurthy VERBOSE("Destination ID must not be SPMD ID.\n"); 48666bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 48766bdfd6eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 48866bdfd6eSRaghu Krishnamurthy return true; 48966bdfd6eSRaghu Krishnamurthy } 49066bdfd6eSRaghu Krishnamurthy 49166bdfd6eSRaghu Krishnamurthy if (ffa_endpoint_destination(x1) == spmd_spmc_id_get()) { 49266bdfd6eSRaghu Krishnamurthy VERBOSE("Destination ID must not be SPMC ID.\n"); 49366bdfd6eSRaghu Krishnamurthy spmd_encode_ffa_error(retval, 49466bdfd6eSRaghu Krishnamurthy FFA_ERROR_INVALID_PARAMETER); 49566bdfd6eSRaghu Krishnamurthy return true; 49666bdfd6eSRaghu Krishnamurthy } 49766bdfd6eSRaghu Krishnamurthy 49866bdfd6eSRaghu Krishnamurthy /* Save the non-secure context before entering SPMC */ 49966bdfd6eSRaghu Krishnamurthy cm_el1_sysregs_context_save(NON_SECURE); 50066bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2 50166bdfd6eSRaghu Krishnamurthy cm_el2_sysregs_context_save(NON_SECURE); 50266bdfd6eSRaghu Krishnamurthy #endif 50366bdfd6eSRaghu Krishnamurthy 50466bdfd6eSRaghu Krishnamurthy /* 50566bdfd6eSRaghu Krishnamurthy * Perform synchronous entry into the SPMC. Synchronous entry is 50666bdfd6eSRaghu Krishnamurthy * required because the spec requires that a direct message request 50766bdfd6eSRaghu Krishnamurthy * from an SPMD LP look like a function call from it's perspective. 50866bdfd6eSRaghu Krishnamurthy */ 50966bdfd6eSRaghu Krishnamurthy spmd_build_direct_message_req(ctx, x1, x2, x3, x4); 51066bdfd6eSRaghu Krishnamurthy spmd_logical_sp_set_dir_req_ongoing(ctx); 51166bdfd6eSRaghu Krishnamurthy 51266bdfd6eSRaghu Krishnamurthy rc = spmd_spm_core_sync_entry(ctx); 51366bdfd6eSRaghu Krishnamurthy 51466bdfd6eSRaghu Krishnamurthy spmd_logical_sp_reset_dir_req_ongoing(ctx); 51566bdfd6eSRaghu Krishnamurthy 51666bdfd6eSRaghu Krishnamurthy if (rc != 0ULL) { 51766bdfd6eSRaghu Krishnamurthy ERROR("%s failed (%lx) on CPU%u\n", __func__, rc, 51866bdfd6eSRaghu Krishnamurthy plat_my_core_pos()); 51966bdfd6eSRaghu Krishnamurthy panic(); 52066bdfd6eSRaghu Krishnamurthy } else { 52166bdfd6eSRaghu Krishnamurthy spmd_encode_ctx_to_ffa_value(ctx, retval); 52266bdfd6eSRaghu Krishnamurthy 52366bdfd6eSRaghu Krishnamurthy /* 52466bdfd6eSRaghu Krishnamurthy * Only expect error or direct response, 52566bdfd6eSRaghu Krishnamurthy * spmd_spm_core_sync_exit should not be called on other paths. 52666bdfd6eSRaghu Krishnamurthy * Checks are asserts since the LSP can fail gracefully if the 52766bdfd6eSRaghu Krishnamurthy * source or destination ids are not the same. Panic'ing would 52866bdfd6eSRaghu Krishnamurthy * not provide any benefit. 52966bdfd6eSRaghu Krishnamurthy */ 53066bdfd6eSRaghu Krishnamurthy assert(is_ffa_error(retval) || is_ffa_direct_msg_resp(retval)); 53166bdfd6eSRaghu Krishnamurthy assert(is_ffa_error(retval) || 53266bdfd6eSRaghu Krishnamurthy (ffa_endpoint_destination(retval->arg1) == 53366bdfd6eSRaghu Krishnamurthy ffa_endpoint_source(x1))); 53466bdfd6eSRaghu Krishnamurthy assert(is_ffa_error(retval) || 53566bdfd6eSRaghu Krishnamurthy (ffa_endpoint_source(retval->arg1) == 53666bdfd6eSRaghu Krishnamurthy ffa_endpoint_destination(x1))); 53766bdfd6eSRaghu Krishnamurthy } 53866bdfd6eSRaghu Krishnamurthy 53966bdfd6eSRaghu Krishnamurthy cm_el1_sysregs_context_restore(NON_SECURE); 54066bdfd6eSRaghu Krishnamurthy #if SPMD_SPM_AT_SEL2 54166bdfd6eSRaghu Krishnamurthy cm_el2_sysregs_context_restore(NON_SECURE); 54266bdfd6eSRaghu Krishnamurthy #endif 54366bdfd6eSRaghu Krishnamurthy cm_set_next_eret_context(NON_SECURE); 54466bdfd6eSRaghu Krishnamurthy 54566bdfd6eSRaghu Krishnamurthy return true; 54666bdfd6eSRaghu Krishnamurthy #else 54766bdfd6eSRaghu Krishnamurthy return false; 54866bdfd6eSRaghu Krishnamurthy #endif 54966bdfd6eSRaghu Krishnamurthy } 55066bdfd6eSRaghu Krishnamurthy 551*0b850e9eSRaghu Krishnamurthy bool is_spmd_logical_sp_info_regs_req_in_progress( 552*0b850e9eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx) 553*0b850e9eSRaghu Krishnamurthy { 554*0b850e9eSRaghu Krishnamurthy #if ENABLE_SPMD_LP 555*0b850e9eSRaghu Krishnamurthy return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_INFO_GET_REG_ONGOING) 556*0b850e9eSRaghu Krishnamurthy == SPMD_LP_FFA_INFO_GET_REG_ONGOING); 557*0b850e9eSRaghu Krishnamurthy #else 558*0b850e9eSRaghu Krishnamurthy return false; 559*0b850e9eSRaghu Krishnamurthy #endif 560*0b850e9eSRaghu Krishnamurthy } 561*0b850e9eSRaghu Krishnamurthy 56266bdfd6eSRaghu Krishnamurthy bool is_spmd_logical_sp_dir_req_in_progress( 56366bdfd6eSRaghu Krishnamurthy spmd_spm_core_context_t *ctx) 56466bdfd6eSRaghu Krishnamurthy { 56566bdfd6eSRaghu Krishnamurthy #if ENABLE_SPMD_LP 56666bdfd6eSRaghu Krishnamurthy return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING) 56766bdfd6eSRaghu Krishnamurthy == SPMD_LP_FFA_DIR_REQ_ONGOING); 56866bdfd6eSRaghu Krishnamurthy #else 56966bdfd6eSRaghu Krishnamurthy return false; 57066bdfd6eSRaghu Krishnamurthy #endif 57166bdfd6eSRaghu Krishnamurthy } 572