From nobody Sat Dec 13 07:22:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1764931102929568.3916287154794; Fri, 5 Dec 2025 02:38:22 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178642.1502440 (Exim 4.92) (envelope-from ) id 1vRTCC-0007Pt-0r; Fri, 05 Dec 2025 10:37:52 +0000 Received: by outflank-mailman (output) from mailman id 1178642.1502440; Fri, 05 Dec 2025 10:37:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTCB-0007PY-PD; Fri, 05 Dec 2025 10:37:51 +0000 Received: by outflank-mailman (input) for mailman id 1178642; Fri, 05 Dec 2025 10:37:50 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC9-0005j7-R8 for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:49 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 71b53fc3-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:49 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 56F8C339; Fri, 5 Dec 2025 02:37:41 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 957C33F86F; Fri, 5 Dec 2025 02:37:47 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 71b53fc3-d1c6-11f0-9d1b-b5c5bf9af7f9 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v1 08/12] xen/arm: ffa: add UUID helpers for partition info Date: Fri, 5 Dec 2025 11:36:41 +0100 Message-ID: <480cc4c4c0a46fc7a812de5c7aa6365af220e9f2.1764930353.git.bertrand.marquis@arm.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1764931103874019200 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Jens Wiklander --- 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_partinf= o.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; =20 -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 =3D { @@ -41,15 +41,12 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, u= int32_t flags, .a5 =3D flags, }; struct arm_smccc_1_2_regs resp; - uint32_t ret; + int32_t ret; =20 - if ( uuid ) - { - arg.a1 =3D uuid[0]; - arg.a2 =3D uuid[1]; - arg.a3 =3D uuid[2]; - arg.a4 =3D uuid[3]; - } + arg.a1 =3D uuid.val[0] & GENMASK(31, 0); + arg.a2 =3D (uuid.val[0] >> 32) & GENMASK(31, 0); + arg.a3 =3D uuid.val[1] & GENMASK(31, 0); + arg.a4 =3D (uuid.val[1] >> 32) & GENMASK(31, 0); =20 arm_smccc_1_2_smc(&arg, &resp); =20 @@ -63,7 +60,26 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, ui= nt32_t flags, return ret; } =20 -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 =3D *dst; + uint8_t *end =3D 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 =3D 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; =20 @@ -71,8 +87,8 @@ static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t = *sp_count) sp_count, &src_size); } =20 -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_coun= t, + 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, ui= nt32_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 =3D FFA_RET_NO_MEMORY; - goto out; - } + /* + * If VM is 1.0 but firmware is 1.1 we could have several entr= ies + * with the same ID but different UUIDs. In this case the VM w= ill + * get a list with several time the same ID. + * This is a non-compliance to the specification but 1.0 VMs s= hould + * handle that on their own to simplify Xen implementation. + */ =20 - 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 =3D ffa_copy_info(dst_buf, end_buf, src_buf, dst_size, src= _size); + if ( ret ) + goto out; =20 - dst_buf +=3D dst_size; count++; } =20 @@ -144,69 +161,90 @@ out: return ret; } =20 -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_coun= t, + void **dst_buf, void *end_buf, + uint32_t dst_size) { - struct ffa_ctx *curr_ctx =3D current->domain->arch.tee; + struct domain *d =3D current->domain; + struct ffa_ctx *curr_ctx =3D d->arch.tee; struct ffa_ctx *dest_ctx; uint32_t count =3D 0; int32_t ret =3D FFA_RET_OK; + /* + * We do not have UUID info for VMs so use the 1.0 structure so that w= e set + * UUIDs to zero using memset + */ + struct ffa_partition_info_1_0 info; =20 /* - * 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 U= UID + * 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 =3D 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) >=3D FFA_VERSION_1_2 ) + { + /* Add caller VM information */ + info.id =3D curr_ctx->ffa_id; + info.execution_context =3D curr_ctx->num_vcpus; + info.partition_properties =3D FFA_PART_VM_PROP; + if ( is_64bit_domain(d) ) + info.partition_properties |=3D FFA_PART_PROP_AARCH64_STATE; + + ret =3D ffa_copy_info(dst_buf, end_buf, &info, dst_size, sizeof(in= fo)); + 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 co= uld + * 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 chec= ks. */ - if ( dest_ctx !=3D 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 =3D=3D curr_ctx ) + continue; =20 - if ( dst_buf > (end_buf - dst_size) ) - { - ret =3D FFA_RET_NO_MEMORY; - goto out; - } - - /* - * Context might has been removed since we go it or being remo= ved - * right now so we might return information for a VM not exist= ing - * anymore. This is acceptable as we return a view of the syst= em - * which could change at any time. - */ info.id =3D dest_ctx->ffa_id; info.execution_context =3D dest_ctx->num_vcpus; info.partition_properties =3D FFA_PART_VM_PROP; if ( dest_ctx->is_64bit ) info.partition_properties |=3D FFA_PART_PROP_AARCH64_STATE; =20 - 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 =3D ffa_copy_info(dst_buf, end_buf, &info, dst_size, + sizeof(info)); + if ( ret ) + { + read_unlock(&ffa_ctx_list_rwlock); + return ret; + } =20 - dst_buf +=3D dst_size; count++; } + read_unlock(&ffa_ctx_list_rwlock); } - *vm_count =3D count; =20 -out: - read_unlock(&ffa_ctx_list_rwlock); + *vm_count =3D count; =20 return ret; } @@ -217,17 +255,18 @@ void ffa_handle_partition_info_get(struct cpu_user_re= gs *regs) struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; uint32_t flags =3D get_user_reg(regs, 5); - uint32_t uuid[4] =3D { - 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 =3D 0; size_t buf_size; void *dst_buf, *end_buf; uint32_t ffa_vm_count =3D 0, ffa_sp_count =3D 0; =20 + 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_re= gs *regs) } =20 /* - * 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 N= il + * UUID we must return a vm_count of 0 */ - ffa_vm_count =3D get_ffa_vm_count() - 1; + if ( ffa_uuid_is_nil(uuid) ) + { + ffa_vm_count =3D 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 implement= ations + * 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 -=3D 1; + } =20 goto out; } @@ -290,17 +342,15 @@ void ffa_handle_partition_info_get(struct cpu_user_re= gs *regs) =20 if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) { - ret =3D ffa_get_sp_partinfo(uuid, &ffa_sp_count, dst_buf, end_buf, + ret =3D ffa_get_sp_partinfo(uuid, &ffa_sp_count, &dst_buf, end_buf, dst_size); =20 if ( ret ) goto out_rx_release; - - dst_buf +=3D ffa_sp_count * dst_size; } =20 - if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) ) - ret =3D ffa_get_vm_partinfo(&ffa_vm_count, dst_buf, end_buf, dst_s= ize); + ret =3D ffa_get_vm_partinfo(uuid, &ffa_vm_count, &dst_buf, end_buf, + dst_size); =20 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) =3D=3D FFA_VERSION_1_0 ) + dst_size =3D 0; + ffa_set_regs_success(regs, ffa_sp_count + ffa_vm_count, dst_size); + } } =20 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 =3D { .val =3D { 0ULL, 0ULL } }; =20 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; =20 - e =3D ffa_partition_info_get(NULL, 0, &count, &fpi_size); + e =3D 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[]; }; =20 +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); } =20 +static inline bool ffa_uuid_is_nil(struct ffa_uuid id) +{ + return id.val[0] =3D=3D 0 && id.val[1] =3D=3D 0; +} + +static inline bool ffa_uuid_equal(struct ffa_uuid id1, struct ffa_uuid id2) +{ + return id1.val[0] =3D=3D id2.val[0] && id1.val[1] =3D=3D id2.val[1]; +} + +static inline void ffa_uuid_set(struct ffa_uuid *id, uint32_t val0, + uint32_t val1, uint32_t val2, uint32_t val= 3) +{ + id->val[0] =3D ((uint64_t)val1 << 32U) | val0; + id->val[1] =3D ((uint64_t)val3 << 32U) | val2; +} + #endif /*__FFA_PRIVATE_H__*/ --=20 2.51.2