diff --git a/common/uuid.c b/common/uuid.c index ac6db50a0..3e47eb4ba 100644 --- a/common/uuid.c +++ b/common/uuid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -132,3 +132,27 @@ int read_uuid(uint8_t *dest, char *uuid) return 0; } +/* + * Helper function to check if 2 UUIDs match. + */ +bool uuid_match(uint32_t *uuid1, uint32_t *uuid2) +{ + return !memcmp(uuid1, uuid2, sizeof(uint32_t) * 4); +} + +/* + * Helper function to copy from one UUID struct to another. + */ +void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid) +{ + to_uuid[0] = from_uuid[0]; + to_uuid[1] = from_uuid[1]; + to_uuid[2] = from_uuid[2]; + to_uuid[3] = from_uuid[3]; +} + +bool is_null_uuid(uint32_t *uuid) +{ + return (uuid[0] == 0 && uuid[1] == 0 && + uuid[2] == 0 && uuid[3] == 0); +} diff --git a/include/common/uuid.h b/include/common/uuid.h index 5651d0d58..c8dd68197 100644 --- a/include/common/uuid.h +++ b/include/common/uuid.h @@ -1,15 +1,18 @@ /* - * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef UUID_H -#define UUID_H +#ifndef UUID_COMMON_H +#define UUID_COMMON_H #define UUID_BYTES_LENGTH 16 #define UUID_STRING_LENGTH 36 int read_uuid(uint8_t *dest, char *uuid); +bool uuid_match(uint32_t *uuid1, uint32_t *uuid2); +void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid); +bool is_null_uuid(uint32_t *uuid); -#endif /* UUID_H */ +#endif /* UUID_COMMON_H */ diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 08365796c..153d206b9 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -195,6 +195,11 @@ #define SPMC_SECURE_ID_MASK U(1) #define SPMC_SECURE_ID_SHIFT U(15) +/* + * Partition Count Flag in FFA_PARTITION_INFO_GET. + */ +#define FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK U(1 << 0) + /* * Mask for source and destination endpoint id in * a direct message request/response. diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h index 31ebe3612..1afd6880a 100644 --- a/services/std_svc/spm/el3_spmc/spmc.h +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -184,6 +184,24 @@ struct ns_endpoint_desc { uint32_t ffa_version; }; +/** + * Holds information returned for each partition by the FFA_PARTITION_INFO_GET + * interface. + */ +struct ffa_partition_info_v1_0 { + uint16_t ep_id; + uint16_t execution_ctx_count; + uint32_t properties; +}; + +/* Extended structure for v1.1. */ +struct ffa_partition_info_v1_1 { + uint16_t ep_id; + uint16_t execution_ctx_count; + uint32_t properties; + uint32_t uuid[4]; +}; + /* Setup Function for different SP types. */ void spmc_sp_common_setup(struct secure_partition_desc *sp, entry_point_info_t *ep_info); diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index 1f6190814..ece4df951 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,9 @@ #include +/* Declare the maximum number of SPs and El3 LPs. */ +#define MAX_SP_LP_PARTITIONS SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT + /* * Allocate a secure partition descriptor to describe each SP in the system that * does not reside at EL3. @@ -727,6 +731,251 @@ static uint64_t rxtx_unmap_handler(uint32_t smc_fid, SMC_RET1(handle, FFA_SUCCESS_SMC32); } +/* + * Collate the partition information in a v1.1 partition information + * descriptor format, this will be converter later if required. + */ +static int partition_info_get_handler_v1_1(uint32_t *uuid, + struct ffa_partition_info_v1_1 + *partitions, + uint32_t max_partitions, + uint32_t *partition_count) +{ + uint32_t index; + struct ffa_partition_info_v1_1 *desc; + bool null_uuid = is_null_uuid(uuid); + struct el3_lp_desc *el3_lp_descs = get_el3_lp_array(); + + /* Deal with Logical Partitions. */ + for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) { + if (null_uuid || uuid_match(uuid, el3_lp_descs[index].uuid)) { + /* Found a matching UUID, populate appropriately. */ + if (*partition_count >= max_partitions) { + return FFA_ERROR_NO_MEMORY; + } + + desc = &partitions[*partition_count]; + desc->ep_id = el3_lp_descs[index].sp_id; + desc->execution_ctx_count = PLATFORM_CORE_COUNT; + desc->properties = el3_lp_descs[index].properties; + if (null_uuid) { + copy_uuid(desc->uuid, el3_lp_descs[index].uuid); + } + (*partition_count)++; + } + } + + /* Deal with physical SP's. */ + for (index = 0U; index < SECURE_PARTITION_COUNT; index++) { + if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) { + /* Found a matching UUID, populate appropriately. */ + if (*partition_count >= max_partitions) { + return FFA_ERROR_NO_MEMORY; + } + + desc = &partitions[*partition_count]; + desc->ep_id = sp_desc[index].sp_id; + /* + * Execution context count must match No. cores for + * S-EL1 SPs. + */ + desc->execution_ctx_count = PLATFORM_CORE_COUNT; + desc->properties = sp_desc[index].properties; + if (null_uuid) { + copy_uuid(desc->uuid, sp_desc[index].uuid); + } + (*partition_count)++; + } + } + return 0; +} + +/* + * Handle the case where that caller only wants the count of partitions + * matching a given UUID and does not want the corresponding descriptors + * populated. + */ +static uint32_t partition_info_get_handler_count_only(uint32_t *uuid) +{ + uint32_t index = 0; + uint32_t partition_count = 0; + bool null_uuid = is_null_uuid(uuid); + struct el3_lp_desc *el3_lp_descs = get_el3_lp_array(); + + /* Deal with Logical Partitions. */ + for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) { + if (null_uuid || + uuid_match(uuid, el3_lp_descs[index].uuid)) { + (partition_count)++; + } + } + + /* Deal with physical SP's. */ + for (index = 0U; index < SECURE_PARTITION_COUNT; index++) { + if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) { + (partition_count)++; + } + } + return partition_count; +} + +/* + * If the caller of the PARTITION_INFO_GET ABI was a v1.0 caller, populate + * the coresponding descriptor format from the v1.1 descriptor array. + */ +static uint64_t partition_info_populate_v1_0(struct ffa_partition_info_v1_1 + *partitions, + struct mailbox *mbox, + int partition_count) +{ + uint32_t index; + uint32_t buf_size; + uint32_t descriptor_size; + struct ffa_partition_info_v1_0 *v1_0_partitions = + (struct ffa_partition_info_v1_0 *) mbox->rx_buffer; + + buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE; + descriptor_size = partition_count * + sizeof(struct ffa_partition_info_v1_0); + + if (descriptor_size > buf_size) { + return FFA_ERROR_NO_MEMORY; + } + + for (index = 0U; index < partition_count; index++) { + v1_0_partitions[index].ep_id = partitions[index].ep_id; + v1_0_partitions[index].execution_ctx_count = + partitions[index].execution_ctx_count; + v1_0_partitions[index].properties = + partitions[index].properties; + } + return 0; +} + +/* + * Main handler for FFA_PARTITION_INFO_GET which supports both FF-A v1.1 and + * v1.0 implementations. + */ +static uint64_t partition_info_get_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + int ret; + uint32_t partition_count = 0; + uint32_t size = 0; + uint32_t ffa_version = get_partition_ffa_version(secure_origin); + struct mailbox *mbox; + uint64_t info_get_flags; + bool count_only; + uint32_t uuid[4]; + + uuid[0] = x1; + uuid[1] = x2; + uuid[2] = x3; + uuid[3] = x4; + + /* Determine if the Partition descriptors should be populated. */ + info_get_flags = SMC_GET_GP(handle, CTX_GPREG_X5); + count_only = (info_get_flags & FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK); + + /* Handle the case where we don't need to populate the descriptors. */ + if (count_only) { + partition_count = partition_info_get_handler_count_only(uuid); + if (partition_count == 0) { + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + } else { + struct ffa_partition_info_v1_1 partitions[MAX_SP_LP_PARTITIONS]; + + /* + * Handle the case where the partition descriptors are required, + * check we have the buffers available and populate the + * appropriate structure version. + */ + + /* Obtain the v1.1 format of the descriptors. */ + ret = partition_info_get_handler_v1_1(uuid, partitions, + MAX_SP_LP_PARTITIONS, + &partition_count); + + /* Check if an error occurred during discovery. */ + if (ret != 0) { + goto err; + } + + /* If we didn't find any matches the UUID is unknown. */ + if (partition_count == 0) { + ret = FFA_ERROR_INVALID_PARAMETER; + goto err; + } + + /* Obtain the partition mailbox RX/TX buffer pair descriptor. */ + mbox = spmc_get_mbox_desc(secure_origin); + + /* + * If the caller has not bothered registering its RX/TX pair + * then return an error code. + */ + spin_lock(&mbox->lock); + if (mbox->rx_buffer == NULL) { + ret = FFA_ERROR_BUSY; + goto err_unlock; + } + + /* Ensure the RX buffer is currently free. */ + if (mbox->state != MAILBOX_STATE_EMPTY) { + ret = FFA_ERROR_BUSY; + goto err_unlock; + } + + /* Zero the RX buffer before populating. */ + (void)memset(mbox->rx_buffer, 0, + mbox->rxtx_page_count * FFA_PAGE_SIZE); + + /* + * Depending on the FF-A version of the requesting partition + * we may need to convert to a v1.0 format otherwise we can copy + * directly. + */ + if (ffa_version == MAKE_FFA_VERSION(U(1), U(0))) { + ret = partition_info_populate_v1_0(partitions, + mbox, + partition_count); + if (ret != 0) { + goto err_unlock; + } + } else { + uint32_t buf_size = mbox->rxtx_page_count * + FFA_PAGE_SIZE; + + /* Ensure the descriptor will fit in the buffer. */ + size = sizeof(struct ffa_partition_info_v1_1); + if (partition_count * size > buf_size) { + ret = FFA_ERROR_NO_MEMORY; + goto err_unlock; + } + memcpy(mbox->rx_buffer, partitions, + partition_count * size); + } + + mbox->state = MAILBOX_STATE_FULL; + spin_unlock(&mbox->lock); + } + SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, partition_count, size); + +err_unlock: + spin_unlock(&mbox->lock); +err: + return spmc_ffa_error_return(handle, ret); +} + /******************************************************************************* * This function will parse the Secure Partition Manifest. From manifest, it * will fetch details for preparing Secure partition image context and secure @@ -1142,6 +1391,11 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, return rxtx_unmap_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); + case FFA_PARTITION_INFO_GET: + return partition_info_get_handler(smc_fid, secure_origin, x1, + x2, x3, x4, cookie, handle, + flags); + case FFA_MSG_WAIT: return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags);