1 /*
2 * Copyright (c) 2023-2026, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <string.h>
10 #include "spmd_private.h"
11
12 #include <common/debug.h>
13 #include <common/uuid.h>
14 #include <lib/el3_runtime/context_mgmt.h>
15 #include <services/el3_spmd_logical_sp.h>
16 #include <services/lfa_svc.h>
17 #include <services/spmc_svc.h>
18 #include <smccc_helpers.h>
19
20 #if ENABLE_SPMD_LP
21 static bool is_spmd_lp_inited;
22 static bool is_spmc_inited;
23
24 /*
25 * Helper function to obtain the array storing the EL3
26 * SPMD Logical Partition descriptors.
27 */
get_spmd_el3_lp_array(void)28 static struct spmd_lp_desc *get_spmd_el3_lp_array(void)
29 {
30 return (struct spmd_lp_desc *) SPMD_LP_DESCS_START;
31 }
32
33 /*******************************************************************************
34 * Validate any logical partition descriptors before we initialize.
35 * Initialization of said partitions will be taken care of during SPMD boot.
36 ******************************************************************************/
el3_spmd_sp_desc_validate(struct spmd_lp_desc * lp_array)37 static int el3_spmd_sp_desc_validate(struct spmd_lp_desc *lp_array)
38 {
39 /* Check the array bounds are valid. */
40 assert(SPMD_LP_DESCS_END > SPMD_LP_DESCS_START);
41
42 /*
43 * No support for SPMD logical partitions when SPMC is at EL3.
44 */
45 assert(!is_spmc_at_el3());
46
47 /* If no SPMD logical partitions are implemented then simply bail out. */
48 if (SPMD_LP_DESCS_COUNT == 0U) {
49 return -1;
50 }
51
52 for (uint32_t index = 0U; index < SPMD_LP_DESCS_COUNT; index++) {
53 struct spmd_lp_desc *lp_desc = &lp_array[index];
54
55 /* Validate our logical partition descriptors. */
56 if (lp_desc == NULL) {
57 ERROR("Invalid SPMD Logical SP Descriptor\n");
58 return -EINVAL;
59 }
60
61 /*
62 * Ensure the ID follows the convention to indicate it resides
63 * in the secure world.
64 */
65 if (!ffa_is_secure_world_id(lp_desc->sp_id)) {
66 ERROR("Invalid SPMD Logical SP ID (0x%x)\n",
67 lp_desc->sp_id);
68 return -EINVAL;
69 }
70
71 /* Ensure SPMD logical partition is in valid range. */
72 if (!is_spmd_lp_id(lp_desc->sp_id)) {
73 ERROR("Invalid SPMD Logical Partition ID (0x%x)\n",
74 lp_desc->sp_id);
75 return -EINVAL;
76 }
77
78 /* Ensure the UUID is not the NULL UUID. */
79 if (lp_desc->uuid[0] == 0 && lp_desc->uuid[1] == 0 &&
80 lp_desc->uuid[2] == 0 && lp_desc->uuid[3] == 0) {
81 ERROR("Invalid UUID for SPMD Logical SP (0x%x)\n",
82 lp_desc->sp_id);
83 return -EINVAL;
84 }
85
86 /* Ensure init function callback is registered. */
87 if (lp_desc->init == NULL) {
88 ERROR("Missing init function for Logical SP(0x%x)\n",
89 lp_desc->sp_id);
90 return -EINVAL;
91 }
92
93 /* Ensure that SPMD LP only supports sending direct requests. */
94 if (lp_desc->properties != FFA_PARTITION_DIRECT_REQ_SEND) {
95 ERROR("Invalid SPMD logical partition properties (0x%x)\n",
96 lp_desc->properties);
97 return -EINVAL;
98 }
99
100 /* Ensure that all partition IDs are unique. */
101 for (uint32_t inner_idx = index + 1;
102 inner_idx < SPMD_LP_DESCS_COUNT; inner_idx++) {
103 if (lp_desc->sp_id == lp_array[inner_idx].sp_id) {
104 ERROR("Duplicate SPMD logical SP ID Detected (0x%x)\n",
105 lp_desc->sp_id);
106 return -EINVAL;
107 }
108 }
109 }
110 return 0;
111 }
112
spmd_encode_ffa_error(struct ffa_value * retval,int32_t error_code)113 static void spmd_encode_ffa_error(struct ffa_value *retval, int32_t error_code)
114 {
115 retval->func = FFA_ERROR;
116 retval->arg1 = FFA_TARGET_INFO_MBZ;
117 retval->arg2 = (uint32_t)error_code;
118 retval->arg3 = FFA_TARGET_INFO_MBZ;
119 retval->arg4 = FFA_TARGET_INFO_MBZ;
120 retval->arg5 = FFA_TARGET_INFO_MBZ;
121 retval->arg6 = FFA_TARGET_INFO_MBZ;
122 retval->arg7 = FFA_TARGET_INFO_MBZ;
123 }
124
spmd_build_direct_message_req(spmd_spm_core_context_t * ctx,uint64_t function_id,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,uint64_t x5,uint64_t x6,uint64_t x7)125 static void spmd_build_direct_message_req(spmd_spm_core_context_t *ctx,
126 uint64_t function_id,
127 uint64_t x1, uint64_t x2,
128 uint64_t x3, uint64_t x4,
129 uint64_t x5, uint64_t x6,
130 uint64_t x7)
131 {
132 gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
133
134 write_ctx_reg(gpregs, CTX_GPREG_X0, function_id);
135 write_ctx_reg(gpregs, CTX_GPREG_X1, x1);
136 write_ctx_reg(gpregs, CTX_GPREG_X2, x2);
137 write_ctx_reg(gpregs, CTX_GPREG_X3, x3);
138 write_ctx_reg(gpregs, CTX_GPREG_X4, x4);
139 write_ctx_reg(gpregs, CTX_GPREG_X5, x5);
140 write_ctx_reg(gpregs, CTX_GPREG_X6, x6);
141 write_ctx_reg(gpregs, CTX_GPREG_X7, x7);
142 }
143
spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t * ctx,struct ffa_value * retval)144 static void spmd_encode_ctx_to_ffa_value(spmd_spm_core_context_t *ctx,
145 struct ffa_value *retval)
146 {
147 gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
148
149 retval->func = read_ctx_reg(gpregs, CTX_GPREG_X0);
150 retval->arg1 = read_ctx_reg(gpregs, CTX_GPREG_X1);
151 retval->arg2 = read_ctx_reg(gpregs, CTX_GPREG_X2);
152 retval->arg3 = read_ctx_reg(gpregs, CTX_GPREG_X3);
153 retval->arg4 = read_ctx_reg(gpregs, CTX_GPREG_X4);
154 retval->arg5 = read_ctx_reg(gpregs, CTX_GPREG_X5);
155 retval->arg6 = read_ctx_reg(gpregs, CTX_GPREG_X6);
156 retval->arg7 = read_ctx_reg(gpregs, CTX_GPREG_X7);
157 retval->arg8 = read_ctx_reg(gpregs, CTX_GPREG_X8);
158 retval->arg9 = read_ctx_reg(gpregs, CTX_GPREG_X9);
159 retval->arg10 = read_ctx_reg(gpregs, CTX_GPREG_X10);
160 retval->arg11 = read_ctx_reg(gpregs, CTX_GPREG_X11);
161 retval->arg12 = read_ctx_reg(gpregs, CTX_GPREG_X12);
162 retval->arg13 = read_ctx_reg(gpregs, CTX_GPREG_X13);
163 retval->arg14 = read_ctx_reg(gpregs, CTX_GPREG_X14);
164 retval->arg15 = read_ctx_reg(gpregs, CTX_GPREG_X15);
165 retval->arg16 = read_ctx_reg(gpregs, CTX_GPREG_X16);
166 retval->arg17 = read_ctx_reg(gpregs, CTX_GPREG_X17);
167 }
168
spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t * ctx)169 static void spmd_logical_sp_set_dir_req_ongoing(spmd_spm_core_context_t *ctx)
170 {
171 ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_DIR_REQ_ONGOING;
172 }
173
spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t * ctx)174 static void spmd_logical_sp_reset_dir_req_ongoing(spmd_spm_core_context_t *ctx)
175 {
176 ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_DIR_REQ_ONGOING;
177 }
178
spmd_build_ffa_info_get_regs(spmd_spm_core_context_t * ctx,const uint32_t uuid[4],const uint16_t start_index,const uint16_t tag)179 static void spmd_build_ffa_info_get_regs(spmd_spm_core_context_t *ctx,
180 const uint32_t uuid[4],
181 const uint16_t start_index,
182 const uint16_t tag)
183 {
184 gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
185
186 uint64_t arg1 = (uint64_t)uuid[1] << 32 | uuid[0];
187 uint64_t arg2 = (uint64_t)uuid[3] << 32 | uuid[2];
188 uint64_t arg3 = start_index | (uint64_t)tag << 16;
189
190 write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_PARTITION_INFO_GET_REGS_SMC64);
191 write_ctx_reg(gpregs, CTX_GPREG_X1, arg1);
192 write_ctx_reg(gpregs, CTX_GPREG_X2, arg2);
193 write_ctx_reg(gpregs, CTX_GPREG_X3, arg3);
194 write_ctx_reg(gpregs, CTX_GPREG_X4, 0U);
195 write_ctx_reg(gpregs, CTX_GPREG_X5, 0U);
196 write_ctx_reg(gpregs, CTX_GPREG_X6, 0U);
197 write_ctx_reg(gpregs, CTX_GPREG_X7, 0U);
198 write_ctx_reg(gpregs, CTX_GPREG_X8, 0U);
199 write_ctx_reg(gpregs, CTX_GPREG_X9, 0U);
200 write_ctx_reg(gpregs, CTX_GPREG_X10, 0U);
201 write_ctx_reg(gpregs, CTX_GPREG_X11, 0U);
202 write_ctx_reg(gpregs, CTX_GPREG_X12, 0U);
203 write_ctx_reg(gpregs, CTX_GPREG_X13, 0U);
204 write_ctx_reg(gpregs, CTX_GPREG_X14, 0U);
205 write_ctx_reg(gpregs, CTX_GPREG_X15, 0U);
206 write_ctx_reg(gpregs, CTX_GPREG_X16, 0U);
207 write_ctx_reg(gpregs, CTX_GPREG_X17, 0U);
208 }
209
spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t * ctx)210 static void spmd_logical_sp_set_info_regs_ongoing(spmd_spm_core_context_t *ctx)
211 {
212 ctx->spmd_lp_sync_req_ongoing |= SPMD_LP_FFA_INFO_GET_REG_ONGOING;
213 }
214
spmd_logical_sp_reset_info_regs_ongoing(spmd_spm_core_context_t * ctx)215 static void spmd_logical_sp_reset_info_regs_ongoing(
216 spmd_spm_core_context_t *ctx)
217 {
218 ctx->spmd_lp_sync_req_ongoing &= ~SPMD_LP_FFA_INFO_GET_REG_ONGOING;
219 }
220
spmd_fill_lp_info_array(struct ffa_partition_info_v1_3 (* partitions)[EL3_SPMD_MAX_NUM_LP],uint32_t uuid[4],uint16_t * lp_count_out)221 static void spmd_fill_lp_info_array(
222 struct ffa_partition_info_v1_3 (*partitions)[EL3_SPMD_MAX_NUM_LP],
223 uint32_t uuid[4], uint16_t *lp_count_out)
224 {
225 uint16_t lp_count = 0;
226 struct spmd_lp_desc *lp_array;
227 bool uuid_is_null = is_null_uuid(uuid);
228
229 if (SPMD_LP_DESCS_COUNT == 0U) {
230 *lp_count_out = 0;
231 return;
232 }
233
234 lp_array = get_spmd_el3_lp_array();
235 for (uint16_t index = 0; index < SPMD_LP_DESCS_COUNT; ++index) {
236 struct spmd_lp_desc *lp = &lp_array[index];
237
238 if (uuid_is_null || uuid_match(uuid, lp->uuid)) {
239 uint16_t array_index = lp_count;
240
241 ++lp_count;
242
243 (*partitions)[array_index].ep_id = lp->sp_id;
244 (*partitions)[array_index].execution_ctx_count = 1;
245 (*partitions)[array_index].properties = lp->properties;
246 (*partitions)[array_index].properties |=
247 (FFA_PARTITION_INFO_GET_AARCH64_STATE <<
248 FFA_PARTITION_INFO_GET_EXEC_STATE_SHIFT);
249 if (uuid_is_null) {
250 memcpy(&((*partitions)[array_index].protocol_uuid),
251 &lp->uuid, sizeof(lp->uuid));
252 }
253
254 /* Zero the Image UUID. */
255 memset(&((*partitions)[array_index].image_uuid),
256 0, sizeof(lp->uuid));
257
258 /* Same as SPMD's version. */
259 (*partitions)[array_index].ffa_version = FFA_VERSION_COMPILED;
260 }
261 }
262
263 *lp_count_out = lp_count;
264 }
265
spmd_pack_lp_count_props(uint64_t * xn,uint16_t ep_id,uint16_t vcpu_count,uint32_t properties)266 static inline void spmd_pack_lp_count_props(
267 uint64_t *xn, uint16_t ep_id, uint16_t vcpu_count,
268 uint32_t properties)
269 {
270 *xn = (uint64_t)ep_id;
271 *xn |= (uint64_t)vcpu_count << 16;
272 *xn |= (uint64_t)properties << 32;
273 }
274
spmd_pack_lp_uuid(uint64_t * xn_1,uint64_t * xn_2,uint32_t uuid[4])275 static inline void spmd_pack_lp_uuid(uint64_t *xn_1, uint64_t *xn_2,
276 uint32_t uuid[4])
277 {
278 *xn_1 = (uint64_t)uuid[0];
279 *xn_1 |= (uint64_t)uuid[1] << 32;
280 *xn_2 = (uint64_t)uuid[2];
281 *xn_2 |= (uint64_t)uuid[3] << 32;
282 }
283 #endif
284
285 /*
286 * Initialize SPMD logical partitions. This function assumes that it is called
287 * only after the SPMC has successfully initialized.
288 */
spmd_logical_sp_init(void)289 int32_t spmd_logical_sp_init(void)
290 {
291 #if ENABLE_SPMD_LP
292 int32_t rc = 0;
293 struct spmd_lp_desc *spmd_lp_descs;
294
295 assert(SPMD_LP_DESCS_COUNT <= EL3_SPMD_MAX_NUM_LP);
296
297 if (is_spmd_lp_inited == true) {
298 return 0;
299 }
300
301 if (is_spmc_inited == false) {
302 return -1;
303 }
304
305 spmd_lp_descs = get_spmd_el3_lp_array();
306
307 /* Perform initial validation of the SPMD Logical Partitions. */
308 rc = el3_spmd_sp_desc_validate(spmd_lp_descs);
309 if (rc != 0) {
310 ERROR("Logical SPMD Partition validation failed!\n");
311 return rc;
312 }
313
314 VERBOSE("SPMD Logical Secure Partition init start.\n");
315 for (unsigned int i = 0U; i < SPMD_LP_DESCS_COUNT; i++) {
316 rc = spmd_lp_descs[i].init();
317 if (rc != 0) {
318 ERROR("SPMD Logical SP (0x%x) failed to initialize\n",
319 spmd_lp_descs[i].sp_id);
320 return rc;
321 }
322 VERBOSE("SPMD Logical SP (0x%x) Initialized\n",
323 spmd_lp_descs[i].sp_id);
324 }
325
326 INFO("SPMD Logical Secure Partition init completed.\n");
327 if (rc == 0) {
328 is_spmd_lp_inited = true;
329 }
330 return rc;
331 #else
332 return 0;
333 #endif
334 }
335
spmd_logical_sp_set_spmc_initialized(void)336 void spmd_logical_sp_set_spmc_initialized(void)
337 {
338 #if ENABLE_SPMD_LP
339 is_spmc_inited = true;
340 #endif
341 }
342
spmd_logical_sp_set_spmc_failure(void)343 void spmd_logical_sp_set_spmc_failure(void)
344 {
345 #if ENABLE_SPMD_LP
346 is_spmc_inited = false;
347 #endif
348 }
349
350 /*
351 * This function takes an ffa_value structure populated with partition
352 * information from an FFA_PARTITION_INFO_GET_REGS ABI call, extracts
353 * the values and writes it into a ffa_partition_info structure for
354 * other code to consume.
355 */
ffa_partition_info_regs_get_part_info(struct ffa_value * args,uint8_t idx,struct ffa_partition_info_v1_3 * partition_info)356 bool ffa_partition_info_regs_get_part_info(
357 struct ffa_value *args, uint8_t idx,
358 struct ffa_partition_info_v1_3 *partition_info)
359 {
360 uint64_t *arg_ptrs;
361 uint64_t info, uuid_lo, uuid_high, image_uuid_lo, image_uuid_high, version;
362
363 /*
364 * Each partition information is encoded in 6 registers, so there can be
365 * a maximum of 2 entries.
366 */
367 if (idx >= MAX_INFO_REGS_ENTRIES_PER_CALL || partition_info == NULL) {
368 return false;
369 }
370
371 /*
372 * List of pointers to args in return value. arg0/func encodes ff-a
373 * function, arg1 is reserved, arg2 encodes indices. arg3 and greater
374 * values reflect partition properties.
375 */
376 arg_ptrs = (uint64_t *)args + ((idx * 6) + 3);
377 info = *arg_ptrs;
378
379 arg_ptrs++;
380 uuid_lo = *arg_ptrs;
381
382 arg_ptrs++;
383 uuid_high = *arg_ptrs;
384
385 arg_ptrs++;
386 image_uuid_lo = *arg_ptrs;
387
388 arg_ptrs++;
389 image_uuid_high = *arg_ptrs;
390
391 arg_ptrs++;
392 version = *arg_ptrs;
393
394 partition_info->ep_id = (uint16_t)info;
395 partition_info->execution_ctx_count = (uint16_t)(info >> 16);
396 partition_info->properties = (uint32_t)(info >> 32);
397 partition_info->protocol_uuid[0] = (uint32_t)uuid_lo;
398 partition_info->protocol_uuid[1] = (uint32_t)(uuid_lo >> 32);
399 partition_info->protocol_uuid[2] = (uint32_t)uuid_high;
400 partition_info->protocol_uuid[3] = (uint32_t)(uuid_high >> 32);
401 partition_info->image_uuid[0] = (uint32_t)image_uuid_lo;
402 partition_info->image_uuid[1] = (uint32_t)(image_uuid_lo >> 32);
403 partition_info->image_uuid[2] = (uint32_t)image_uuid_high;
404 partition_info->image_uuid[3] = (uint32_t)(image_uuid_high >> 32);
405 partition_info->ffa_version = (uint32_t)version;
406 return true;
407 }
408
409 /*
410 * This function is called by the SPMD in response to
411 * an FFA_PARTITION_INFO_GET_REG ABI invocation by the SPMC. Secure partitions
412 * are allowed to discover the presence of EL3 SPMD logical partitions by
413 * invoking the aforementioned ABI and this function populates the required
414 * information about EL3 SPMD logical partitions.
415 */
spmd_el3_populate_logical_partition_info(void * handle,uint64_t x1,uint64_t x2,uint64_t x3)416 uint64_t spmd_el3_populate_logical_partition_info(void *handle, uint64_t x1,
417 uint64_t x2, uint64_t x3)
418 {
419 #if ENABLE_SPMD_LP
420 uint32_t target_uuid[4] = { 0 };
421 uint32_t w0;
422 uint32_t w1;
423 uint32_t w2;
424 uint32_t w3;
425 uint16_t start_index;
426 uint16_t tag;
427 static struct ffa_partition_info_v1_3 partitions[EL3_SPMD_MAX_NUM_LP];
428 uint16_t lp_count = 0;
429 uint16_t max_idx = 0;
430 uint16_t curr_idx = 0;
431 uint8_t num_entries_to_ret = 0;
432 struct ffa_value ret = { 0 };
433 uint64_t *arg_ptrs = (uint64_t *)&ret + 3;
434
435 w0 = (uint32_t)(x1 & 0xFFFFFFFFU);
436 w1 = (uint32_t)(x1 >> 32);
437 w2 = (uint32_t)(x2 & 0xFFFFFFFFU);
438 w3 = (uint32_t)(x2 >> 32);
439
440 target_uuid[0] = w0;
441 target_uuid[1] = w1;
442 target_uuid[2] = w2;
443 target_uuid[3] = w3;
444
445 start_index = (uint16_t)(x3 & 0xFFFFU);
446 tag = (uint16_t)((x3 >> 16) & 0xFFFFU);
447
448 assert(handle == cm_get_context(SECURE));
449
450 if (tag != 0) {
451 VERBOSE("Tag is not 0. Cannot return partition info.\n");
452 return spmd_ffa_error_return(handle, FFA_ERROR_RETRY);
453 }
454
455 memset(&partitions, 0, sizeof(partitions));
456
457 spmd_fill_lp_info_array(&partitions, target_uuid, &lp_count);
458
459 if (lp_count == 0) {
460 VERBOSE("No SPDM EL3 logical partitions exist.\n");
461 return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
462 }
463
464 if (start_index >= lp_count) {
465 VERBOSE("start_index = %d, lp_count = %d (start index must be"
466 " less than partition count.\n",
467 start_index, lp_count);
468 return spmd_ffa_error_return(handle,
469 FFA_ERROR_INVALID_PARAMETER);
470 }
471
472 max_idx = lp_count - 1;
473 num_entries_to_ret = (max_idx - start_index) + 1;
474 num_entries_to_ret =
475 MIN(num_entries_to_ret, (uint8_t)MAX_INFO_REGS_ENTRIES_PER_CALL);
476 curr_idx = start_index + num_entries_to_ret - 1;
477 assert(curr_idx <= max_idx);
478
479 ret.func = FFA_SUCCESS_SMC64;
480 ret.arg2 = (uint64_t)((sizeof(struct ffa_partition_info_v1_3) & 0xFFFFU) << 48);
481 ret.arg2 |= (uint64_t)(curr_idx << 16);
482 ret.arg2 |= (uint64_t)max_idx;
483
484 for (uint16_t idx = start_index; idx <= curr_idx; ++idx) {
485 spmd_pack_lp_count_props(arg_ptrs, partitions[idx].ep_id,
486 partitions[idx].execution_ctx_count,
487 partitions[idx].properties);
488 arg_ptrs++;
489 if (is_null_uuid(target_uuid)) {
490 /* Protocol UUID occupies two 64-bit registers. */
491 spmd_pack_lp_uuid(arg_ptrs, (arg_ptrs + 1),
492 partitions[idx].protocol_uuid);
493 }
494 arg_ptrs += 2;
495
496 /* Image UUID occupies two 64-bit registers. */
497 spmd_pack_lp_uuid(arg_ptrs, (arg_ptrs + 1),
498 partitions[idx].image_uuid);
499 arg_ptrs += 2;
500
501 /* FF-A version. */
502 *arg_ptrs = partitions[idx].ffa_version;
503 arg_ptrs += 1;
504 }
505
506 SMC_RET18(handle, ret.func, ret.arg1, ret.arg2, ret.arg3, ret.arg4,
507 ret.arg5, ret.arg6, ret.arg7, ret.arg8, ret.arg9, ret.arg10,
508 ret.arg11, ret.arg12, ret.arg13, ret.arg14, ret.arg15,
509 ret.arg16, ret.arg17);
510 #else
511 return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
512 #endif
513 }
514
515 /* This function can be used by an SPMD logical partition to invoke the
516 * FFA_PARTITION_INFO_GET_REGS ABI to the SPMC, to discover the secure
517 * partitions in the system. The function takes a UUID, start index and
518 * tag and the partition information are returned in an ffa_value structure
519 * and can be consumed by using appropriate helper functions.
520 */
spmd_el3_invoke_partition_info_get(const uint32_t target_uuid[4],const uint16_t start_index,const uint16_t tag,struct ffa_value * retval)521 bool spmd_el3_invoke_partition_info_get(
522 const uint32_t target_uuid[4],
523 const uint16_t start_index,
524 const uint16_t tag,
525 struct ffa_value *retval)
526 {
527 #if ENABLE_SPMD_LP
528 uint64_t rc = UINT64_MAX;
529 spmd_spm_core_context_t *ctx = spmd_get_context();
530
531 if (retval == NULL) {
532 return false;
533 }
534
535 memset(retval, 0, sizeof(*retval));
536
537 if (!is_spmc_inited) {
538 VERBOSE("Cannot discover partition before,"
539 " SPMC is initialized.\n");
540 spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
541 return true;
542 }
543
544 if (tag != 0) {
545 VERBOSE("Tag must be zero. other tags unsupported\n");
546 spmd_encode_ffa_error(retval,
547 FFA_ERROR_INVALID_PARAMETER);
548 return true;
549 }
550
551 /* Save the non-secure context before entering SPMC */
552 #if SPMD_SPM_AT_SEL2
553 cm_el2_sysregs_context_save(NON_SECURE);
554 cm_el2_sysregs_context_save_gic(NON_SECURE);
555 #else
556 cm_el1_sysregs_context_save(NON_SECURE);
557 #endif
558
559 spmd_build_ffa_info_get_regs(ctx, target_uuid, start_index, tag);
560 spmd_logical_sp_set_info_regs_ongoing(ctx);
561
562 rc = spmd_spm_core_sync_entry(ctx);
563 if (rc != 0ULL) {
564 ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
565 plat_my_core_pos());
566 panic();
567 }
568
569 spmd_logical_sp_reset_info_regs_ongoing(ctx);
570 spmd_encode_ctx_to_ffa_value(ctx, retval);
571
572 assert(is_ffa_error(retval) || is_ffa_success(retval));
573
574 #if SPMD_SPM_AT_SEL2
575 cm_el2_sysregs_context_restore(NON_SECURE);
576 cm_el2_sysregs_context_restore_gic(NON_SECURE);
577 #else
578 cm_el1_sysregs_context_restore(NON_SECURE);
579 #endif
580 cm_set_next_eret_context(NON_SECURE);
581 return true;
582 #else
583 return false;
584 #endif
585 }
586
587 /*******************************************************************************
588 * Common helper function for sending FF-A Direct Requests from EL3.
589 * This function contains the common logic for both Direct Request and
590 * Direct Request2 ABIs.
591 *
592 * x1, x2, x3, x4, x5, x6, x7: Parameters as specified in FF-A specification
593 * ffa_msg_function_id: FFA function ID to use (Direct Req or Direct Req2)
594 * handle: Context handle (must be non-secure)
595 * retval: Output parameter for direct response values
596 * return true if retval has valid values, false otherwise
597 ******************************************************************************/
spmd_el3_ffa_msg_direct_req_common(uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,uint64_t x5,uint64_t x6,uint64_t x7,uint64_t ffa_msg_function_id,void * handle,struct ffa_value * retval)598 static bool spmd_el3_ffa_msg_direct_req_common(uint64_t x1,
599 uint64_t x2,
600 uint64_t x3,
601 uint64_t x4,
602 uint64_t x5,
603 uint64_t x6,
604 uint64_t x7,
605 uint64_t ffa_msg_function_id,
606 void *handle,
607 struct ffa_value *retval)
608 {
609 #if ENABLE_SPMD_LP
610
611 uint64_t rc = UINT64_MAX;
612 spmd_spm_core_context_t *ctx = spmd_get_context();
613
614 if (retval == NULL) {
615 return false;
616 }
617
618 memset(retval, 0, sizeof(*retval));
619
620 if (!is_spmd_lp_inited || !is_spmc_inited) {
621 VERBOSE("Cannot send SPMD logical partition direct message,"
622 " Partitions not initialized or SPMC not initialized.\n");
623 spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
624 return true;
625 }
626
627 /*
628 * Current context must be non-secure. API is expected to be used
629 * when entry into EL3 and the SPMD logical partition is via an
630 * interrupt that occurs when execution is in normal world and
631 * SMCs from normal world. FF-A compliant SPMCs are expected to
632 * trap interrupts during secure execution in lower ELs since they
633 * are usually not re-entrant and SMCs from secure world can be
634 * handled synchronously. There is no known use case for an SPMD
635 * logical partition to send a direct message to another partition
636 * in response to a secure interrupt or SMCs from secure world.
637 */
638 if (handle != cm_get_context(NON_SECURE)) {
639 VERBOSE("Handle must be for the non-secure context.\n");
640 spmd_encode_ffa_error(retval, FFA_ERROR_DENIED);
641 return true;
642 }
643
644 if (!is_spmd_lp_id(ffa_endpoint_source(x1))) {
645 VERBOSE("Source ID must be valid SPMD logical partition"
646 " ID.\n");
647 spmd_encode_ffa_error(retval,
648 FFA_ERROR_INVALID_PARAMETER);
649 return true;
650 }
651
652 if (is_spmd_lp_id(ffa_endpoint_destination(x1))) {
653 VERBOSE("Destination ID must not be SPMD logical partition"
654 " ID.\n");
655 spmd_encode_ffa_error(retval,
656 FFA_ERROR_INVALID_PARAMETER);
657 return true;
658 }
659
660 if (!ffa_is_secure_world_id(ffa_endpoint_destination(x1))) {
661 VERBOSE("Destination ID must be secure world ID.\n");
662 spmd_encode_ffa_error(retval,
663 FFA_ERROR_INVALID_PARAMETER);
664 return true;
665 }
666
667 if (ffa_endpoint_destination(x1) == SPMD_DIRECT_MSG_ENDPOINT_ID) {
668 VERBOSE("Destination ID must not be SPMD ID.\n");
669 spmd_encode_ffa_error(retval,
670 FFA_ERROR_INVALID_PARAMETER);
671 return true;
672 }
673
674 /* Save the non-secure context before entering SPMC */
675 #if SPMD_SPM_AT_SEL2
676 cm_el2_sysregs_context_save(NON_SECURE);
677 cm_el2_sysregs_context_save_gic(NON_SECURE);
678 #else
679 cm_el1_sysregs_context_save(NON_SECURE);
680 #endif
681
682 /*
683 * Perform synchronous entry into the SPMC. Synchronous entry is
684 * required because the spec requires that a direct message request
685 * from an SPMD LP look like a function call from it's perspective.
686 */
687 spmd_build_direct_message_req(ctx, ffa_msg_function_id,
688 x1, x2, x3, x4, x5, x6, x7);
689 spmd_logical_sp_set_dir_req_ongoing(ctx);
690
691 rc = spmd_spm_core_sync_entry(ctx);
692
693 spmd_logical_sp_reset_dir_req_ongoing(ctx);
694
695 if (rc != 0ULL) {
696 ERROR("%s failed (%lx) on CPU%u\n", __func__, rc,
697 plat_my_core_pos());
698 panic();
699 } else {
700 spmd_encode_ctx_to_ffa_value(ctx, retval);
701
702 /*
703 * Only expect error or direct response,
704 * spmd_spm_core_sync_exit should not be called on other paths.
705 * Checks are asserts since the LSP can fail gracefully if the
706 * source or destination ids are not the same. Panic'ing would
707 * not provide any benefit.
708 */
709 assert(is_ffa_error(retval) || is_ffa_direct_msg_resp(retval));
710 assert(is_ffa_error(retval) ||
711 (ffa_endpoint_destination(retval->arg1) ==
712 ffa_endpoint_source(x1)));
713 assert(is_ffa_error(retval) ||
714 (ffa_endpoint_source(retval->arg1) ==
715 ffa_endpoint_destination(x1)));
716 }
717
718 #if SPMD_SPM_AT_SEL2
719 cm_el2_sysregs_context_restore(NON_SECURE);
720 cm_el2_sysregs_context_restore_gic(NON_SECURE);
721 #else
722 cm_el1_sysregs_context_restore(NON_SECURE);
723 #endif
724 cm_set_next_eret_context(NON_SECURE);
725
726 return true;
727 #else
728 return false;
729 #endif
730 }
731
732 /*******************************************************************************
733 * This function sends an FF-A Direct Request2 from a partition in EL3 to a
734 * partition that may reside under an SPMC (only lower ELs supported). The main
735 * use of this API is for SPMD logical partitions.
736 * The API is expected to be used when there are platform specific SMCs that
737 * need to be routed to a secure partition that is FF-A compliant or when
738 * there are group 0 interrupts that need to be handled first in EL3 and then
739 * forwarded to an FF-A compliant secure partition. Therefore, it is expected
740 * that the handle to the context provided belongs to the non-secure context.
741 * This also means that interrupts/SMCs that trap to EL3 during secure execution
742 * cannot use this API.
743 * x1, x2, x3, and x4 are encoded as specified in the FF-A specification.
744 * retval is used to pass the direct response values to the caller.
745 * The function returns true if retval has valid values, and false otherwise.
746 ******************************************************************************/
spmd_el3_ffa_msg_direct_req2(uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * handle,struct ffa_value * retval)747 bool spmd_el3_ffa_msg_direct_req2(uint64_t x1,
748 uint64_t x2,
749 uint64_t x3,
750 uint64_t x4,
751 void *handle,
752 struct ffa_value *retval)
753 {
754 return spmd_el3_ffa_msg_direct_req_common(x1, x2, x3, x4, 0U, 0U, 0U,
755 FFA_MSG_SEND_DIRECT_REQ2_SMC64,
756 handle,
757 retval);
758 }
759
760
761 /*******************************************************************************
762 * This function sends an FF-A Direct Request from a partition in EL3 to SPMC
763 * or a partition that may reside under an SPMC (only lower ELs supported). The
764 * main use of this API is for SPMD LSP (logical secure partitions).
765 * The API is expected to be used when:
766 * - There are platform specific SMCs that need to be routed to a secure
767 partition that is FF-A compliant.
768 * - There are group 0 interrupts that need to be handled first in EL3 and then
769 * forwarded to an FF-A compliant secure partition.
770 * - Framework messages need to be sent by an LSP to SPMC for live activating
771 * a Secure Partition in lower ELs.
772
773 * Therefore, it is expected that the handle to the context provided belongs to
774 * the non-secure context. This also means that interrupts/SMCs that trap to EL3
775 * during secure execution cannot use this API.
776 * x1, x2, x3, x4, x5, x6 and x7 are encoded as specified in the FF-A spec.
777 * retval is used to pass the direct response values to the caller.
778 * The function returns true if retval has valid values, and false otherwise.
779 ******************************************************************************/
spmd_el3_ffa_msg_direct_req(uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,uint64_t x5,uint64_t x6,uint64_t x7,void * handle,struct ffa_value * retval)780 bool spmd_el3_ffa_msg_direct_req(uint64_t x1,
781 uint64_t x2,
782 uint64_t x3,
783 uint64_t x4,
784 uint64_t x5,
785 uint64_t x6,
786 uint64_t x7,
787 void *handle,
788 struct ffa_value *retval)
789 {
790 return spmd_el3_ffa_msg_direct_req_common(x1, x2, x3, x4, x5, x6, x7,
791 FFA_MSG_SEND_DIRECT_REQ_SMC64,
792 handle,
793 retval);
794 }
795
796 bool
is_spmd_logical_sp_info_regs_req_in_progress(const spmd_spm_core_context_t * ctx)797 is_spmd_logical_sp_info_regs_req_in_progress(const spmd_spm_core_context_t *ctx)
798 {
799 #if ENABLE_SPMD_LP
800 return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_INFO_GET_REG_ONGOING)
801 == SPMD_LP_FFA_INFO_GET_REG_ONGOING);
802 #else
803 return false;
804 #endif
805 }
806
is_spmd_logical_sp_dir_req_in_progress(const spmd_spm_core_context_t * ctx)807 bool is_spmd_logical_sp_dir_req_in_progress(const spmd_spm_core_context_t *ctx)
808 {
809 #if ENABLE_SPMD_LP
810 return ((ctx->spmd_lp_sync_req_ongoing & SPMD_LP_FFA_DIR_REQ_ONGOING)
811 == SPMD_LP_FFA_DIR_REQ_ONGOING);
812 #else
813 return false;
814 #endif
815 }
816
817 #if SUPPORT_SP_LIVE_ACTIVATION
convert_ffa_error_code_to_lfa(int32_t ffa_error_code)818 enum lfa_retc convert_ffa_error_code_to_lfa(int32_t ffa_error_code)
819 {
820 switch (ffa_error_code) {
821 case FFA_ERROR_NOT_SUPPORTED:
822 return LFA_NOT_SUPPORTED;
823 case FFA_ERROR_INVALID_PARAMETER:
824 return LFA_INVALID_PARAMETERS;
825 case FFA_ERROR_NO_MEMORY:
826 return LFA_NO_MEMORY;
827 case FFA_ERROR_DENIED:
828 return LFA_COMPONENT_WRONG_STATE;
829 case FFA_ERROR_INTERRUPTED:
830 __fallthrough;
831 case FFA_ERROR_BUSY:
832 __fallthrough;
833 case FFA_ERROR_RETRY:
834 return LFA_BUSY;
835 case FFA_ERROR_ABORTED:
836 return LFA_CRITICAL_ERROR;
837 default:
838 return LFA_ACTIVATION_FAILED;
839 }
840 }
841
spmd_lsp_build_live_activation_request(uint16_t lsp_id,uint16_t sp_id,uintptr_t image_base,uint32_t image_page_count,uintptr_t manifest_base,uint32_t manifest_page_count,uint64_t msg_flags,enum lfa_retc * lfa_ret,struct ffa_value * retval)842 static bool spmd_lsp_build_live_activation_request(
843 uint16_t lsp_id, uint16_t sp_id, uintptr_t image_base,
844 uint32_t image_page_count, uintptr_t manifest_base,
845 uint32_t manifest_page_count, uint64_t msg_flags,
846 enum lfa_retc *lfa_ret, struct ffa_value *retval)
847 {
848 bool status;
849 uint64_t send_recv_id;
850 cpu_context_t *handle;
851 uint64_t x4, x5, x6, x7;
852
853 x4 = image_base;
854 x5 = image_page_count;
855 x6 = manifest_base;
856 x7 = manifest_page_count;
857
858 /* Get a reference to the non-secure context */
859 handle = cm_get_context(NON_SECURE);
860 assert(handle != NULL);
861
862 if (!is_spmd_lp_id(lsp_id)) {
863 ERROR("Invalid SPMD Logical Partition ID (0x%x)\n", lsp_id);
864 *lfa_ret = convert_ffa_error_code_to_lfa(
865 FFA_ERROR_INVALID_PARAMETER);
866 return false;
867 }
868
869 if (!ffa_is_secure_world_id(sp_id)) {
870 ERROR("Invalid Secure Partition ID (0x%x) specified for live activation\n",
871 sp_id);
872 *lfa_ret = convert_ffa_error_code_to_lfa(
873 FFA_ERROR_INVALID_PARAMETER);
874 return false;
875 }
876
877 /*
878 * Build a direct request framework message for partition live activation
879 * request. Sender is SPMD LSP and receiver is SPMC.
880 */
881 send_recv_id = (lsp_id << 16) | spmd_spmc_id_get();
882
883 status = spmd_el3_ffa_msg_direct_req(send_recv_id, msg_flags, sp_id, x4,
884 x5, x6, x7, (void *)handle,
885 retval);
886
887 if (!status) {
888 ERROR("Failed to build SP live activation request.\n");
889 panic();
890 }
891
892 return true;
893 }
894
895 static enum lfa_retc
spmd_lsp_check_live_activation_response(struct ffa_value retval,uint64_t resp_msg)896 spmd_lsp_check_live_activation_response(struct ffa_value retval,
897 uint64_t resp_msg)
898 {
899 /*
900 * SPMC does not support framework message which implies that Live
901 * Activation cannot be supported.
902 */
903 if (is_ffa_error(&retval)) {
904 return convert_ffa_error_code_to_lfa((int32_t)retval.arg2);
905 }
906
907 /* Check the direct response message fields. */
908 if (retval.arg2 != resp_msg) {
909 ERROR("SPMC failed to process live activation message\n");
910 return LFA_ACTIVATION_FAILED;
911 }
912
913 /* Check if the response indicates any kind of failure. */
914 if (retval.arg3 != 0U) {
915 return convert_ffa_error_code_to_lfa((int32_t)retval.arg3);
916 }
917
918 /* SUCCESS */
919 return LFA_SUCCESS;
920 }
921
spmd_lsp_start_request_sp_live_activation(uint16_t lsp_id,uint16_t sp_id,uintptr_t image_base,uint32_t image_page_count,uintptr_t manifest_base,uint32_t manifest_page_count)922 enum lfa_retc spmd_lsp_start_request_sp_live_activation(
923 uint16_t lsp_id, uint16_t sp_id, uintptr_t image_base,
924 uint32_t image_page_count, uintptr_t manifest_base,
925 uint32_t manifest_page_count)
926 {
927 /* Message flags: */
928 uint64_t msg_flags = FFA_FWK_MSG_BIT |
929 LSP_FWK_MSG_START_LIVE_ACTIVATION_REQ;
930 enum lfa_retc lfa_ret = LFA_ACTIVATION_FAILED;
931 bool proceed;
932 struct ffa_value ffa_ret = { 0 };
933 uint64_t resp_msg = 0U;
934
935 assert(image_base != 0U && image_page_count != 0U);
936 proceed = spmd_lsp_build_live_activation_request(
937 lsp_id, sp_id, image_base, image_page_count, manifest_base,
938 manifest_page_count, msg_flags, &lfa_ret, &ffa_ret);
939
940 if (!proceed) {
941 return lfa_ret;
942 }
943
944 resp_msg = (FFA_FWK_MSG_BIT | LSP_FWK_MSG_START_LIVE_ACTIVATION_RESP);
945 lfa_ret = spmd_lsp_check_live_activation_response(ffa_ret, resp_msg);
946 return lfa_ret;
947 }
948
spmd_lsp_finish_request_sp_live_activation(uint16_t lsp_id,uint16_t sp_id)949 enum lfa_retc spmd_lsp_finish_request_sp_live_activation(uint16_t lsp_id,
950 uint16_t sp_id)
951 {
952 /* Message flags: */
953 uint64_t msg_flags = FFA_FWK_MSG_BIT |
954 LSP_FWK_MSG_FINISH_LIVE_ACTIVATION_REQ;
955 enum lfa_retc lfa_ret = LFA_ACTIVATION_FAILED;
956 bool proceed;
957 struct ffa_value ffa_ret = { 0 };
958 uint64_t resp_msg = 0U;
959
960 proceed = spmd_lsp_build_live_activation_request(
961 lsp_id, sp_id, 0, 0, 0, 0, msg_flags, &lfa_ret, &ffa_ret);
962
963 if (!proceed) {
964 return lfa_ret;
965 }
966
967 resp_msg = (FFA_FWK_MSG_BIT | LSP_FWK_MSG_FINISH_LIVE_ACTIVATION_RESP);
968 lfa_ret = spmd_lsp_check_live_activation_response(ffa_ret, resp_msg);
969 return lfa_ret;
970 }
971
972 #endif /* SUPPORT_SP_LIVE_ACTIVATION */
973