Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 1 | /* |
Madhukar Pappireddy | d3f3207 | 2024-01-29 16:43:56 -0600 | [diff] [blame] | 2 | * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved. |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
| 8 | #include <errno.h> |
| 9 | #include <string.h> |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 10 | #include "spmd_private.h" |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 11 | |
| 12 | #include <common/debug.h> |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 13 | #include <common/uuid.h> |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 14 | #include <lib/el3_runtime/context_mgmt.h> |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 15 | #include <services/el3_spmd_logical_sp.h> |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 16 | #include <services/spmc_svc.h> |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 17 | #include <smccc_helpers.h> |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 18 | |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 19 | |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 20 | /* |
| 21 | * Maximum ffa_partition_info entries that can be returned by an invocation |
| 22 | * of FFA_PARTITION_INFO_GET_REGS_64 is size in bytes, of available |
| 23 | * registers/args in struct ffa_value divided by size of struct |
| 24 | * ffa_partition_info. For this ABI, arg3-arg17 in ffa_value can be used, i.e. |
| 25 | * 15 uint64_t fields. For FF-A v1.1, this value should be 5. |
| 26 | */ |
| 27 | #define MAX_INFO_REGS_ENTRIES_PER_CALL \ |
| 28 | (uint8_t)((15 * sizeof(uint64_t)) / \ |
| 29 | sizeof(struct ffa_partition_info_v1_1)) |
| 30 | CASSERT(MAX_INFO_REGS_ENTRIES_PER_CALL == 5, assert_too_many_info_reg_entries); |
| 31 | |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 32 | #if ENABLE_SPMD_LP |
| 33 | static bool is_spmd_lp_inited; |
| 34 | static bool is_spmc_inited; |
| 35 | |
| 36 | /* |
| 37 | * Helper function to obtain the array storing the EL3 |
| 38 | * SPMD Logical Partition descriptors. |
| 39 | */ |
| 40 | static struct spmd_lp_desc *get_spmd_el3_lp_array(void) |
| 41 | { |
| 42 | return (struct spmd_lp_desc *) SPMD_LP_DESCS_START; |
| 43 | } |
| 44 | |
| 45 | /******************************************************************************* |
| 46 | * Validate any logical partition descriptors before we initialize. |
| 47 | * Initialization of said partitions will be taken care of during SPMD boot. |
| 48 | ******************************************************************************/ |
| 49 | static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array) |
| 50 | { |
| 51 | /* Check the array bounds are valid. */ |
| 52 | assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START); |
| 53 | |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 54 | /* |
| 55 | * No support for SPMD logical partitions when SPMC is at EL3. |
| 56 | */ |
| 57 | assert(!is_spmc_at_el3()); |
| 58 | |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 59 | /* If no SPMD logical partitions are implemented then simply bail out. */ |
| 60 | if (SPMD_LP_DESCS_COUNT == 0U) { |
| 61 | return -1; |
| 62 | } |
| 63 | |
| 64 | for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) { |
| 65 | struct spmd_lp_desc *lp_desc = &lp_array[index]; |
| 66 | |
| 67 | /* Validate our logical partition descriptors. */ |
| 68 | if (lp_desc == NULL) { |
| 69 | ERROR("Invalid SPMD Logical SP Descriptor\n"); |
| 70 | return -EINVAL; |
| 71 | } |
| 72 | |
| 73 | /* |
| 74 | * Ensure the ID follows the convention to indicate it resides |
| 75 | * in the secure world. |
| 76 | */ |
| 77 | if (!ffa_is_secure_world_id(lp_desc->sp_id)) { |
| 78 | ERROR("Invalid SPMD Logical SP ID (0x%x)\n", |
| 79 | lp_desc->sp_id); |
| 80 | return -EINVAL; |
| 81 | } |
| 82 | |
| 83 | /* Ensure SPMD logical partition is in valid range. */ |
| 84 | if (!is_spmd_lp_id(lp_desc->sp_id)) { |
| 85 | ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", |
| 86 | lp_desc->sp_id); |
| 87 | return -EINVAL; |
| 88 | } |
| 89 | |
| 90 | /* Ensure the UUID is not the NULL UUID. */ |
| 91 | if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 && |
| 92 | lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) { |
| 93 | ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n", |
| 94 | lp_desc->sp_id); |
| 95 | return -EINVAL; |
| 96 | } |
| 97 | |
| 98 | /* Ensure init function callback is registered. */ |
| 99 | if (lp_desc->init == NULL) { |
| 100 | ERROR("Missing init function for Logical SP(0x%x)\n", |
| 101 | lp_desc->sp_id); |
| 102 | return -EINVAL; |
| 103 | } |
| 104 | |
| 105 | /* Ensure that SPMD LP only supports sending direct requests. */ |
| 106 | if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) { |
| 107 | ERROR("Invalid SPMD logical partition properties (0x%x)\n", |
| 108 | lp_desc->properties); |
| 109 | return -EINVAL; |
| 110 | } |
| 111 | |
| 112 | /* Ensure that all partition IDs are unique. */ |
| 113 | for (uint32_t inner_idx = index + 1; |
| 114 | inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) { |
| 115 | if (lp_desc->sp_id == lp_array[inner_idx].sp_id) { |
| 116 | ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n", |
| 117 | lp_desc->sp_id); |
| 118 | return -EINVAL; |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | return 0; |
| 123 | } |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 124 | |
| 125 | static void spmd_encode_ffa_error(struct ffa_value *retval, int32_t error_code) |
| 126 | { |
| 127 | retval->func = FFA_ERROR; |
| 128 | retval->arg1 = FFA_TARGET_INFO_MBZ; |
| 129 | retval->arg2 = (uint32_t)error_code; |
| 130 | retval->arg3 = FFA_TARGET_INFO_MBZ; |
| 131 | retval->arg4 = FFA_TARGET_INFO_MBZ; |
| 132 | retval->arg5 = FFA_TARGET_INFO_MBZ; |
| 133 | retval->arg6 = FFA_TARGET_INFO_MBZ; |
| 134 | retval->arg7 = FFA_TARGET_INFO_MBZ; |
| 135 | } |
| 136 | |
| 137 | static void spmd_build_direct_message_req(spmd_spm_core_context_t *ctx, |
| 138 | uint64_t x1, uint64_t x2, |
| 139 | uint64_t x3, uint64_t x4) |
| 140 | { |
| 141 | gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); |
| 142 | |
| 143 | write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32); |
| 144 | write_ctx_reg(gpregs, CTX_GPREG_X1, x1); |
| 145 | write_ctx_reg(gpregs, CTX_GPREG_X2, x2); |
| 146 | write_ctx_reg(gpregs, CTX_GPREG_X3, x3); |
| 147 | write_ctx_reg(gpregs, CTX_GPREG_X4, x4); |
| 148 | write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); |
| 149 | write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); |
| 150 | write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); |
| 151 | } |
| 152 | |
| 153 | static void spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t *ctx, |
| 154 | struct ffa_value *retval) |
| 155 | { |
| 156 | gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); |
| 157 | |
| 158 | retval->func = read_ctx_reg(gpregs, CTX_GPREG_X0); |
| 159 | retval->arg1 = read_ctx_reg(gpregs, CTX_GPREG_X1); |
| 160 | retval->arg2 = read_ctx_reg(gpregs, CTX_GPREG_X2); |
| 161 | retval->arg3 = read_ctx_reg(gpregs, CTX_GPREG_X3); |
| 162 | retval->arg4 = read_ctx_reg(gpregs, CTX_GPREG_X4); |
| 163 | retval->arg5 = read_ctx_reg(gpregs, CTX_GPREG_X5); |
| 164 | retval->arg6 = read_ctx_reg(gpregs, CTX_GPREG_X6); |
| 165 | retval->arg7 = read_ctx_reg(gpregs, CTX_GPREG_X7); |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 166 | retval->arg8 = read_ctx_reg(gpregs, CTX_GPREG_X8); |
| 167 | retval->arg9 = read_ctx_reg(gpregs, CTX_GPREG_X9); |
| 168 | retval->arg10 = read_ctx_reg(gpregs, CTX_GPREG_X10); |
| 169 | retval->arg11 = read_ctx_reg(gpregs, CTX_GPREG_X11); |
| 170 | retval->arg12 = read_ctx_reg(gpregs, CTX_GPREG_X12); |
| 171 | retval->arg13 = read_ctx_reg(gpregs, CTX_GPREG_X13); |
| 172 | retval->arg14 = read_ctx_reg(gpregs, CTX_GPREG_X14); |
| 173 | retval->arg15 = read_ctx_reg(gpregs, CTX_GPREG_X15); |
| 174 | retval->arg16 = read_ctx_reg(gpregs, CTX_GPREG_X16); |
| 175 | retval->arg17 = read_ctx_reg(gpregs, CTX_GPREG_X17); |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 176 | } |
| 177 | |
| 178 | static void spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t *ctx) |
| 179 | { |
| 180 | ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_DIR_REQ_ONGOING; |
| 181 | } |
| 182 | |
| 183 | static void spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t *ctx) |
| 184 | { |
| 185 | ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_DIR_REQ_ONGOING; |
| 186 | } |
| 187 | |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 188 | static void spmd_build_ffa_info_get_regs(spmd_spm_core_context_t *ctx, |
| 189 | const uint32_t uuid[4], |
| 190 | const uint16_t start_index, |
| 191 | const uint16_t tag) |
| 192 | { |
| 193 | gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); |
| 194 | |
| 195 | uint64_t arg1 = (uint64_t)uuid[1] << 32 | uuid[0]; |
| 196 | uint64_t arg2 = (uint64_t)uuid[3] << 32 | uuid[2]; |
| 197 | uint64_t arg3 = start_index | (uint64_t)tag << 16; |
| 198 | |
| 199 | write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_PARTITION_INFO_GET_REGS_SMC64); |
| 200 | write_ctx_reg(gpregs, CTX_GPREG_X1, arg1); |
| 201 | write_ctx_reg(gpregs, CTX_GPREG_X2, arg2); |
| 202 | write_ctx_reg(gpregs, CTX_GPREG_X3, arg3); |
| 203 | write_ctx_reg(gpregs, CTX_GPREG_X4, 0U); |
| 204 | write_ctx_reg(gpregs, CTX_GPREG_X5, 0U); |
| 205 | write_ctx_reg(gpregs, CTX_GPREG_X6, 0U); |
| 206 | write_ctx_reg(gpregs, CTX_GPREG_X7, 0U); |
| 207 | write_ctx_reg(gpregs, CTX_GPREG_X8, 0U); |
| 208 | write_ctx_reg(gpregs, CTX_GPREG_X9, 0U); |
| 209 | write_ctx_reg(gpregs, CTX_GPREG_X10, 0U); |
| 210 | write_ctx_reg(gpregs, CTX_GPREG_X11, 0U); |
| 211 | write_ctx_reg(gpregs, CTX_GPREG_X12, 0U); |
| 212 | write_ctx_reg(gpregs, CTX_GPREG_X13, 0U); |
| 213 | write_ctx_reg(gpregs, CTX_GPREG_X14, 0U); |
| 214 | write_ctx_reg(gpregs, CTX_GPREG_X15, 0U); |
| 215 | write_ctx_reg(gpregs, CTX_GPREG_X16, 0U); |
| 216 | write_ctx_reg(gpregs, CTX_GPREG_X17, 0U); |
| 217 | } |
| 218 | |
| 219 | static void spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t *ctx) |
| 220 | { |
| 221 | ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_INFO_GET_REG_ONGOING; |
| 222 | } |
| 223 | |
| 224 | static void spmd_logical_sp_reset_info_regs_ongoing( |
| 225 | spmd_spm_core_context_t *ctx) |
| 226 | { |
| 227 | ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_INFO_GET_REG_ONGOING; |
| 228 | } |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 229 | |
| 230 | static void spmd_fill_lp_info_array( |
| 231 | struct ffa_partition_info_v1_1 (*partitions)[EL3_SPMD_MAX_NUM_LP], |
| 232 | uint32_t uuid[4], uint16_t *lp_count_out) |
| 233 | { |
| 234 | uint16_t lp_count = 0; |
| 235 | struct spmd_lp_desc *lp_array; |
| 236 | bool uuid_is_null = is_null_uuid(uuid); |
| 237 | |
| 238 | if (SPMD_LP_DESCS_COUNT == 0U) { |
| 239 | *lp_count_out = 0; |
| 240 | return; |
| 241 | } |
| 242 | |
| 243 | lp_array = get_spmd_el3_lp_array(); |
| 244 | for (uint16_t index = 0; index < SPMD_LP_DESCS_COUNT; ++index) { |
| 245 | struct spmd_lp_desc *lp = &lp_array[index]; |
| 246 | |
| 247 | if (uuid_is_null || uuid_match(uuid, lp->uuid)) { |
| 248 | uint16_t array_index = lp_count; |
| 249 | |
| 250 | ++lp_count; |
| 251 | |
| 252 | (*partitions)[array_index].ep_id = lp->sp_id; |
| 253 | (*partitions)[array_index].execution_ctx_count = 1; |
| 254 | (*partitions)[array_index].properties = lp->properties; |
| 255 | (*partitions)[array_index].properties |= |
| 256 | (FFA_PARTITION_INFO_GET_AARCH64_STATE << |
| 257 | FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT); |
| 258 | if (uuid_is_null) { |
| 259 | memcpy(&((*partitions)[array_index].uuid), |
| 260 | &lp->uuid, sizeof(lp->uuid)); |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | *lp_count_out = lp_count; |
| 266 | } |
| 267 | |
| 268 | static inline void spmd_pack_lp_count_props( |
| 269 | uint64_t *xn, uint16_t ep_id, uint16_t vcpu_count, |
| 270 | uint32_t properties) |
| 271 | { |
| 272 | *xn = (uint64_t)ep_id; |
| 273 | *xn |= (uint64_t)vcpu_count << 16; |
| 274 | *xn |= (uint64_t)properties << 32; |
| 275 | } |
| 276 | |
| 277 | static inline void spmd_pack_lp_uuid(uint64_t *xn_1, uint64_t *xn_2, |
| 278 | uint32_t uuid[4]) |
| 279 | { |
| 280 | *xn_1 = (uint64_t)uuid[0]; |
| 281 | *xn_1 |= (uint64_t)uuid[1] << 32; |
| 282 | *xn_2 = (uint64_t)uuid[2]; |
| 283 | *xn_2 |= (uint64_t)uuid[3] << 32; |
| 284 | } |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 285 | #endif |
| 286 | |
| 287 | /* |
| 288 | * Initialize SPMD logical partitions. This function assumes that it is called |
| 289 | * only after the SPMC has successfully initialized. |
| 290 | */ |
| 291 | int32_t spmd_logical_sp_init(void) |
| 292 | { |
| 293 | #if ENABLE_SPMD_LP |
| 294 | int32_t rc = 0; |
| 295 | struct spmd_lp_desc *spmd_lp_descs; |
| 296 | |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 297 | assert(SPMD_LP_DESCS_COUNT <= EL3_SPMD_MAX_NUM_LP); |
| 298 | |
Raghu Krishnamurthy | 7f046c1 | 2023-02-25 13:26:10 -0800 | [diff] [blame] | 299 | if (is_spmd_lp_inited == true) { |
| 300 | return 0; |
| 301 | } |
| 302 | |
| 303 | if (is_spmc_inited == false) { |
| 304 | return -1; |
| 305 | } |
| 306 | |
| 307 | spmd_lp_descs = get_spmd_el3_lp_array(); |
| 308 | |
| 309 | /* Perform initial validation of the SPMD Logical Partitions. */ |
| 310 | rc = el3_spmd_sp_desc_validate(spmd_lp_descs); |
| 311 | if (rc != 0) { |
| 312 | ERROR("Logical SPMD Partition validation failed!\n"); |
| 313 | return rc; |
| 314 | } |
| 315 | |
| 316 | VERBOSE("SPMD Logical Secure Partition init start.\n"); |
| 317 | for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) { |
| 318 | rc = spmd_lp_descs[i].init(); |
| 319 | if (rc != 0) { |
| 320 | ERROR("SPMD Logical SP (0x%x) failed to initialize\n", |
| 321 | spmd_lp_descs[i].sp_id); |
| 322 | return rc; |
| 323 | } |
| 324 | VERBOSE("SPMD Logical SP (0x%x) Initialized\n", |
| 325 | spmd_lp_descs[i].sp_id); |
| 326 | } |
| 327 | |
| 328 | INFO("SPMD Logical Secure Partition init completed.\n"); |
| 329 | if (rc == 0) { |
| 330 | is_spmd_lp_inited = true; |
| 331 | } |
| 332 | return rc; |
| 333 | #else |
| 334 | return 0; |
| 335 | #endif |
| 336 | } |
| 337 | |
| 338 | void spmd_logical_sp_set_spmc_initialized(void) |
| 339 | { |
| 340 | #if ENABLE_SPMD_LP |
| 341 | is_spmc_inited = true; |
| 342 | #endif |
| 343 | } |
| 344 | |
| 345 | void spmd_logical_sp_set_spmc_failure(void) |
| 346 | { |
| 347 | #if ENABLE_SPMD_LP |
| 348 | is_spmc_inited = false; |
| 349 | #endif |
| 350 | } |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 351 | |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 352 | /* |
| 353 | * This function takes an ffa_value structure populated with partition |
| 354 | * information from an FFA_PARTITION_INFO_GET_REGS ABI call, extracts |
| 355 | * the values and writes it into a ffa_partition_info_v1_1 structure for |
| 356 | * other code to consume. |
| 357 | */ |
| 358 | bool ffa_partition_info_regs_get_part_info( |
Raghu Krishnamurthy | 717c840 | 2023-09-25 13:05:55 -0700 | [diff] [blame] | 359 | struct ffa_value *args, uint8_t idx, |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 360 | struct ffa_partition_info_v1_1 *partition_info) |
| 361 | { |
| 362 | uint64_t *arg_ptrs; |
| 363 | uint64_t info, uuid_lo, uuid_high; |
| 364 | |
| 365 | /* |
| 366 | * Each partition information is encoded in 3 registers, so there can be |
| 367 | * a maximum of 5 entries. |
| 368 | */ |
| 369 | if (idx >= 5 || partition_info == NULL) { |
| 370 | return false; |
| 371 | } |
| 372 | |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 373 | /* |
| 374 | * List of pointers to args in return value. arg0/func encodes ff-a |
| 375 | * function, arg1 is reserved, arg2 encodes indices. arg3 and greater |
| 376 | * values reflect partition properties. |
| 377 | */ |
Raghu Krishnamurthy | 717c840 | 2023-09-25 13:05:55 -0700 | [diff] [blame] | 378 | arg_ptrs = (uint64_t *)args + ((idx * 3) + 3); |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 379 | info = *arg_ptrs; |
| 380 | |
| 381 | arg_ptrs++; |
| 382 | uuid_lo = *arg_ptrs; |
| 383 | |
| 384 | arg_ptrs++; |
| 385 | uuid_high = *arg_ptrs; |
| 386 | |
| 387 | partition_info->ep_id = (uint16_t)(info & 0xFFFFU); |
| 388 | partition_info->execution_ctx_count = (uint16_t)((info >> 16) & 0xFFFFU); |
| 389 | partition_info->properties = (uint32_t)(info >> 32); |
| 390 | partition_info->uuid[0] = (uint32_t)(uuid_lo & 0xFFFFFFFFU); |
| 391 | partition_info->uuid[1] = (uint32_t)((uuid_lo >> 32) & 0xFFFFFFFFU); |
| 392 | partition_info->uuid[2] = (uint32_t)(uuid_high & 0xFFFFFFFFU); |
| 393 | partition_info->uuid[3] = (uint32_t)((uuid_high >> 32) & 0xFFFFFFFFU); |
| 394 | |
| 395 | return true; |
| 396 | } |
| 397 | |
| 398 | /* |
Raghu Krishnamurthy | 9d9584f | 2023-04-22 18:00:02 -0700 | [diff] [blame] | 399 | * This function is called by the SPMD in response to |
| 400 | * an FFA_PARTITION_INFO_GET_REG ABI invocation by the SPMC. Secure partitions |
| 401 | * are allowed to discover the presence of EL3 SPMD logical partitions by |
| 402 | * invoking the aforementioned ABI and this function populates the required |
| 403 | * information about EL3 SPMD logical partitions. |
| 404 | */ |
| 405 | uint64_t spmd_el3_populate_logical_partition_info(void *handle, uint64_t x1, |
| 406 | uint64_t x2, uint64_t x3) |
| 407 | { |
| 408 | #if ENABLE_SPMD_LP |
| 409 | uint32_t target_uuid[4] = { 0 }; |
| 410 | uint32_t w0; |
| 411 | uint32_t w1; |
| 412 | uint32_t w2; |
| 413 | uint32_t w3; |
| 414 | uint16_t start_index; |
| 415 | uint16_t tag; |
| 416 | static struct ffa_partition_info_v1_1 partitions[EL3_SPMD_MAX_NUM_LP]; |
| 417 | uint16_t lp_count = 0; |
| 418 | uint16_t max_idx = 0; |
| 419 | uint16_t curr_idx = 0; |
| 420 | uint8_t num_entries_to_ret = 0; |
| 421 | struct ffa_value ret = { 0 }; |
| 422 | uint64_t *arg_ptrs = (uint64_t *)&ret + 3; |
| 423 | |
| 424 | w0 = (uint32_t)(x1 & 0xFFFFFFFFU); |
| 425 | w1 = (uint32_t)(x1 >> 32); |
| 426 | w2 = (uint32_t)(x2 & 0xFFFFFFFFU); |
| 427 | w3 = (uint32_t)(x2 >> 32); |
| 428 | |
| 429 | target_uuid[0] = w0; |
| 430 | target_uuid[1] = w1; |
| 431 | target_uuid[2] = w2; |
| 432 | target_uuid[3] = w3; |
| 433 | |
| 434 | start_index = (uint16_t)(x3 & 0xFFFFU); |
| 435 | tag = (uint16_t)((x3 >> 16) & 0xFFFFU); |
| 436 | |
| 437 | assert(handle == cm_get_context(SECURE)); |
| 438 | |
| 439 | if (tag != 0) { |
| 440 | VERBOSE("Tag is not 0. Cannot return partition info.\n"); |
| 441 | return spmd_ffa_error_return(handle, FFA_ERROR_RETRY); |
| 442 | } |
| 443 | |
| 444 | memset(&partitions, 0, sizeof(partitions)); |
| 445 | |
| 446 | spmd_fill_lp_info_array(&partitions, target_uuid, &lp_count); |
| 447 | |
| 448 | if (lp_count == 0) { |
| 449 | VERBOSE("No SPDM EL3 logical partitions exist.\n"); |
| 450 | return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); |
| 451 | } |
| 452 | |
| 453 | if (start_index >= lp_count) { |
| 454 | VERBOSE("start_index = %d, lp_count = %d (start index must be" |
| 455 | " less than partition count.\n", |
| 456 | start_index, lp_count); |
| 457 | return spmd_ffa_error_return(handle, |
| 458 | FFA_ERROR_INVALID_PARAMETER); |
| 459 | } |
| 460 | |
| 461 | max_idx = lp_count - 1; |
| 462 | num_entries_to_ret = (max_idx - start_index) + 1; |
| 463 | num_entries_to_ret = |
| 464 | MIN(num_entries_to_ret, MAX_INFO_REGS_ENTRIES_PER_CALL); |
| 465 | curr_idx = start_index + num_entries_to_ret - 1; |
| 466 | assert(curr_idx <= max_idx); |
| 467 | |
| 468 | ret.func = FFA_SUCCESS_SMC64; |
| 469 | ret.arg2 = (uint64_t)((sizeof(struct ffa_partition_info_v1_1) & 0xFFFFU) << 48); |
| 470 | ret.arg2 |= (uint64_t)(curr_idx << 16); |
| 471 | ret.arg2 |= (uint64_t)max_idx; |
| 472 | |
| 473 | for (uint16_t idx = start_index; idx <= curr_idx; ++idx) { |
| 474 | spmd_pack_lp_count_props(arg_ptrs, partitions[idx].ep_id, |
| 475 | partitions[idx].execution_ctx_count, |
| 476 | partitions[idx].properties); |
| 477 | arg_ptrs++; |
| 478 | if (is_null_uuid(target_uuid)) { |
| 479 | spmd_pack_lp_uuid(arg_ptrs, (arg_ptrs + 1), |
| 480 | partitions[idx].uuid); |
| 481 | } |
| 482 | arg_ptrs += 2; |
| 483 | } |
| 484 | |
| 485 | SMC_RET18(handle, ret.func, ret.arg1, ret.arg2, ret.arg3, ret.arg4, |
| 486 | ret.arg5, ret.arg6, ret.arg7, ret.arg8, ret.arg9, ret.arg10, |
| 487 | ret.arg11, ret.arg12, ret.arg13, ret.arg14, ret.arg15, |
| 488 | ret.arg16, ret.arg17); |
| 489 | #else |
| 490 | return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); |
| 491 | #endif |
| 492 | } |
| 493 | |
| 494 | /* This function can be used by an SPMD logical partition to invoke the |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 495 | * FFA_PARTITION_INFO_GET_REGS ABI to the SPMC, to discover the secure |
| 496 | * partitions in the system. The function takes a UUID, start index and |
| 497 | * tag and the partition information are returned in an ffa_value structure |
| 498 | * and can be consumed by using appropriate helper functions. |
| 499 | */ |
| 500 | bool spmd_el3_invoke_partition_info_get( |
| 501 | const uint32_t target_uuid[4], |
| 502 | const uint16_t start_index, |
| 503 | const uint16_t tag, |
| 504 | struct ffa_value *retval) |
| 505 | { |
| 506 | #if ENABLE_SPMD_LP |
| 507 | uint64_t rc = UINT64_MAX; |
| 508 | spmd_spm_core_context_t *ctx = spmd_get_context(); |
| 509 | |
| 510 | if (retval == NULL) { |
| 511 | return false; |
| 512 | } |
| 513 | |
| 514 | memset(retval, 0, sizeof(*retval)); |
| 515 | |
| 516 | if (!is_spmc_inited) { |
| 517 | VERBOSE("Cannot discover partition before," |
| 518 | " SPMC is initialized.\n"); |
| 519 | spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); |
| 520 | return true; |
| 521 | } |
| 522 | |
| 523 | if (tag != 0) { |
| 524 | VERBOSE("Tag must be zero. other tags unsupported\n"); |
| 525 | spmd_encode_ffa_error(retval, |
| 526 | FFA_ERROR_INVALID_PARAMETER); |
| 527 | return true; |
| 528 | } |
| 529 | |
| 530 | /* Save the non-secure context before entering SPMC */ |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 531 | #if SPMD_SPM_AT_SEL2 |
| 532 | cm_el2_sysregs_context_save(NON_SECURE); |
Madhukar Pappireddy | d3f3207 | 2024-01-29 16:43:56 -0600 | [diff] [blame] | 533 | #else |
| 534 | cm_el1_sysregs_context_save(NON_SECURE); |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 535 | #endif |
| 536 | |
| 537 | spmd_build_ffa_info_get_regs(ctx, target_uuid, start_index, tag); |
| 538 | spmd_logical_sp_set_info_regs_ongoing(ctx); |
| 539 | |
| 540 | rc = spmd_spm_core_sync_entry(ctx); |
| 541 | if (rc != 0ULL) { |
| 542 | ERROR("%s failed (%lx) on CPU%u\n", __func__, rc, |
| 543 | plat_my_core_pos()); |
| 544 | panic(); |
| 545 | } |
| 546 | |
| 547 | spmd_logical_sp_reset_info_regs_ongoing(ctx); |
| 548 | spmd_encode_ctx_to_ffa_value(ctx, retval); |
| 549 | |
| 550 | assert(is_ffa_error(retval) || is_ffa_success(retval)); |
| 551 | |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 552 | #if SPMD_SPM_AT_SEL2 |
| 553 | cm_el2_sysregs_context_restore(NON_SECURE); |
Madhukar Pappireddy | d3f3207 | 2024-01-29 16:43:56 -0600 | [diff] [blame] | 554 | #else |
| 555 | cm_el1_sysregs_context_restore(NON_SECURE); |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 556 | #endif |
| 557 | cm_set_next_eret_context(NON_SECURE); |
| 558 | return true; |
| 559 | #else |
| 560 | return false; |
| 561 | #endif |
| 562 | } |
| 563 | |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 564 | /******************************************************************************* |
| 565 | * This function sends an FF-A Direct Request from a partition in EL3 to a |
| 566 | * partition that may reside under an SPMC (only lower ELs supported). The main |
| 567 | * use of this API is for SPMD logical partitions. |
| 568 | * The API is expected to be used when there are platform specific SMCs that |
| 569 | * need to be routed to a secure partition that is FF-A compliant or when |
| 570 | * there are group 0 interrupts that need to be handled first in EL3 and then |
| 571 | * forwarded to an FF-A compliant secure partition. Therefore, it is expected |
| 572 | * that the handle to the context provided belongs to the non-secure context. |
| 573 | * This also means that interrupts/SMCs that trap to EL3 during secure execution |
| 574 | * cannot use this API. |
| 575 | * x1, x2, x3 and x4 are encoded as specified in the FF-A specification. |
| 576 | * retval is used to pass the direct response values to the caller. |
| 577 | * The function returns true if retval has valid values, and false otherwise. |
| 578 | ******************************************************************************/ |
| 579 | bool spmd_el3_ffa_msg_direct_req(uint64_t x1, |
| 580 | uint64_t x2, |
| 581 | uint64_t x3, |
| 582 | uint64_t x4, |
| 583 | void *handle, |
| 584 | struct ffa_value *retval) |
| 585 | { |
| 586 | #if ENABLE_SPMD_LP |
| 587 | |
| 588 | uint64_t rc = UINT64_MAX; |
| 589 | spmd_spm_core_context_t *ctx = spmd_get_context(); |
| 590 | |
| 591 | if (retval == NULL) { |
| 592 | return false; |
| 593 | } |
| 594 | |
| 595 | memset(retval, 0, sizeof(*retval)); |
| 596 | |
| 597 | if (!is_spmd_lp_inited || !is_spmc_inited) { |
| 598 | VERBOSE("Cannot send SPMD logical partition direct message," |
| 599 | " Partitions not initialized or SPMC not initialized.\n"); |
| 600 | spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); |
| 601 | return true; |
| 602 | } |
| 603 | |
| 604 | /* |
| 605 | * x2 must be zero, since there is no support for framework message via |
| 606 | * an SPMD logical partition. This is sort of a useless check and it is |
| 607 | * possible to not take parameter. However, as the framework extends it |
| 608 | * may be useful to have x2 and extend this function later with |
| 609 | * functionality based on x2. |
| 610 | */ |
| 611 | if (x2 != 0) { |
| 612 | VERBOSE("x2 must be zero. Cannot send framework message.\n"); |
| 613 | spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); |
| 614 | return true; |
| 615 | } |
| 616 | |
| 617 | /* |
| 618 | * Current context must be non-secure. API is expected to be used |
| 619 | * when entry into EL3 and the SPMD logical partition is via an |
| 620 | * interrupt that occurs when execution is in normal world and |
| 621 | * SMCs from normal world. FF-A compliant SPMCs are expected to |
| 622 | * trap interrupts during secure execution in lower ELs since they |
| 623 | * are usually not re-entrant and SMCs from secure world can be |
| 624 | * handled synchronously. There is no known use case for an SPMD |
| 625 | * logical partition to send a direct message to another partition |
| 626 | * in response to a secure interrupt or SMCs from secure world. |
| 627 | */ |
| 628 | if (handle != cm_get_context(NON_SECURE)) { |
| 629 | VERBOSE("Handle must be for the non-secure context.\n"); |
| 630 | spmd_encode_ffa_error(retval, FFA_ERROR_DENIED); |
| 631 | return true; |
| 632 | } |
| 633 | |
| 634 | if (!is_spmd_lp_id(ffa_endpoint_source(x1))) { |
| 635 | VERBOSE("Source ID must be valid SPMD logical partition" |
| 636 | " ID.\n"); |
| 637 | spmd_encode_ffa_error(retval, |
| 638 | FFA_ERROR_INVALID_PARAMETER); |
| 639 | return true; |
| 640 | } |
| 641 | |
| 642 | if (is_spmd_lp_id(ffa_endpoint_destination(x1))) { |
| 643 | VERBOSE("Destination ID must not be SPMD logical partition" |
| 644 | " ID.\n"); |
| 645 | spmd_encode_ffa_error(retval, |
| 646 | FFA_ERROR_INVALID_PARAMETER); |
| 647 | return true; |
| 648 | } |
| 649 | |
| 650 | if (!ffa_is_secure_world_id(ffa_endpoint_destination(x1))) { |
| 651 | VERBOSE("Destination ID must be secure world ID.\n"); |
| 652 | spmd_encode_ffa_error(retval, |
| 653 | FFA_ERROR_INVALID_PARAMETER); |
| 654 | return true; |
| 655 | } |
| 656 | |
| 657 | if (ffa_endpoint_destination(x1) == SPMD_DIRECT_MSG_ENDPOINT_ID) { |
| 658 | VERBOSE("Destination ID must not be SPMD ID.\n"); |
| 659 | spmd_encode_ffa_error(retval, |
| 660 | FFA_ERROR_INVALID_PARAMETER); |
| 661 | return true; |
| 662 | } |
| 663 | |
| 664 | if (ffa_endpoint_destination(x1) == spmd_spmc_id_get()) { |
| 665 | VERBOSE("Destination ID must not be SPMC ID.\n"); |
| 666 | spmd_encode_ffa_error(retval, |
| 667 | FFA_ERROR_INVALID_PARAMETER); |
| 668 | return true; |
| 669 | } |
| 670 | |
| 671 | /* Save the non-secure context before entering SPMC */ |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 672 | #if SPMD_SPM_AT_SEL2 |
| 673 | cm_el2_sysregs_context_save(NON_SECURE); |
Madhukar Pappireddy | d3f3207 | 2024-01-29 16:43:56 -0600 | [diff] [blame] | 674 | #else |
| 675 | cm_el1_sysregs_context_save(NON_SECURE); |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 676 | #endif |
| 677 | |
| 678 | /* |
| 679 | * Perform synchronous entry into the SPMC. Synchronous entry is |
| 680 | * required because the spec requires that a direct message request |
| 681 | * from an SPMD LP look like a function call from it's perspective. |
| 682 | */ |
| 683 | spmd_build_direct_message_req(ctx, x1, x2, x3, x4); |
| 684 | spmd_logical_sp_set_dir_req_ongoing(ctx); |
| 685 | |
| 686 | rc = spmd_spm_core_sync_entry(ctx); |
| 687 | |
| 688 | spmd_logical_sp_reset_dir_req_ongoing(ctx); |
| 689 | |
| 690 | if (rc != 0ULL) { |
| 691 | ERROR("%s failed (%lx) on CPU%u\n", __func__, rc, |
| 692 | plat_my_core_pos()); |
| 693 | panic(); |
| 694 | } else { |
| 695 | spmd_encode_ctx_to_ffa_value(ctx, retval); |
| 696 | |
| 697 | /* |
| 698 | * Only expect error or direct response, |
| 699 | * spmd_spm_core_sync_exit should not be called on other paths. |
| 700 | * Checks are asserts since the LSP can fail gracefully if the |
| 701 | * source or destination ids are not the same. Panic'ing would |
| 702 | * not provide any benefit. |
| 703 | */ |
| 704 | assert(is_ffa_error(retval) || is_ffa_direct_msg_resp(retval)); |
| 705 | assert(is_ffa_error(retval) || |
| 706 | (ffa_endpoint_destination(retval->arg1) == |
| 707 | ffa_endpoint_source(x1))); |
| 708 | assert(is_ffa_error(retval) || |
| 709 | (ffa_endpoint_source(retval->arg1) == |
| 710 | ffa_endpoint_destination(x1))); |
| 711 | } |
| 712 | |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 713 | #if SPMD_SPM_AT_SEL2 |
| 714 | cm_el2_sysregs_context_restore(NON_SECURE); |
Madhukar Pappireddy | d3f3207 | 2024-01-29 16:43:56 -0600 | [diff] [blame] | 715 | #else |
| 716 | cm_el1_sysregs_context_restore(NON_SECURE); |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 717 | #endif |
| 718 | cm_set_next_eret_context(NON_SECURE); |
| 719 | |
| 720 | return true; |
| 721 | #else |
| 722 | return false; |
| 723 | #endif |
| 724 | } |
| 725 | |
Raghu Krishnamurthy | 43fda97 | 2023-04-22 11:28:38 -0700 | [diff] [blame] | 726 | bool is_spmd_logical_sp_info_regs_req_in_progress( |
| 727 | spmd_spm_core_context_t *ctx) |
| 728 | { |
| 729 | #if ENABLE_SPMD_LP |
| 730 | return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_INFO_GET_REG_ONGOING) |
| 731 | == SPMD_LP_FFA_INFO_GET_REG_ONGOING); |
| 732 | #else |
| 733 | return false; |
| 734 | #endif |
| 735 | } |
| 736 | |
Raghu Krishnamurthy | 6a30514 | 2023-03-03 06:41:29 -0800 | [diff] [blame] | 737 | bool is_spmd_logical_sp_dir_req_in_progress( |
| 738 | spmd_spm_core_context_t *ctx) |
| 739 | { |
| 740 | #if ENABLE_SPMD_LP |
| 741 | return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING) |
| 742 | == SPMD_LP_FFA_DIR_REQ_ONGOING); |
| 743 | #else |
| 744 | return false; |
| 745 | #endif |
| 746 | } |