Introduce struct ffa_uuid together with nil/equality/set helpers, and
use it end-to-end in the partition-info plumbing.
The SP and VM enumeration paths now build UUIDs from the guest
registers, call a new ffa_copy_info() helper and ensure non-nil UUID
queries only return matching SP entries, relying on firmware UUID
filtering. VM entries are skipped because we do not track per-VM UUIDs.
Count requests and subscriber initialisation are updated accordingly so
firmware is always called with an explicit UUID. This keeps count and
listing requests aligned with the FF-A v1.1 rules while preserving the
Linux compatibility workaround for v1.2 requesters.
Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com>
---
Changes in v1:
- Use GENMASK in ffa_partition_info_get instead of explicit values.
- Use ACCESS_ONCE to read guest_vers
- use is_64bit_domain to get current domain 32/64 bit support
---
xen/arch/arm/tee/ffa_partinfo.c | 209 ++++++++++++++++++++------------
xen/arch/arm/tee/ffa_private.h | 21 ++++
2 files changed, 154 insertions(+), 76 deletions(-)
diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c
index c9faf5415853..bf906ed0c88f 100644
--- a/xen/arch/arm/tee/ffa_partinfo.c
+++ b/xen/arch/arm/tee/ffa_partinfo.c
@@ -33,7 +33,7 @@ static uint16_t subscr_vm_created_count __read_mostly;
static uint16_t *subscr_vm_destroyed __read_mostly;
static uint16_t subscr_vm_destroyed_count __read_mostly;
-static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
+static int32_t ffa_partition_info_get(struct ffa_uuid uuid, uint32_t flags,
uint32_t *count, uint32_t *fpi_size)
{
struct arm_smccc_1_2_regs arg = {
@@ -41,15 +41,12 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
.a5 = flags,
};
struct arm_smccc_1_2_regs resp;
- uint32_t ret;
+ int32_t ret;
- if ( uuid )
- {
- arg.a1 = uuid[0];
- arg.a2 = uuid[1];
- arg.a3 = uuid[2];
- arg.a4 = uuid[3];
- }
+ arg.a1 = uuid.val[0] & GENMASK(31, 0);
+ arg.a2 = (uuid.val[0] >> 32) & GENMASK(31, 0);
+ arg.a3 = uuid.val[1] & GENMASK(31, 0);
+ arg.a4 = (uuid.val[1] >> 32) & GENMASK(31, 0);
arm_smccc_1_2_smc(&arg, &resp);
@@ -63,7 +60,26 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
return ret;
}
-static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count)
+static int32_t ffa_copy_info(void **dst, void *dst_end, const void *src,
+ uint32_t dst_size, uint32_t src_size)
+{
+ uint8_t *pos = *dst;
+ uint8_t *end = dst_end;
+
+ if ( pos > end - dst_size )
+ return FFA_RET_NO_MEMORY;
+
+ memcpy(pos, src, MIN(dst_size, src_size));
+
+ if ( dst_size > src_size )
+ memset(pos + src_size, 0, dst_size - src_size);
+
+ *dst = pos + dst_size;
+
+ return FFA_RET_OK;
+}
+
+static int32_t ffa_get_sp_count(struct ffa_uuid uuid, uint32_t *sp_count)
{
uint32_t src_size;
@@ -71,8 +87,8 @@ static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count)
sp_count, &src_size);
}
-static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count,
- void *dst_buf, void *end_buf,
+static int32_t ffa_get_sp_partinfo(struct ffa_uuid uuid, uint32_t *sp_count,
+ void **dst_buf, void *end_buf,
uint32_t dst_size)
{
int32_t ret;
@@ -120,17 +136,18 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count,
/* filter out SP not following bit 15 convention if any */
if ( FFA_ID_IS_SECURE(fpi->id) )
{
- if ( dst_buf > (end_buf - dst_size) )
- {
- ret = FFA_RET_NO_MEMORY;
- goto out;
- }
+ /*
+ * If VM is 1.0 but firmware is 1.1 we could have several entries
+ * with the same ID but different UUIDs. In this case the VM will
+ * get a list with several time the same ID.
+ * This is a non-compliance to the specification but 1.0 VMs should
+ * handle that on their own to simplify Xen implementation.
+ */
- memcpy(dst_buf, src_buf, MIN(src_size, dst_size));
- if ( dst_size > src_size )
- memset(dst_buf + src_size, 0, dst_size - src_size);
+ ret = ffa_copy_info(dst_buf, end_buf, src_buf, dst_size, src_size);
+ if ( ret )
+ goto out;
- dst_buf += dst_size;
count++;
}
@@ -144,69 +161,90 @@ out:
return ret;
}
-static int32_t ffa_get_vm_partinfo(uint32_t *vm_count, void *dst_buf,
- void *end_buf, uint32_t dst_size)
+static int32_t ffa_get_vm_partinfo(struct ffa_uuid uuid, uint32_t *vm_count,
+ void **dst_buf, void *end_buf,
+ uint32_t dst_size)
{
- struct ffa_ctx *curr_ctx = current->domain->arch.tee;
+ struct domain *d = current->domain;
+ struct ffa_ctx *curr_ctx = d->arch.tee;
struct ffa_ctx *dest_ctx;
uint32_t count = 0;
int32_t ret = FFA_RET_OK;
+ /*
+ * We do not have UUID info for VMs so use the 1.0 structure so that we set
+ * UUIDs to zero using memset
+ */
+ struct ffa_partition_info_1_0 info;
/*
- * There could potentially be a lot of VMs in the system and we could
- * hold the CPU for long here.
- * Right now there is no solution in FF-A specification to split
- * the work in this case.
- * TODO: Check how we could delay the work or have preemption checks.
+ * We do not have protocol UUIDs for VMs so if a request has non Nil UUID
+ * we must return an empty list.
*/
- read_lock(&ffa_ctx_list_rwlock);
- list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
+ if ( !ffa_uuid_is_nil(uuid) )
+ {
+ *vm_count = 0;
+ return FFA_RET_OK;
+ }
+
+ /*
+ * Workaround for Linux FF-A Driver not accepting to have its own
+ * entry in the list before FF-A v1.2 was supported.
+ * This workaround is generally acceptable for other implementations
+ * as the specification was not completely clear on wether or not
+ * the requester endpoint information should be included or not
+ */
+ if ( ACCESS_ONCE(curr_ctx->guest_vers) >= FFA_VERSION_1_2 )
+ {
+ /* Add caller VM information */
+ info.id = curr_ctx->ffa_id;
+ info.execution_context = curr_ctx->num_vcpus;
+ info.partition_properties = FFA_PART_VM_PROP;
+ if ( is_64bit_domain(d) )
+ info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
+
+ ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size, sizeof(info));
+ if ( ret )
+ return ret;
+
+ count++;
+ }
+
+ if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
{
/*
- * Do not include an entry for the caller VM as the spec is not
- * clearly mandating it and it is not supported by Linux.
+ * There could potentially be a lot of VMs in the system and we could
+ * hold the CPU for long here.
+ * Right now there is no solution in FF-A specification to split
+ * the work in this case.
+ * TODO: Check how we could delay the work or have preemption checks.
*/
- if ( dest_ctx != curr_ctx )
+ read_lock(&ffa_ctx_list_rwlock);
+ list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
{
- /*
- * We do not have UUID info for VMs so use
- * the 1.0 structure so that we set UUIDs to
- * zero using memset
- */
- struct ffa_partition_info_1_0 info;
+ /* Ignore the caller entry as it was already added */
+ if ( dest_ctx == curr_ctx )
+ continue;
- if ( dst_buf > (end_buf - dst_size) )
- {
- ret = FFA_RET_NO_MEMORY;
- goto out;
- }
-
- /*
- * Context might has been removed since we go it or being removed
- * right now so we might return information for a VM not existing
- * anymore. This is acceptable as we return a view of the system
- * which could change at any time.
- */
info.id = dest_ctx->ffa_id;
info.execution_context = dest_ctx->num_vcpus;
info.partition_properties = FFA_PART_VM_PROP;
if ( dest_ctx->is_64bit )
info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
- memcpy(dst_buf, &info, MIN(sizeof(info), dst_size));
-
- if ( dst_size > sizeof(info) )
- memset(dst_buf + sizeof(info), 0,
- dst_size - sizeof(info));
+ ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size,
+ sizeof(info));
+ if ( ret )
+ {
+ read_unlock(&ffa_ctx_list_rwlock);
+ return ret;
+ }
- dst_buf += dst_size;
count++;
}
+ read_unlock(&ffa_ctx_list_rwlock);
}
- *vm_count = count;
-out:
- read_unlock(&ffa_ctx_list_rwlock);
+ *vm_count = count;
return ret;
}
@@ -217,17 +255,18 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
struct domain *d = current->domain;
struct ffa_ctx *ctx = d->arch.tee;
uint32_t flags = get_user_reg(regs, 5);
- uint32_t uuid[4] = {
- get_user_reg(regs, 1),
- get_user_reg(regs, 2),
- get_user_reg(regs, 3),
- get_user_reg(regs, 4),
- };
+ struct ffa_uuid uuid;
uint32_t dst_size = 0;
size_t buf_size;
void *dst_buf, *end_buf;
uint32_t ffa_vm_count = 0, ffa_sp_count = 0;
+ ffa_uuid_set(&uuid,
+ get_user_reg(regs, 1),
+ get_user_reg(regs, 2),
+ get_user_reg(regs, 3),
+ get_user_reg(regs, 4));
+
/*
* If the guest is v1.0, he does not get back the entry size so we must
* use the v1.0 structure size in the destination buffer.
@@ -260,10 +299,23 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
}
/*
- * Do not count the caller VM as the spec is not clearly mandating it
- * and it is not supported by Linux.
+ * We do not have protocol UUIDs for VMs so if a request has non Nil
+ * UUID we must return a vm_count of 0
*/
- ffa_vm_count = get_ffa_vm_count() - 1;
+ if ( ffa_uuid_is_nil(uuid) )
+ {
+ ffa_vm_count = get_ffa_vm_count();
+
+ /*
+ * Workaround for Linux FF-A Driver not accepting to have its own
+ * entry in the list before FF-A v1.2 was supported.
+ * This workaround is generally acceptable for other implementations
+ * as the specification was not completely clear on wether or not
+ * the requester endpoint information should be included or not
+ */
+ if ( ACCESS_ONCE(ctx->guest_vers) < FFA_VERSION_1_2 )
+ ffa_vm_count -= 1;
+ }
goto out;
}
@@ -290,17 +342,15 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) )
{
- ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, dst_buf, end_buf,
+ ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, &dst_buf, end_buf,
dst_size);
if ( ret )
goto out_rx_release;
-
- dst_buf += ffa_sp_count * dst_size;
}
- if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
- ret = ffa_get_vm_partinfo(&ffa_vm_count, dst_buf, end_buf, dst_size);
+ ret = ffa_get_vm_partinfo(uuid, &ffa_vm_count, &dst_buf, end_buf,
+ dst_size);
out_rx_release:
if ( ret )
@@ -309,7 +359,13 @@ out:
if ( ret )
ffa_set_regs_error(regs, ret);
else
+ {
+ /* Size should be 0 on count request and was not supported in 1.0 */
+ if ( flags || ACCESS_ONCE(ctx->guest_vers) == FFA_VERSION_1_0 )
+ dst_size = 0;
+
ffa_set_regs_success(regs, ffa_sp_count + ffa_vm_count, dst_size);
+ }
}
static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
@@ -450,6 +506,7 @@ bool ffa_partinfo_init(void)
uint32_t count;
int32_t e;
void *spmc_rx;
+ struct ffa_uuid nil_uuid = { .val = { 0ULL, 0ULL } };
if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ||
!ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32))
@@ -459,7 +516,7 @@ bool ffa_partinfo_init(void)
if (!spmc_rx)
return false;
- e = ffa_partition_info_get(NULL, 0, &count, &fpi_size);
+ e = ffa_partition_info_get(nil_uuid, 0, &count, &fpi_size);
if ( e )
{
printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e);
diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
index a18e56b05bbb..d883114948b1 100644
--- a/xen/arch/arm/tee/ffa_private.h
+++ b/xen/arch/arm/tee/ffa_private.h
@@ -307,6 +307,10 @@ struct ffa_mem_region {
struct ffa_address_range address_range_array[];
};
+struct ffa_uuid {
+ uint64_t val[2];
+};
+
struct ffa_ctx_notif {
/*
* True if domain is reported by FFA_NOTIFICATION_INFO_GET to have
@@ -580,4 +584,21 @@ static inline bool ffa_fw_supports_fid(uint32_t fid)
return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported);
}
+static inline bool ffa_uuid_is_nil(struct ffa_uuid id)
+{
+ return id.val[0] == 0 && id.val[1] == 0;
+}
+
+static inline bool ffa_uuid_equal(struct ffa_uuid id1, struct ffa_uuid id2)
+{
+ return id1.val[0] == id2.val[0] && id1.val[1] == id2.val[1];
+}
+
+static inline void ffa_uuid_set(struct ffa_uuid *id, uint32_t val0,
+ uint32_t val1, uint32_t val2, uint32_t val3)
+{
+ id->val[0] = ((uint64_t)val1 << 32U) | val0;
+ id->val[1] = ((uint64_t)val3 << 32U) | val2;
+}
+
#endif /*__FFA_PRIVATE_H__*/
--
2.51.2
Hi Bertrand,
On Fri, Dec 5, 2025 at 11:37 AM Bertrand Marquis
<bertrand.marquis@arm.com> wrote:
>
> Introduce struct ffa_uuid together with nil/equality/set helpers, and
> use it end-to-end in the partition-info plumbing.
>
> The SP and VM enumeration paths now build UUIDs from the guest
> registers, call a new ffa_copy_info() helper and ensure non-nil UUID
> queries only return matching SP entries, relying on firmware UUID
> filtering. VM entries are skipped because we do not track per-VM UUIDs.
>
> Count requests and subscriber initialisation are updated accordingly so
> firmware is always called with an explicit UUID. This keeps count and
> listing requests aligned with the FF-A v1.1 rules while preserving the
> Linux compatibility workaround for v1.2 requesters.
>
> Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com>
> ---
> Changes in v1:
> - Use GENMASK in ffa_partition_info_get instead of explicit values.
> - Use ACCESS_ONCE to read guest_vers
> - use is_64bit_domain to get current domain 32/64 bit support
> ---
> xen/arch/arm/tee/ffa_partinfo.c | 209 ++++++++++++++++++++------------
> xen/arch/arm/tee/ffa_private.h | 21 ++++
> 2 files changed, 154 insertions(+), 76 deletions(-)
Looks good
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Cheers,
Jens
>
> diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c
> index c9faf5415853..bf906ed0c88f 100644
> --- a/xen/arch/arm/tee/ffa_partinfo.c
> +++ b/xen/arch/arm/tee/ffa_partinfo.c
> @@ -33,7 +33,7 @@ static uint16_t subscr_vm_created_count __read_mostly;
> static uint16_t *subscr_vm_destroyed __read_mostly;
> static uint16_t subscr_vm_destroyed_count __read_mostly;
>
> -static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
> +static int32_t ffa_partition_info_get(struct ffa_uuid uuid, uint32_t flags,
> uint32_t *count, uint32_t *fpi_size)
> {
> struct arm_smccc_1_2_regs arg = {
> @@ -41,15 +41,12 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
> .a5 = flags,
> };
> struct arm_smccc_1_2_regs resp;
> - uint32_t ret;
> + int32_t ret;
>
> - if ( uuid )
> - {
> - arg.a1 = uuid[0];
> - arg.a2 = uuid[1];
> - arg.a3 = uuid[2];
> - arg.a4 = uuid[3];
> - }
> + arg.a1 = uuid.val[0] & GENMASK(31, 0);
> + arg.a2 = (uuid.val[0] >> 32) & GENMASK(31, 0);
> + arg.a3 = uuid.val[1] & GENMASK(31, 0);
> + arg.a4 = (uuid.val[1] >> 32) & GENMASK(31, 0);
>
> arm_smccc_1_2_smc(&arg, &resp);
>
> @@ -63,7 +60,26 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags,
> return ret;
> }
>
> -static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count)
> +static int32_t ffa_copy_info(void **dst, void *dst_end, const void *src,
> + uint32_t dst_size, uint32_t src_size)
> +{
> + uint8_t *pos = *dst;
> + uint8_t *end = dst_end;
> +
> + if ( pos > end - dst_size )
> + return FFA_RET_NO_MEMORY;
> +
> + memcpy(pos, src, MIN(dst_size, src_size));
> +
> + if ( dst_size > src_size )
> + memset(pos + src_size, 0, dst_size - src_size);
> +
> + *dst = pos + dst_size;
> +
> + return FFA_RET_OK;
> +}
> +
> +static int32_t ffa_get_sp_count(struct ffa_uuid uuid, uint32_t *sp_count)
> {
> uint32_t src_size;
>
> @@ -71,8 +87,8 @@ static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count)
> sp_count, &src_size);
> }
>
> -static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count,
> - void *dst_buf, void *end_buf,
> +static int32_t ffa_get_sp_partinfo(struct ffa_uuid uuid, uint32_t *sp_count,
> + void **dst_buf, void *end_buf,
> uint32_t dst_size)
> {
> int32_t ret;
> @@ -120,17 +136,18 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count,
> /* filter out SP not following bit 15 convention if any */
> if ( FFA_ID_IS_SECURE(fpi->id) )
> {
> - if ( dst_buf > (end_buf - dst_size) )
> - {
> - ret = FFA_RET_NO_MEMORY;
> - goto out;
> - }
> + /*
> + * If VM is 1.0 but firmware is 1.1 we could have several entries
> + * with the same ID but different UUIDs. In this case the VM will
> + * get a list with several time the same ID.
> + * This is a non-compliance to the specification but 1.0 VMs should
> + * handle that on their own to simplify Xen implementation.
> + */
>
> - memcpy(dst_buf, src_buf, MIN(src_size, dst_size));
> - if ( dst_size > src_size )
> - memset(dst_buf + src_size, 0, dst_size - src_size);
> + ret = ffa_copy_info(dst_buf, end_buf, src_buf, dst_size, src_size);
> + if ( ret )
> + goto out;
>
> - dst_buf += dst_size;
> count++;
> }
>
> @@ -144,69 +161,90 @@ out:
> return ret;
> }
>
> -static int32_t ffa_get_vm_partinfo(uint32_t *vm_count, void *dst_buf,
> - void *end_buf, uint32_t dst_size)
> +static int32_t ffa_get_vm_partinfo(struct ffa_uuid uuid, uint32_t *vm_count,
> + void **dst_buf, void *end_buf,
> + uint32_t dst_size)
> {
> - struct ffa_ctx *curr_ctx = current->domain->arch.tee;
> + struct domain *d = current->domain;
> + struct ffa_ctx *curr_ctx = d->arch.tee;
> struct ffa_ctx *dest_ctx;
> uint32_t count = 0;
> int32_t ret = FFA_RET_OK;
> + /*
> + * We do not have UUID info for VMs so use the 1.0 structure so that we set
> + * UUIDs to zero using memset
> + */
> + struct ffa_partition_info_1_0 info;
>
> /*
> - * There could potentially be a lot of VMs in the system and we could
> - * hold the CPU for long here.
> - * Right now there is no solution in FF-A specification to split
> - * the work in this case.
> - * TODO: Check how we could delay the work or have preemption checks.
> + * We do not have protocol UUIDs for VMs so if a request has non Nil UUID
> + * we must return an empty list.
> */
> - read_lock(&ffa_ctx_list_rwlock);
> - list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
> + if ( !ffa_uuid_is_nil(uuid) )
> + {
> + *vm_count = 0;
> + return FFA_RET_OK;
> + }
> +
> + /*
> + * Workaround for Linux FF-A Driver not accepting to have its own
> + * entry in the list before FF-A v1.2 was supported.
> + * This workaround is generally acceptable for other implementations
> + * as the specification was not completely clear on wether or not
> + * the requester endpoint information should be included or not
> + */
> + if ( ACCESS_ONCE(curr_ctx->guest_vers) >= FFA_VERSION_1_2 )
> + {
> + /* Add caller VM information */
> + info.id = curr_ctx->ffa_id;
> + info.execution_context = curr_ctx->num_vcpus;
> + info.partition_properties = FFA_PART_VM_PROP;
> + if ( is_64bit_domain(d) )
> + info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
> +
> + ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size, sizeof(info));
> + if ( ret )
> + return ret;
> +
> + count++;
> + }
> +
> + if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
> {
> /*
> - * Do not include an entry for the caller VM as the spec is not
> - * clearly mandating it and it is not supported by Linux.
> + * There could potentially be a lot of VMs in the system and we could
> + * hold the CPU for long here.
> + * Right now there is no solution in FF-A specification to split
> + * the work in this case.
> + * TODO: Check how we could delay the work or have preemption checks.
> */
> - if ( dest_ctx != curr_ctx )
> + read_lock(&ffa_ctx_list_rwlock);
> + list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
> {
> - /*
> - * We do not have UUID info for VMs so use
> - * the 1.0 structure so that we set UUIDs to
> - * zero using memset
> - */
> - struct ffa_partition_info_1_0 info;
> + /* Ignore the caller entry as it was already added */
> + if ( dest_ctx == curr_ctx )
> + continue;
>
> - if ( dst_buf > (end_buf - dst_size) )
> - {
> - ret = FFA_RET_NO_MEMORY;
> - goto out;
> - }
> -
> - /*
> - * Context might has been removed since we go it or being removed
> - * right now so we might return information for a VM not existing
> - * anymore. This is acceptable as we return a view of the system
> - * which could change at any time.
> - */
> info.id = dest_ctx->ffa_id;
> info.execution_context = dest_ctx->num_vcpus;
> info.partition_properties = FFA_PART_VM_PROP;
> if ( dest_ctx->is_64bit )
> info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
>
> - memcpy(dst_buf, &info, MIN(sizeof(info), dst_size));
> -
> - if ( dst_size > sizeof(info) )
> - memset(dst_buf + sizeof(info), 0,
> - dst_size - sizeof(info));
> + ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size,
> + sizeof(info));
> + if ( ret )
> + {
> + read_unlock(&ffa_ctx_list_rwlock);
> + return ret;
> + }
>
> - dst_buf += dst_size;
> count++;
> }
> + read_unlock(&ffa_ctx_list_rwlock);
> }
> - *vm_count = count;
>
> -out:
> - read_unlock(&ffa_ctx_list_rwlock);
> + *vm_count = count;
>
> return ret;
> }
> @@ -217,17 +255,18 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
> struct domain *d = current->domain;
> struct ffa_ctx *ctx = d->arch.tee;
> uint32_t flags = get_user_reg(regs, 5);
> - uint32_t uuid[4] = {
> - get_user_reg(regs, 1),
> - get_user_reg(regs, 2),
> - get_user_reg(regs, 3),
> - get_user_reg(regs, 4),
> - };
> + struct ffa_uuid uuid;
> uint32_t dst_size = 0;
> size_t buf_size;
> void *dst_buf, *end_buf;
> uint32_t ffa_vm_count = 0, ffa_sp_count = 0;
>
> + ffa_uuid_set(&uuid,
> + get_user_reg(regs, 1),
> + get_user_reg(regs, 2),
> + get_user_reg(regs, 3),
> + get_user_reg(regs, 4));
> +
> /*
> * If the guest is v1.0, he does not get back the entry size so we must
> * use the v1.0 structure size in the destination buffer.
> @@ -260,10 +299,23 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
> }
>
> /*
> - * Do not count the caller VM as the spec is not clearly mandating it
> - * and it is not supported by Linux.
> + * We do not have protocol UUIDs for VMs so if a request has non Nil
> + * UUID we must return a vm_count of 0
> */
> - ffa_vm_count = get_ffa_vm_count() - 1;
> + if ( ffa_uuid_is_nil(uuid) )
> + {
> + ffa_vm_count = get_ffa_vm_count();
> +
> + /*
> + * Workaround for Linux FF-A Driver not accepting to have its own
> + * entry in the list before FF-A v1.2 was supported.
> + * This workaround is generally acceptable for other implementations
> + * as the specification was not completely clear on wether or not
> + * the requester endpoint information should be included or not
> + */
> + if ( ACCESS_ONCE(ctx->guest_vers) < FFA_VERSION_1_2 )
> + ffa_vm_count -= 1;
> + }
>
> goto out;
> }
> @@ -290,17 +342,15 @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs)
>
> if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) )
> {
> - ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, dst_buf, end_buf,
> + ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, &dst_buf, end_buf,
> dst_size);
>
> if ( ret )
> goto out_rx_release;
> -
> - dst_buf += ffa_sp_count * dst_size;
> }
>
> - if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
> - ret = ffa_get_vm_partinfo(&ffa_vm_count, dst_buf, end_buf, dst_size);
> + ret = ffa_get_vm_partinfo(uuid, &ffa_vm_count, &dst_buf, end_buf,
> + dst_size);
>
> out_rx_release:
> if ( ret )
> @@ -309,7 +359,13 @@ out:
> if ( ret )
> ffa_set_regs_error(regs, ret);
> else
> + {
> + /* Size should be 0 on count request and was not supported in 1.0 */
> + if ( flags || ACCESS_ONCE(ctx->guest_vers) == FFA_VERSION_1_0 )
> + dst_size = 0;
> +
> ffa_set_regs_success(regs, ffa_sp_count + ffa_vm_count, dst_size);
> + }
> }
>
> static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
> @@ -450,6 +506,7 @@ bool ffa_partinfo_init(void)
> uint32_t count;
> int32_t e;
> void *spmc_rx;
> + struct ffa_uuid nil_uuid = { .val = { 0ULL, 0ULL } };
>
> if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ||
> !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32))
> @@ -459,7 +516,7 @@ bool ffa_partinfo_init(void)
> if (!spmc_rx)
> return false;
>
> - e = ffa_partition_info_get(NULL, 0, &count, &fpi_size);
> + e = ffa_partition_info_get(nil_uuid, 0, &count, &fpi_size);
> if ( e )
> {
> printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e);
> diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
> index a18e56b05bbb..d883114948b1 100644
> --- a/xen/arch/arm/tee/ffa_private.h
> +++ b/xen/arch/arm/tee/ffa_private.h
> @@ -307,6 +307,10 @@ struct ffa_mem_region {
> struct ffa_address_range address_range_array[];
> };
>
> +struct ffa_uuid {
> + uint64_t val[2];
> +};
> +
> struct ffa_ctx_notif {
> /*
> * True if domain is reported by FFA_NOTIFICATION_INFO_GET to have
> @@ -580,4 +584,21 @@ static inline bool ffa_fw_supports_fid(uint32_t fid)
> return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported);
> }
>
> +static inline bool ffa_uuid_is_nil(struct ffa_uuid id)
> +{
> + return id.val[0] == 0 && id.val[1] == 0;
> +}
> +
> +static inline bool ffa_uuid_equal(struct ffa_uuid id1, struct ffa_uuid id2)
> +{
> + return id1.val[0] == id2.val[0] && id1.val[1] == id2.val[1];
> +}
> +
> +static inline void ffa_uuid_set(struct ffa_uuid *id, uint32_t val0,
> + uint32_t val1, uint32_t val2, uint32_t val3)
> +{
> + id->val[0] = ((uint64_t)val1 << 32U) | val0;
> + id->val[1] = ((uint64_t)val3 << 32U) | val2;
> +}
> +
> #endif /*__FFA_PRIVATE_H__*/
> --
> 2.51.2
>
© 2016 - 2025 Red Hat, Inc.