[PATCH v1 08/12] xen/arm: ffa: add UUID helpers for partition info

Bertrand Marquis posted 12 patches 1 week ago
[PATCH v1 08/12] xen/arm: ffa: add UUID helpers for partition info
Posted by Bertrand Marquis 1 week ago
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
Re: [PATCH v1 08/12] xen/arm: ffa: add UUID helpers for partition info
Posted by Jens Wiklander 3 days, 4 hours ago
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
>