From nobody Fri Dec 12 19:30:14 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 176493108166896.20759459433589; Fri, 5 Dec 2025 02:38:01 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178632.1502374 (Exim 4.92) (envelope-from ) id 1vRTC2-0005n7-Ll; Fri, 05 Dec 2025 10:37:42 +0000 Received: by outflank-mailman (output) from mailman id 1178632.1502374; Fri, 05 Dec 2025 10:37:42 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC2-0005n0-I5; Fri, 05 Dec 2025 10:37:42 +0000 Received: by outflank-mailman (input) for mailman id 1178632; Fri, 05 Dec 2025 10:37:41 +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 1vRTC1-0005j7-8r for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:41 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 6c23669e-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:40 +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 EDBC8339; Fri, 5 Dec 2025 02:37:31 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3EB5A3F86F; Fri, 5 Dec 2025 02:37:38 -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: 6c23669e-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 01/12] xen/arm: ffa: add FF-A v1.2 function IDs Date: Fri, 5 Dec 2025 11:36:34 +0100 Message-ID: <6832face6780228ac2704da70d5ddbd7f00dd385.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: 1764931083693019200 Content-Type: text/plain; charset="utf-8" Bring the FF-A headers up to the v1.2 baseline and fix the function-number range used for ABI discovery: - update FFA_FNUM_MAX_VALUE so the FF-A function-number window covers the full v1.2 range, and derive the ABI bitmap bounds from FFA_FNUM_MIN_VALUE/FFA_FNUM_MAX_VALUE instead of hard-coding FFA_ERROR/FFA_MSG_SEND2 - define the new v1.2 function IDs; CONSOLE_LOG_32/64 and PARTITION_INFO_GET_REGS are added for ABI discovery even though they are not implemented yet - extend the firmware ABI table to probe RUN and MSG_SEND_DIRECT_REQ2/RESP2 - while there, fix an off-by-one in ffa_fw_supports_fid(): the computed bit index must be strictly smaller than FFA_ABI_BITMAP_SIZE, so use >=3D in t= he bounds check - Also fix comment as call IDs reserved for FF-A are from 0x60 to 0xEF Keep FFA_MY_VERSION at 1.1 for now; we only advertise v1.2 once the implementation is fully compliant. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - Add CONSOLE_LOG_64 and rename CONSOLE_LOG to CONSOLE_LOG_32 - Set MAX value to 0x8E which is the highest abi value available in 1.2 - Mention in ffa_private.h comment that SMCCC is actually reserving 0x60 to 0xEF included for FF-A (and fix previous FF which was wrong). --- xen/arch/arm/include/asm/tee/ffa.h | 3 ++- xen/arch/arm/tee/ffa.c | 4 ++++ xen/arch/arm/tee/ffa_private.h | 21 +++++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/include/asm/tee/ffa.h b/xen/arch/arm/include/asm/= tee/ffa.h index 24cd4d99c8f9..7acb541d1ff0 100644 --- a/xen/arch/arm/include/asm/tee/ffa.h +++ b/xen/arch/arm/include/asm/tee/ffa.h @@ -15,8 +15,9 @@ #include #include =20 +/* FF-A Function ID range (AArch32 function number field) as of FF-A v1.2 = */ #define FFA_FNUM_MIN_VALUE _AC(0x60,U) -#define FFA_FNUM_MAX_VALUE _AC(0x86,U) +#define FFA_FNUM_MAX_VALUE _AC(0x8E,U) =20 static inline bool is_ffa_fid(uint32_t fid) { diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 1d0239cf6950..2b4e24750d52 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -11,6 +11,8 @@ * https://developer.arm.com/documentation/den0077/a * FF-A-1.1-REL0: FF-A specification version 1.1 available at * https://developer.arm.com/documentation/den0077/e + * FF-A-1.2-REL0: FF-A specification version 1.2 available at + * https://developer.arm.com/documentation/den0077/j * TEEC-1.0C: TEE Client API Specification version 1.0c available at * https://globalplatform.org/specs-library/tee-client-api-spec= ification/ * @@ -102,6 +104,8 @@ static const struct ffa_fw_abi ffa_fw_abi_needed[] =3D { FW_ABI(FFA_MSG_SEND_DIRECT_REQ_32), FW_ABI(FFA_MSG_SEND_DIRECT_REQ_64), FW_ABI(FFA_MSG_SEND2), + FW_ABI(FFA_MSG_SEND_DIRECT_REQ2), + FW_ABI(FFA_RUN), }; =20 /* diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 6dbdb200d840..8d01da0009d3 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -15,6 +15,7 @@ #include #include #include +#include =20 /* Error codes */ #define FFA_RET_OK 0 @@ -42,6 +43,7 @@ =20 #define FFA_VERSION_1_0 MAKE_FFA_VERSION(1, 0) #define FFA_VERSION_1_1 MAKE_FFA_VERSION(1, 1) +#define FFA_VERSION_1_2 MAKE_FFA_VERSION(1, 2) /* The minimal FF-A version of the SPMC that can be supported */ #define FFA_MIN_SPMC_VERSION FFA_VERSION_1_1 =20 @@ -270,21 +272,24 @@ #define FFA_RX_ACQUIRE 0x84000084U #define FFA_SPM_ID_GET 0x84000085U #define FFA_MSG_SEND2 0x84000086U +#define FFA_CONSOLE_LOG_32 0x8400008AU +#define FFA_CONSOLE_LOG_64 0xC400008AU +#define FFA_PARTITION_INFO_GET_REGS 0x8400008BU +#define FFA_MSG_SEND_DIRECT_REQ2 0xC400008DU +#define FFA_MSG_SEND_DIRECT_RESP2 0xC400008EU =20 /** * Encoding of features supported or not by the fw in a bitmap: - * - Function IDs are going from 0x60 to 0xFF + * - Function IDs are going from 0x60 to 0xEF in SMCCC standard * - A function can be supported in 32 and/or 64bit * The bitmap has one bit for each function in 32 and 64 bit. */ #define FFA_ABI_ID(id) ((id) & ARM_SMCCC_FUNC_MASK) #define FFA_ABI_CONV(id) (((id) >> ARM_SMCCC_CONV_SHIFT) & BIT(0,U)) =20 -#define FFA_ABI_MIN FFA_ABI_ID(FFA_ERROR) -#define FFA_ABI_MAX FFA_ABI_ID(FFA_MSG_SEND2) - -#define FFA_ABI_BITMAP_SIZE (2 * (FFA_ABI_MAX - FFA_ABI_MIN + 1)) -#define FFA_ABI_BITNUM(id) ((FFA_ABI_ID(id) - FFA_ABI_MIN) << 1 | \ +#define FFA_ABI_BITMAP_SIZE (2 * (FFA_FNUM_MAX_VALUE - FFA_FNUM_MIN_VALU= E \ + + 1)) +#define FFA_ABI_BITNUM(id) ((FFA_ABI_ID(id) - FFA_FNUM_MIN_VALUE) << 1 = | \ FFA_ABI_CONV(id)) =20 /* Constituent memory region descriptor */ @@ -549,9 +554,9 @@ static inline int32_t ffa_hyp_rx_release(void) =20 static inline bool ffa_fw_supports_fid(uint32_t fid) { - BUILD_BUG_ON(FFA_ABI_MIN > FFA_ABI_MAX); + BUILD_BUG_ON(FFA_FNUM_MIN_VALUE > FFA_FNUM_MAX_VALUE); =20 - if ( FFA_ABI_BITNUM(fid) > FFA_ABI_BITMAP_SIZE) + if ( FFA_ABI_BITNUM(fid) >=3D FFA_ABI_BITMAP_SIZE) return false; return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported); } --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931085378212.16007872110663; Fri, 5 Dec 2025 02:38:05 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178633.1502384 (Exim 4.92) (envelope-from ) id 1vRTC3-00063F-Rs; Fri, 05 Dec 2025 10:37:43 +0000 Received: by outflank-mailman (output) from mailman id 1178633.1502384; Fri, 05 Dec 2025 10:37:43 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC3-000638-Ot; Fri, 05 Dec 2025 10:37:43 +0000 Received: by outflank-mailman (input) for mailman id 1178633; Fri, 05 Dec 2025 10:37:42 +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 1vRTC2-0005j7-95 for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:42 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 6d02f811-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:41 +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 5262A1063; Fri, 5 Dec 2025 02:37:33 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 92EAB3F86F; Fri, 5 Dec 2025 02:37:39 -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: 6d02f811-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 02/12] xen/arm: ffa: per-VM FFA_VERSION negotiation state Date: Fri, 5 Dec 2025 11:36:35 +0100 Message-ID: X-Mailer: git-send-email 2.51.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1764931085743019200 Content-Type: text/plain; charset="utf-8" Track FF-A version negotiation per VM and enforce that no FF-A ABI (other than FFA_VERSION) is processed before a guest has selected a version. Each ffa_ctx gains a dedicated guest_vers_lock, a negotiated version (guest_vers) and a guest_vers_tmp: - guest_vers is the version negotiated or 0 if no version has been negotiated. This must be used with ACCESS_ONCE when reading it without the spinlock taken. - guest_vers_tmp stores the version currently requested by a VM. The version requested is the one actually negotiated once a call different from FFA_VERSION is done to allow several attempts and as requested by FF-A specification. We always return our implementation version FFA_MY_VERSION, even if the version requested was different, as requested by FF-A specification. Any call other than FFA_VERSION is rejected until a version has been requested. Update all places in the code where guest_vers is used to use ACCESS_ONCE. This prevents partially initialised contexts from using the mediator and complies with the FF-A 1.2 FFA_VERSION semantics. Signed-off-by: Bertrand Marquis --- Changes in v1: - remove the guest_vers_negotiated and use guest_vers =3D 0 as condition for a version being negotiated instead - introduce guest_vers_tmp to store a requested version until it is becoming the one negotiated. - remove not needed if negotiated condition. - use ACCESS_ONCE when reading guest_vers and use guest_vers =3D=3D 0 as condition for a version being negotiated. - Update FF-A version handling comment in ffa_private.h --- xen/arch/arm/tee/ffa.c | 101 +++++++++++++++++++++++++------- xen/arch/arm/tee/ffa_msg.c | 2 +- xen/arch/arm/tee/ffa_partinfo.c | 4 +- xen/arch/arm/tee/ffa_private.h | 26 ++++++-- xen/arch/arm/tee/ffa_shm.c | 3 +- 5 files changed, 105 insertions(+), 31 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 2b4e24750d52..aadd6c21e7f2 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -158,31 +158,38 @@ static bool ffa_abi_supported(uint32_t id) return !ffa_simple_call(FFA_FEATURES, id, 0, 0, 0); } =20 -static void handle_version(struct cpu_user_regs *regs) +static bool ffa_negotiate_version(struct cpu_user_regs *regs) { struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; - uint32_t vers =3D get_user_reg(regs, 1); - uint32_t old_vers; + uint32_t fid =3D get_user_reg(regs, 0); + uint32_t in_vers =3D get_user_reg(regs, 1); + uint32_t out_vers =3D FFA_MY_VERSION; =20 - /* - * Guest will use the version it requested if it is our major and minor - * lower or equals to ours. If the minor is greater, our version will = be - * used. - * In any case return our version to the caller. - */ - if ( FFA_VERSION_MAJOR(vers) =3D=3D FFA_MY_VERSION_MAJOR ) + spin_lock(&ctx->guest_vers_lock); + + /* If negotiation already published, continue without handling. */ + if ( ACCESS_ONCE(ctx->guest_vers) ) + goto out_continue; + + if ( fid !=3D FFA_VERSION ) { - spin_lock(&ctx->lock); - old_vers =3D ctx->guest_vers; + if ( !ctx->guest_vers_tmp ) + { + out_vers =3D 0; + goto out_handled; + } =20 - if ( FFA_VERSION_MINOR(vers) > FFA_MY_VERSION_MINOR ) - ctx->guest_vers =3D FFA_MY_VERSION; - else - ctx->guest_vers =3D vers; - spin_unlock(&ctx->lock); + /* + * A successful FFA_VERSION call does not freeze negotiation. Gues= ts + * are allowed to issue multiple FFA_VERSION attempts (e.g. probing + * several minor versions). Negotiation becomes final only when a + * non-VERSION ABI is invoked, as required by the FF-A specificati= on. + * Finalize negotiation: publish guest_vers once, then never chang= e. + */ + ACCESS_ONCE(ctx->guest_vers) =3D ctx->guest_vers_tmp; =20 - if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) && !old_vers ) + if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) ) { /* One more VM with FF-A support available */ inc_ffa_vm_count(); @@ -190,8 +197,48 @@ static void handle_version(struct cpu_user_regs *regs) list_add_tail(&ctx->ctx_list, &ffa_ctx_head); write_unlock(&ffa_ctx_list_rwlock); } + + goto out_continue; } - ffa_set_regs(regs, FFA_MY_VERSION, 0, 0, 0, 0, 0, 0, 0); + + /* + * guest_vers_tmp stores the version selected by the guest (lower mino= r may + * require reduced data structures). However, the value returned to the + * guest via FFA_VERSION is always FFA_MY_VERSION, the implementation + * version, as required by FF-A. The two values intentionally differ. + */ + + /* + * Return our highest implementation version on request different than= our + * major and mark negotiated version as our implementation version. + */ + if ( FFA_VERSION_MAJOR(in_vers) !=3D FFA_MY_VERSION_MAJOR ) + { + ctx->guest_vers_tmp =3D FFA_MY_VERSION; + goto out_handled; + } + + /* + * Use our minor version if a greater minor was requested or the reque= sted + * minor if it is lower than ours was requested. + */ + if ( FFA_VERSION_MINOR(in_vers) > FFA_MY_VERSION_MINOR ) + ctx->guest_vers_tmp =3D FFA_MY_VERSION; + else + ctx->guest_vers_tmp =3D in_vers; + +out_handled: + spin_unlock(&ctx->guest_vers_lock); + if ( out_vers ) + ffa_set_regs(regs, out_vers, 0, 0, 0, 0, 0, 0, 0); + else + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + return true; + +out_continue: + spin_unlock(&ctx->guest_vers_lock); + + return false; } =20 static void handle_features(struct cpu_user_regs *regs) @@ -274,10 +321,17 @@ static bool ffa_handle_call(struct cpu_user_regs *reg= s) if ( !ctx ) return false; =20 + /* A version must be negotiated first */ + if ( !ACCESS_ONCE(ctx->guest_vers) ) + { + if ( ffa_negotiate_version(regs) ) + return true; + } + switch ( fid ) { case FFA_VERSION: - handle_version(regs); + ffa_set_regs(regs, FFA_MY_VERSION, 0, 0, 0, 0, 0, 0, 0); return true; case FFA_ID_GET: ffa_set_regs_success(regs, ffa_get_vm_id(d), 0); @@ -371,6 +425,11 @@ static int ffa_domain_init(struct domain *d) d->arch.tee =3D ctx; ctx->teardown_d =3D d; INIT_LIST_HEAD(&ctx->shm_list); + spin_lock_init(&ctx->lock); + spin_lock_init(&ctx->guest_vers_lock); + ctx->guest_vers =3D 0; + ctx->guest_vers_tmp =3D 0; + INIT_LIST_HEAD(&ctx->ctx_list); =20 ctx->ffa_id =3D ffa_get_vm_id(d); ctx->num_vcpus =3D d->max_vcpus; @@ -452,7 +511,7 @@ static int ffa_domain_teardown(struct domain *d) if ( !ctx ) return 0; =20 - if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) && ctx->guest_vers ) + if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) && ACCESS_ONCE(ctx->guest_vers) ) { dec_ffa_vm_count(); write_lock(&ffa_ctx_list_rwlock); diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index c20c5bec0f76..2c2ebc9c5cd6 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -113,7 +113,7 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, const = void *src_buf, } =20 dst_ctx =3D dst_d->arch.tee; - if ( !dst_ctx->guest_vers ) + if ( !ACCESS_ONCE(dst_ctx->guest_vers) ) { ret =3D FFA_RET_INVALID_PARAMETERS; goto out_unlock; diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinf= o.c index fa56b1587e3b..ec5a53ed1cab 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -238,7 +238,7 @@ void ffa_handle_partition_info_get(struct cpu_user_regs= *regs) * use the v1.0 structure size in the destination buffer. * Otherwise use the size of the highest version we support, here 1.1. */ - if ( ctx->guest_vers =3D=3D FFA_VERSION_1_0 ) + if ( ACCESS_ONCE(ctx->guest_vers) =3D=3D FFA_VERSION_1_0 ) dst_size =3D sizeof(struct ffa_partition_info_1_0); else dst_size =3D sizeof(struct ffa_partition_info_1_1); @@ -250,7 +250,7 @@ void ffa_handle_partition_info_get(struct cpu_user_regs= *regs) * FF-A v1.0 has w5 MBZ while v1.1 allows * FFA_PARTITION_INFO_GET_COUNT_FLAG to be non-zero. */ - if ( ctx->guest_vers =3D=3D FFA_VERSION_1_0 || + if ( ACCESS_ONCE(ctx->guest_vers) =3D=3D FFA_VERSION_1_0 || flags !=3D FFA_PARTITION_INFO_GET_COUNT_FLAG ) { ret =3D FFA_RET_INVALID_PARAMETERS; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 8d01da0009d3..4e4ac7fd7bc4 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -355,12 +355,6 @@ struct ffa_ctx { * Global data accessed with lock locked. */ spinlock_t lock; - /* - * FF-A version negotiated by the guest, only modifications to - * this field are done with the lock held as this is expected to - * be done once at init by a guest. - */ - uint32_t guest_vers; /* Number of 4kB pages in each of rx/rx_pg and tx/tx_pg */ unsigned int page_count; /* Number of allocated shared memory object */ @@ -368,6 +362,26 @@ struct ffa_ctx { /* Used shared memory objects, struct ffa_shm_mem */ struct list_head shm_list; =20 + /* + * FF-A version handling + * guest_vers is the single published negotiated version. It is 0 until + * negotiation completes, after which it is set once and never changes. + * Negotiation uses guest_vers_tmp under guest_vers_lock; when a + * non-VERSION ABI is invoked, Xen finalizes negotiation by publishing + * guest_vers using ACCESS_ONCE() store. + * Readers use ACCESS_ONCE(guest_vers) !=3D 0 to detect availability a= nd + * can consume guest_vers without barriers because it never changes on= ce + * published. + */ + spinlock_t guest_vers_lock; + /* + * Published negotiated version. Zero means "not negotiated yet". + * Once non-zero, it never changes. + */ + uint32_t guest_vers; + /* Temporary version used during negotiation under guest_vers_lock */ + uint32_t guest_vers_tmp; + /* * Rx buffer, accessed with rx_lock locked. * rx_is_free is used to serialize access. diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index d628c1b70609..dad3da192247 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -495,7 +495,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) if ( frag_len > ctx->page_count * FFA_PAGE_SIZE ) goto out_unlock; =20 - ret =3D read_mem_transaction(ctx->guest_vers, ctx->tx, frag_len, &tran= s); + ret =3D read_mem_transaction(ACCESS_ONCE(ctx->guest_vers), ctx->tx, + frag_len, &trans); if ( ret ) goto out_unlock; =20 --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931081326969.7872665152936; Fri, 5 Dec 2025 02:38:01 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178635.1502394 (Exim 4.92) (envelope-from ) id 1vRTC6-0006IR-2M; Fri, 05 Dec 2025 10:37:46 +0000 Received: by outflank-mailman (output) from mailman id 1178635.1502394; Fri, 05 Dec 2025 10:37:46 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC5-0006IG-V2; Fri, 05 Dec 2025 10:37:45 +0000 Received: by outflank-mailman (input) for mailman id 1178635; Fri, 05 Dec 2025 10:37:44 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC4-0005Ju-A6 for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:44 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 6dc0335a-d1c6-11f0-980a-7dc792cee155; Fri, 05 Dec 2025 11:37:42 +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 9F95F1575; Fri, 5 Dec 2025 02:37:34 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E79ED3F86F; Fri, 5 Dec 2025 02:37:40 -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: 6dc0335a-d1c6-11f0-980a-7dc792cee155 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 03/12] xen/arm: ffa: Fix is_64bit init Date: Fri, 5 Dec 2025 11:36:36 +0100 Message-ID: <697ab9880767b75c9964ae900a43fd4e065fc502.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: 1764931081784019200 Content-Type: text/plain; charset="utf-8" is_64bit_domain(d) is not set during domain_init as the domain field is only set when loading the domain image which is done after executing domain_init. Fix the implementation to set is_64bit when version gets negotiated. is_64bit is only used during partition_info_get once a domain is added in the list of domains having ffa support. It must only be accessed when the rwlock is taken (which is the case). is_64bit must not be used without the rwlock taken and other places in the code needing to test 64bit support of the current domain will have to use calls to is_64bit_domain instead of the field from now on. Fixes: 09a201605f99 ("xen/arm: ffa: Introduce VM to VM support") Signed-off-by: Bertrand Marquis --- Changes in v1: - patch introduced --- xen/arch/arm/tee/ffa.c | 9 ++++++++- xen/arch/arm/tee/ffa_private.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index aadd6c21e7f2..0f6f837378cc 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -180,6 +180,14 @@ static bool ffa_negotiate_version(struct cpu_user_regs= *regs) goto out_handled; } =20 + /* + * We cannot set is_64bit during domain init because the field is = not + * yet initialized. + * This field is only used during partinfo_get with the rwlock tak= en + * so there is no ordering issue with guest_vers. + */ + ctx->is_64bit =3D is_64bit_domain(d); + /* * A successful FFA_VERSION call does not freeze negotiation. Gues= ts * are allowed to issue multiple FFA_VERSION attempts (e.g. probing @@ -433,7 +441,6 @@ static int ffa_domain_init(struct domain *d) =20 ctx->ffa_id =3D ffa_get_vm_id(d); ctx->num_vcpus =3D d->max_vcpus; - ctx->is_64bit =3D is_64bit_domain(d); =20 /* * ffa_domain_teardown() will be called if ffa_domain_init() returns an diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 4e4ac7fd7bc4..2daa4589a930 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -344,6 +344,11 @@ struct ffa_ctx { /* FF-A Endpoint ID */ uint16_t ffa_id; uint16_t num_vcpus; + /* + * Must only be accessed with the ffa_ctx_list_rwlock taken as it set + * when guest_vers is set and other accesses could see a partially set + * value. + */ bool is_64bit; =20 /* --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931086907441.2710774376736; Fri, 5 Dec 2025 02:38:06 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178636.1502397 (Exim 4.92) (envelope-from ) id 1vRTC6-0006KW-C7; Fri, 05 Dec 2025 10:37:46 +0000 Received: by outflank-mailman (output) from mailman id 1178636.1502397; Fri, 05 Dec 2025 10:37:46 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC6-0006K4-5v; Fri, 05 Dec 2025 10:37:46 +0000 Received: by outflank-mailman (input) for mailman id 1178636; Fri, 05 Dec 2025 10:37:44 +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 1vRTC4-0005j7-Jd for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:44 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 6e8a52dc-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:44 +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 0336C339; Fri, 5 Dec 2025 02:37:36 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 449773F86F; Fri, 5 Dec 2025 02:37:42 -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: 6e8a52dc-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 04/12] xen/arm: ffa: harden RX/TX mapping Date: Fri, 5 Dec 2025 11:36:37 +0100 Message-ID: <93c6c48283da84976a40aae1395db5a8d47f0b97.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: 1764931087729019200 Content-Type: text/plain; charset="utf-8" Harden the RX/TX mapping paths and keep signed FF-A return codes end-to-end. Reject zero-length mappings and insist on page-aligned RX/TX buffer addresses before touching the P2M. The unmap plumbing is switched to use the same signed helpers so dispatcher error handling is consistent across map and unmap operations. This avoids partially mapped or silently truncated buffers and makes the mediator behaviour match the FF-A error model more closely. Prevent concurrent usage of rx or tx buffer during map or unmap by holding the rx_lock and tx_lock. While there also introduce a domain_rxtx_init to properly initialize the rxtx buffers spinlocks. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - take the rx_lock and tx_lock during rxtx_map and rxtx_unmap to prevent concurrent calls using the rx or tx buffer during mapping. - properly clean rx/tx buffer related context entries during domain_init --- xen/arch/arm/tee/ffa.c | 4 ++ xen/arch/arm/tee/ffa_private.h | 5 ++- xen/arch/arm/tee/ffa_rxtx.c | 68 +++++++++++++++++++++++++++------- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 0f6f837378cc..497ada8264e0 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -451,6 +451,10 @@ static int ffa_domain_init(struct domain *d) if ( ret ) return ret; =20 + ret =3D ffa_rxtx_domain_init(d); + if ( ret ) + return ret; + return ffa_notif_domain_init(d); } =20 diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 2daa4589a930..d6400efd50bb 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -438,10 +438,11 @@ void ffa_handle_partition_info_get(struct cpu_user_re= gs *regs); =20 bool ffa_rxtx_init(void); void ffa_rxtx_destroy(void); +int32_t ffa_rxtx_domain_init(struct domain *d); void ffa_rxtx_domain_destroy(struct domain *d); -uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, +int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count); -uint32_t ffa_handle_rxtx_unmap(void); +int32_t ffa_handle_rxtx_unmap(void); int32_t ffa_rx_acquire(struct domain *d); int32_t ffa_rx_release(struct domain *d); =20 diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index a40e5b32e3a5..5776693bb3f0 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -41,10 +41,10 @@ static int32_t ffa_rxtx_unmap(uint16_t id) return ffa_simple_call(FFA_RXTX_UNMAP, ((uint64_t)id) << 16, 0, 0, 0); } =20 -uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, +int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count) { - uint32_t ret =3D FFA_RET_INVALID_PARAMETERS; + int32_t ret =3D FFA_RET_INVALID_PARAMETERS; struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; struct page_info *tx_pg; @@ -66,20 +66,30 @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t t= x_addr, rx_addr &=3D UINT32_MAX; } =20 - if ( page_count > FFA_MAX_RXTX_PAGE_COUNT ) + if ( page_count > FFA_MAX_RXTX_PAGE_COUNT || !page_count ) { printk(XENLOG_ERR "ffa: RXTX_MAP: error: %u pages requested (limit= %u)\n", page_count, FFA_MAX_RXTX_PAGE_COUNT); return FFA_RET_INVALID_PARAMETERS; } =20 + if ( !IS_ALIGNED(tx_addr, FFA_PAGE_SIZE) || + !IS_ALIGNED(rx_addr, FFA_PAGE_SIZE) ) + return FFA_RET_INVALID_PARAMETERS; + + spin_lock(&ctx->rx_lock); + spin_lock(&ctx->tx_lock); + /* Already mapped */ if ( ctx->rx ) - return FFA_RET_DENIED; + { + ret =3D FFA_RET_DENIED; + goto err_unlock_rxtx; + } =20 tx_pg =3D get_page_from_gfn(d, gfn_x(gaddr_to_gfn(tx_addr)), &t, P2M_A= LLOC); if ( !tx_pg ) - return FFA_RET_INVALID_PARAMETERS; + goto err_unlock_rxtx; =20 /* Only normal RW RAM for now */ if ( t !=3D p2m_ram_rw ) @@ -167,6 +177,10 @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t = tx_addr, ctx->tx_pg =3D tx_pg; ctx->page_count =3D page_count; ctx->rx_is_free =3D true; + + spin_unlock(&ctx->tx_lock); + spin_unlock(&ctx->rx_lock); + return FFA_RET_OK; =20 err_unmap_rx: @@ -177,24 +191,32 @@ err_put_rx_pg: put_page(rx_pg); err_put_tx_pg: put_page(tx_pg); +err_unlock_rxtx: + spin_unlock(&ctx->tx_lock); + spin_unlock(&ctx->rx_lock); =20 return ret; } =20 -static uint32_t rxtx_unmap(struct domain *d) +static int32_t rxtx_unmap(struct domain *d) { struct ffa_ctx *ctx =3D d->arch.tee; + int32_t ret =3D FFA_RET_OK; + + spin_lock(&ctx->rx_lock); + spin_lock(&ctx->tx_lock); =20 if ( !ctx->page_count ) - return FFA_RET_INVALID_PARAMETERS; + { + ret =3D FFA_RET_INVALID_PARAMETERS; + goto err_unlock_rxtx; + } =20 if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) { - uint32_t ret; - ret =3D ffa_rxtx_unmap(ffa_get_vm_id(d)); if ( ret !=3D FFA_RET_OK ) - return ret; + goto err_unlock_rxtx; } =20 unmap_domain_page_global(ctx->rx); @@ -208,10 +230,14 @@ static uint32_t rxtx_unmap(struct domain *d) ctx->page_count =3D 0; ctx->rx_is_free =3D false; =20 - return FFA_RET_OK; +err_unlock_rxtx: + spin_unlock(&ctx->tx_lock); + spin_unlock(&ctx->rx_lock); + + return ret; } =20 -uint32_t ffa_handle_rxtx_unmap(void) +int32_t ffa_handle_rxtx_unmap(void) { return rxtx_unmap(current->domain); } @@ -272,6 +298,22 @@ out: return ret; } =20 +int32_t ffa_rxtx_domain_init(struct domain *d) +{ + struct ffa_ctx *ctx =3D d->arch.tee; + + spin_lock_init(&ctx->rx_lock); + spin_lock_init(&ctx->tx_lock); + ctx->rx =3D NULL; + ctx->tx =3D NULL; + ctx->rx_pg =3D NULL; + ctx->tx_pg =3D NULL; + ctx->page_count =3D 0; + ctx->rx_is_free =3D false; + + return 0; +} + void ffa_rxtx_domain_destroy(struct domain *d) { rxtx_unmap(d); @@ -298,7 +340,7 @@ void ffa_rxtx_destroy(void) =20 bool ffa_rxtx_init(void) { - int e; + int32_t e; =20 /* Firmware not there or not supporting */ if ( !ffa_fw_supports_fid(FFA_RXTX_MAP_64) ) --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931087659168.50532270487236; Fri, 5 Dec 2025 02:38:07 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178639.1502414 (Exim 4.92) (envelope-from ) id 1vRTC8-0006ny-NS; Fri, 05 Dec 2025 10:37:48 +0000 Received: by outflank-mailman (output) from mailman id 1178639.1502414; Fri, 05 Dec 2025 10:37:48 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC8-0006nl-Jy; Fri, 05 Dec 2025 10:37:48 +0000 Received: by outflank-mailman (input) for mailman id 1178639; Fri, 05 Dec 2025 10:37:47 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC7-0005Ju-KJ for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:47 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 6f62ceb9-d1c6-11f0-980a-7dc792cee155; Fri, 05 Dec 2025 11:37:45 +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 5B0FE1575; Fri, 5 Dec 2025 02:37:37 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9BA273F86F; Fri, 5 Dec 2025 02:37:43 -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: 6f62ceb9-d1c6-11f0-980a-7dc792cee155 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 05/12] xen/arm: ffa: rework SPMC RX/TX buffer management Date: Fri, 5 Dec 2025 11:36:38 +0100 Message-ID: <491f62ede43a7a135327fa68afe9a648fde1dcba.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: 1764931089776019201 Content-Type: text/plain; charset="utf-8" Rework how Xen accesses the RX/TX buffers shared with the SPMC so that ownership and locking are handled centrally. Move the SPMC RX/TX buffer bases into ffa_rxtx.c as ffa_spmc_rx/ffa_spmc_tx, protect them with dedicated ffa_spmc_{rx,tx}_lock spinlocks and expose ffa_rxtx_spmc_{rx,tx}_{acquire,release}() helpers instead of the global ffa_rx/ffa_tx pointers and ffa_{rx,tx}_buffer_lock. The RX helpers now always issue FFA_RX_RELEASE when we are done consuming data from the SPMC, so partition-info enumeration and shared memory paths release the RX buffer on all exit paths. The RX/TX mapping code is updated to use the descriptor offsets (rx_region_offs and tx_region_offs) rather than hard-coded structure layout, and to use the TX acquire/release helpers instead of touching the TX buffer directly. Signed-off-by: Bertrand Marquis --- Changes in v1: - modify share_shm function to use a goto and have one place to release the spmc tx buffer instead of doing it directly in the if error condition. - fix rx_acquire and tx_acquire to not release the spinlock as this is expected to be done only in release to ensure no parallel usage. --- xen/arch/arm/tee/ffa.c | 22 +----- xen/arch/arm/tee/ffa_partinfo.c | 40 +++++----- xen/arch/arm/tee/ffa_private.h | 18 ++--- xen/arch/arm/tee/ffa_rxtx.c | 130 +++++++++++++++++++++++++------- xen/arch/arm/tee/ffa_shm.c | 29 ++++--- 5 files changed, 153 insertions(+), 86 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 497ada8264e0..43af49d1c011 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -48,8 +48,8 @@ * notification for secure partitions * - doesn't support notifications for Xen itself * - * There are some large locked sections with ffa_tx_buffer_lock and - * ffa_rx_buffer_lock. Especially the ffa_tx_buffer_lock spinlock used + * There are some large locked sections with ffa_spmc_tx_lock and + * ffa_spmc_rx_lock. Especially the ffa_spmc_tx_lock spinlock used * around share_shm() is a very large locked section which can let one VM * affect another VM. */ @@ -108,20 +108,6 @@ static const struct ffa_fw_abi ffa_fw_abi_needed[] =3D= { FW_ABI(FFA_RUN), }; =20 -/* - * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the - * number of pages used in each of these buffers. - * - * The RX buffer is protected from concurrent usage with ffa_rx_buffer_loc= k. - * Note that the SPMC is also tracking the ownership of our RX buffer so - * for calls which uses our RX buffer to deliver a result we must call - * ffa_rx_release() to let the SPMC know that we're done with the buffer. - */ -void *ffa_rx __read_mostly; -void *ffa_tx __read_mostly; -DEFINE_SPINLOCK(ffa_rx_buffer_lock); -DEFINE_SPINLOCK(ffa_tx_buffer_lock); - LIST_HEAD(ffa_ctx_head); /* RW Lock to protect addition/removal and reading in ffa_ctx_head */ DEFINE_RWLOCK(ffa_ctx_list_rwlock); @@ -617,7 +603,7 @@ static bool ffa_probe_fw(void) ffa_fw_abi_needed[i].name); } =20 - if ( !ffa_rxtx_init() ) + if ( !ffa_rxtx_spmc_init() ) { printk(XENLOG_ERR "ffa: Error during RXTX buffer init\n"); goto err_no_fw; @@ -631,7 +617,7 @@ static bool ffa_probe_fw(void) return true; =20 err_rxtx_destroy: - ffa_rxtx_destroy(); + ffa_rxtx_spmc_destroy(); err_no_fw: ffa_fw_version =3D 0; bitmap_zero(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE); diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinf= o.c index ec5a53ed1cab..145b869957b0 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -77,28 +77,24 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint= 32_t *sp_count, { int32_t ret; uint32_t src_size, real_sp_count; - void *src_buf =3D ffa_rx; + void *src_buf; uint32_t count =3D 0; =20 - /* Do we have a RX buffer with the SPMC */ - if ( !ffa_rx ) - return FFA_RET_DENIED; - /* We need to use the RX buffer to receive the list */ - spin_lock(&ffa_rx_buffer_lock); + src_buf =3D ffa_rxtx_spmc_rx_acquire(); + if ( !src_buf ) + return FFA_RET_DENIED; =20 ret =3D ffa_partition_info_get(uuid, 0, &real_sp_count, &src_size); if ( ret ) goto out; =20 - /* We now own the RX buffer */ - /* Validate the src_size we got */ if ( src_size < sizeof(struct ffa_partition_info_1_0) || src_size >=3D FFA_PAGE_SIZE ) { ret =3D FFA_RET_NOT_SUPPORTED; - goto out_release; + goto out; } =20 /* @@ -114,7 +110,7 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint= 32_t *sp_count, if ( real_sp_count > (FFA_RXTX_PAGE_COUNT * FFA_PAGE_SIZE) / src_size ) { ret =3D FFA_RET_NOT_SUPPORTED; - goto out_release; + goto out; } =20 for ( uint32_t sp_num =3D 0; sp_num < real_sp_count; sp_num++ ) @@ -127,7 +123,7 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint= 32_t *sp_count, if ( dst_buf > (end_buf - dst_size) ) { ret =3D FFA_RET_NO_MEMORY; - goto out_release; + goto out; } =20 memcpy(dst_buf, src_buf, MIN(src_size, dst_size)); @@ -143,10 +139,8 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uin= t32_t *sp_count, =20 *sp_count =3D count; =20 -out_release: - ffa_hyp_rx_release(); out: - spin_unlock(&ffa_rx_buffer_lock); + ffa_rxtx_spmc_rx_release(); return ret; } =20 @@ -378,7 +372,7 @@ static void uninit_subscribers(void) XFREE(subscr_vm_destroyed); } =20 -static bool init_subscribers(uint16_t count, uint32_t fpi_size) +static bool init_subscribers(void *buf, uint16_t count, uint32_t fpi_size) { uint16_t n; uint16_t c_pos; @@ -395,7 +389,7 @@ static bool init_subscribers(uint16_t count, uint32_t f= pi_size) subscr_vm_destroyed_count =3D 0; for ( n =3D 0; n < count; n++ ) { - fpi =3D ffa_rx + n * fpi_size; + fpi =3D buf + n * fpi_size; =20 /* * We need to have secure partitions using bit 15 set convention f= or @@ -433,7 +427,7 @@ static bool init_subscribers(uint16_t count, uint32_t f= pi_size) =20 for ( c_pos =3D 0, d_pos =3D 0, n =3D 0; n < count; n++ ) { - fpi =3D ffa_rx + n * fpi_size; + fpi =3D buf + n * fpi_size; =20 if ( FFA_ID_IS_SECURE(fpi->id) ) { @@ -455,10 +449,14 @@ bool ffa_partinfo_init(void) uint32_t fpi_size; uint32_t count; int e; + void *spmc_rx; =20 if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) || - !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) || - !ffa_rx || !ffa_tx ) + !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32)) + return false; + + spmc_rx =3D ffa_rxtx_spmc_rx_acquire(); + if (!spmc_rx) return false; =20 e =3D ffa_partition_info_get(NULL, 0, &count, &fpi_size); @@ -475,10 +473,10 @@ bool ffa_partinfo_init(void) goto out; } =20 - ret =3D init_subscribers(count, fpi_size); + ret =3D init_subscribers(spmc_rx, count, fpi_size); =20 out: - ffa_hyp_rx_release(); + ffa_rxtx_spmc_rx_release(); return ret; } =20 diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index d6400efd50bb..8797a62abd01 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -415,10 +415,6 @@ struct ffa_ctx { unsigned long *vm_destroy_bitmap; }; =20 -extern void *ffa_rx; -extern void *ffa_tx; -extern spinlock_t ffa_rx_buffer_lock; -extern spinlock_t ffa_tx_buffer_lock; extern DECLARE_BITMAP(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE); =20 extern struct list_head ffa_ctx_head; @@ -436,8 +432,13 @@ int ffa_partinfo_domain_init(struct domain *d); bool ffa_partinfo_domain_destroy(struct domain *d); void ffa_handle_partition_info_get(struct cpu_user_regs *regs); =20 -bool ffa_rxtx_init(void); -void ffa_rxtx_destroy(void); +bool ffa_rxtx_spmc_init(void); +void ffa_rxtx_spmc_destroy(void); +void *ffa_rxtx_spmc_rx_acquire(void); +void ffa_rxtx_spmc_rx_release(void); +void *ffa_rxtx_spmc_tx_acquire(void); +void ffa_rxtx_spmc_tx_release(void); + int32_t ffa_rxtx_domain_init(struct domain *d); void ffa_rxtx_domain_destroy(struct domain *d); int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, @@ -567,11 +568,6 @@ static inline int32_t ffa_simple_call(uint32_t fid, re= gister_t a1, return ffa_get_ret_code(&resp); } =20 -static inline int32_t ffa_hyp_rx_release(void) -{ - return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); -} - static inline bool ffa_fw_supports_fid(uint32_t fid) { BUILD_BUG_ON(FFA_FNUM_MIN_VALUE > FFA_FNUM_MAX_VALUE); diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index 5776693bb3f0..e325eae07bda 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -30,6 +30,20 @@ struct ffa_endpoint_rxtx_descriptor_1_1 { uint32_t tx_region_offs; }; =20 +/* + * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the + * number of pages used in each of these buffers. + * Each buffer has its own lock to protect from concurrent usage. + * + * Note that the SPMC is also tracking the ownership of our RX buffer so + * for calls which uses our RX buffer to deliver a result we must do an + * FFA_RX_RELEASE to let the SPMC know that we're done with the buffer. + */ +static void *ffa_spmc_rx __read_mostly; +static void *ffa_spmc_tx __read_mostly; +static DEFINE_SPINLOCK(ffa_spmc_rx_lock); +static DEFINE_SPINLOCK(ffa_spmc_tx_lock); + static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr, uint32_t page_count) { @@ -126,8 +140,9 @@ int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx= _addr, sizeof(struct ffa_address_range) * 2 > FFA_MAX_RXTX_PAGE_COUNT * FFA_PAGE_SIZE); =20 - spin_lock(&ffa_tx_buffer_lock); - rxtx_desc =3D ffa_tx; + rxtx_desc =3D ffa_rxtx_spmc_tx_acquire(); + if ( !rxtx_desc ) + goto err_unmap_rx; =20 /* * We have only one page for each so we pack everything: @@ -144,7 +159,7 @@ int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx= _addr, address_range_array[1]); =20 /* rx buffer */ - mem_reg =3D ffa_tx + sizeof(*rxtx_desc); + mem_reg =3D (void *)rxtx_desc + rxtx_desc->rx_region_offs; mem_reg->total_page_count =3D 1; mem_reg->address_range_count =3D 1; mem_reg->reserved =3D 0; @@ -154,7 +169,7 @@ int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx= _addr, mem_reg->address_range_array[0].reserved =3D 0; =20 /* tx buffer */ - mem_reg =3D ffa_tx + rxtx_desc->tx_region_offs; + mem_reg =3D (void *)rxtx_desc + rxtx_desc->tx_region_offs; mem_reg->total_page_count =3D 1; mem_reg->address_range_count =3D 1; mem_reg->reserved =3D 0; @@ -165,7 +180,7 @@ int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx= _addr, =20 ret =3D ffa_rxtx_map(0, 0, 0); =20 - spin_unlock(&ffa_tx_buffer_lock); + ffa_rxtx_spmc_tx_release(); =20 if ( ret !=3D FFA_RET_OK ) goto err_unmap_rx; @@ -319,49 +334,112 @@ void ffa_rxtx_domain_destroy(struct domain *d) rxtx_unmap(d); } =20 -void ffa_rxtx_destroy(void) +void *ffa_rxtx_spmc_rx_acquire(void) +{ + ASSERT(!spin_is_locked(&ffa_spmc_rx_lock)); + + spin_lock(&ffa_spmc_rx_lock); + + if ( ffa_spmc_rx ) + return ffa_spmc_rx; + + return NULL; +} + +void ffa_rxtx_spmc_rx_release(void) +{ + int32_t ret; + + ASSERT(spin_is_locked(&ffa_spmc_rx_lock)); + + /* Inform the SPMC that we are done with our RX buffer */ + ret =3D ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); + if ( ret !=3D FFA_RET_OK ) + printk(XENLOG_DEBUG "Error releasing SPMC RX buffer: %d\n", ret); + + spin_unlock(&ffa_spmc_rx_lock); +} + +void *ffa_rxtx_spmc_tx_acquire(void) { - bool need_unmap =3D ffa_tx && ffa_rx; + ASSERT(!spin_is_locked(&ffa_spmc_tx_lock)); =20 - if ( ffa_tx ) + spin_lock(&ffa_spmc_tx_lock); + + if ( ffa_spmc_tx ) + return ffa_spmc_tx; + + return NULL; +} + +void ffa_rxtx_spmc_tx_release(void) +{ + ASSERT(spin_is_locked(&ffa_spmc_tx_lock)); + + spin_unlock(&ffa_spmc_tx_lock); +} + +void ffa_rxtx_spmc_destroy(void) +{ + bool need_unmap; + + spin_lock(&ffa_spmc_rx_lock); + spin_lock(&ffa_spmc_tx_lock); + need_unmap =3D ffa_spmc_tx && ffa_spmc_rx; + + if ( ffa_spmc_tx ) { - free_xenheap_pages(ffa_tx, 0); - ffa_tx =3D NULL; + free_xenheap_pages(ffa_spmc_tx, 0); + ffa_spmc_tx =3D NULL; } - if ( ffa_rx ) + if ( ffa_spmc_rx ) { - free_xenheap_pages(ffa_rx, 0); - ffa_rx =3D NULL; + free_xenheap_pages(ffa_spmc_rx, 0); + ffa_spmc_rx =3D NULL; } =20 if ( need_unmap ) ffa_rxtx_unmap(0); + + spin_unlock(&ffa_spmc_tx_lock); + spin_unlock(&ffa_spmc_rx_lock); } =20 -bool ffa_rxtx_init(void) +bool ffa_rxtx_spmc_init(void) { int32_t e; + bool ret =3D false; =20 /* Firmware not there or not supporting */ if ( !ffa_fw_supports_fid(FFA_RXTX_MAP_64) ) return false; =20 - ffa_rx =3D alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUN= T), 0); - if ( !ffa_rx ) - return false; + spin_lock(&ffa_spmc_rx_lock); + spin_lock(&ffa_spmc_tx_lock); + + ffa_spmc_rx =3D alloc_xenheap_pages( + get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); + if ( !ffa_spmc_rx ) + goto exit; =20 - ffa_tx =3D alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUN= T), 0); - if ( !ffa_tx ) - goto err; + ffa_spmc_tx =3D alloc_xenheap_pages( + get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); + if ( !ffa_spmc_tx ) + goto exit; =20 - e =3D ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT); + e =3D ffa_rxtx_map(__pa(ffa_spmc_tx), __pa(ffa_spmc_rx), + FFA_RXTX_PAGE_COUNT); if ( e ) - goto err; + goto exit; =20 - return true; + ret =3D true; =20 -err: - ffa_rxtx_destroy(); +exit: + spin_unlock(&ffa_spmc_tx_lock); + spin_unlock(&ffa_spmc_rx_lock); =20 - return false; + if ( !ret ) + ffa_rxtx_spmc_destroy(); + + return ret; } diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index dad3da192247..e275d3769d9b 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -286,9 +286,8 @@ static void init_range(struct ffa_address_range *addr_r= ange, } =20 /* - * This function uses the ffa_tx buffer to transmit the memory transaction - * descriptor. The function depends ffa_tx_buffer_lock to be used to guard - * the buffer from concurrent use. + * This function uses the ffa_spmc tx buffer to transmit the memory transa= ction + * descriptor. */ static int share_shm(struct ffa_shm_mem *shm) { @@ -298,17 +297,22 @@ static int share_shm(struct ffa_shm_mem *shm) struct ffa_address_range *addr_range; struct ffa_mem_region *region_descr; const unsigned int region_count =3D 1; - void *buf =3D ffa_tx; uint32_t frag_len; uint32_t tot_len; paddr_t last_pa; unsigned int n; paddr_t pa; + int32_t ret; + void *buf; =20 - ASSERT(spin_is_locked(&ffa_tx_buffer_lock)); ASSERT(shm->page_count); =20 + buf =3D ffa_rxtx_spmc_tx_acquire(); + if ( !buf ) + return FFA_RET_NOT_SUPPORTED; + descr =3D buf; + memset(descr, 0, sizeof(*descr)); descr->sender_id =3D shm->sender_id; descr->handle =3D shm->handle; @@ -340,7 +344,10 @@ static int share_shm(struct ffa_shm_mem *shm) tot_len =3D ADDR_RANGE_OFFSET(descr->mem_access_count, region_count, region_descr->address_range_count); if ( tot_len > max_frag_len ) - return FFA_RET_NOT_SUPPORTED; + { + ret =3D FFA_RET_NOT_SUPPORTED; + goto out; + } =20 addr_range =3D region_descr->address_range_array; frag_len =3D ADDR_RANGE_OFFSET(descr->mem_access_count, region_count, = 1); @@ -360,7 +367,12 @@ static int share_shm(struct ffa_shm_mem *shm) init_range(addr_range, pa); } =20 - return ffa_mem_share(tot_len, frag_len, 0, 0, &shm->handle); + ret =3D ffa_mem_share(tot_len, frag_len, 0, 0, &shm->handle); + +out: + ffa_rxtx_spmc_tx_release(); + + return ret; } =20 static int read_mem_transaction(uint32_t ffa_vers, const void *buf, size_t= blen, @@ -579,10 +591,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) if ( ret ) goto out; =20 - /* Note that share_shm() uses our tx buffer */ - spin_lock(&ffa_tx_buffer_lock); ret =3D share_shm(shm); - spin_unlock(&ffa_tx_buffer_lock); if ( ret ) goto out; =20 --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931088922187.27744705442035; Fri, 5 Dec 2025 02:38:08 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178640.1502421 (Exim 4.92) (envelope-from ) id 1vRTC9-0006s9-6E; Fri, 05 Dec 2025 10:37:49 +0000 Received: by outflank-mailman (output) from mailman id 1178640.1502421; Fri, 05 Dec 2025 10:37:49 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC8-0006qu-Tf; Fri, 05 Dec 2025 10:37:48 +0000 Received: by outflank-mailman (input) for mailman id 1178640; Fri, 05 Dec 2025 10:37:47 +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 1vRTC7-0005j7-Qa for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:47 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 7027a3d5-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:46 +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 A65B5339; Fri, 5 Dec 2025 02:37:38 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F09853F86F; Fri, 5 Dec 2025 02:37:44 -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: 7027a3d5-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 06/12] xen/arm: ffa: rework VM RX/TX buffer management Date: Fri, 5 Dec 2025 11:36:39 +0100 Message-ID: <17755cde0354ba0a70996b3a0e9eae23c2342b72.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: 1764931089776019200 Content-Type: text/plain; charset="utf-8" Rework access to VM RX/TX buffer to use acquire/release functions equivalent to the ones used for the SPMC RX/TX buffers and remove all direct access to ctx->tx or ctx->rx by giving back the buffer pointer and size back in acquire. This design ensures that rx or page_count is not accessed without the lock held and limit direct usage of the context rx/tx buffer info to ffa_rxtx.c Modify msg, partinfo and shm code to use the new RX/TX buffer acquire/release functions and remove all direct accesses to rx/tx and page_count so that any access is done only with the lock taken. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - patch introduced --- xen/arch/arm/tee/ffa.c | 2 +- xen/arch/arm/tee/ffa_msg.c | 32 ++++++++++++------------ xen/arch/arm/tee/ffa_partinfo.c | 8 +++--- xen/arch/arm/tee/ffa_private.h | 6 +++-- xen/arch/arm/tee/ffa_rxtx.c | 43 ++++++++++++++++++++++++++++----- xen/arch/arm/tee/ffa_shm.c | 18 +++++++------- 6 files changed, 72 insertions(+), 37 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 43af49d1c011..69a5e1e876ce 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -345,7 +345,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) ffa_handle_partition_info_get(regs); return true; case FFA_RX_RELEASE: - e =3D ffa_rx_release(d); + e =3D ffa_rx_release(ctx); break; case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index 2c2ebc9c5cd6..d60eed6d8811 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -94,6 +94,8 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, const vo= id *src_buf, struct domain *dst_d; struct ffa_ctx *dst_ctx; struct ffa_part_msg_rxtx *dst_msg; + void *rx_buf; + size_t rx_size; int err; int32_t ret; =20 @@ -120,20 +122,19 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, cons= t void *src_buf, } =20 /* This also checks that destination has set a Rx buffer */ - ret =3D ffa_rx_acquire(dst_d); + ret =3D ffa_rx_acquire(dst_ctx , &rx_buf, &rx_size); if ( ret ) goto out_unlock; =20 /* we need to have enough space in the destination buffer */ - if ( (dst_ctx->page_count * FFA_PAGE_SIZE - - sizeof(struct ffa_part_msg_rxtx)) < src_msg->msg_size ) + if ( (rx_size - sizeof(struct ffa_part_msg_rxtx)) < src_msg->msg_size ) { ret =3D FFA_RET_NO_MEMORY; - ffa_rx_release(dst_d); + ffa_rx_release(dst_ctx); goto out_unlock; } =20 - dst_msg =3D dst_ctx->rx; + dst_msg =3D rx_buf; =20 /* prepare destination header */ dst_msg->flags =3D 0; @@ -142,7 +143,7 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, const = void *src_buf, dst_msg->send_recv_id =3D src_msg->send_recv_id; dst_msg->msg_size =3D src_msg->msg_size; =20 - memcpy(dst_ctx->rx + sizeof(struct ffa_part_msg_rxtx), + memcpy(rx_buf + sizeof(struct ffa_part_msg_rxtx), src_buf + src_msg->msg_offset, src_msg->msg_size); =20 /* receiver rx buffer will be released by the receiver*/ @@ -159,17 +160,20 @@ int32_t ffa_handle_msg_send2(struct cpu_user_regs *re= gs) { struct domain *src_d =3D current->domain; struct ffa_ctx *src_ctx =3D src_d->arch.tee; + const void *tx_buf; + size_t tx_size; struct ffa_part_msg_rxtx src_msg; uint16_t dst_id, src_id; int32_t ret; =20 BUILD_BUG_ON(sizeof(struct ffa_part_msg_rxtx) >=3D FFA_PAGE_SIZE); =20 - if ( !spin_trylock(&src_ctx->tx_lock) ) - return FFA_RET_BUSY; + ret =3D ffa_tx_acquire(src_ctx, &tx_buf, &tx_size); + if ( ret !=3D FFA_RET_OK ) + return ret; =20 /* create a copy of the message header */ - memcpy(&src_msg, src_ctx->tx, sizeof(src_msg)); + memcpy(&src_msg, tx_buf, sizeof(src_msg)); =20 src_id =3D src_msg.send_recv_id >> 16; dst_id =3D src_msg.send_recv_id & GENMASK(15,0); @@ -182,10 +186,8 @@ int32_t ffa_handle_msg_send2(struct cpu_user_regs *reg= s) =20 /* check source message fits in buffer */ if ( src_msg.msg_offset < sizeof(struct ffa_part_msg_rxtx) || - src_msg.msg_size =3D=3D 0 || - src_msg.msg_offset > src_ctx->page_count * FFA_PAGE_SIZE || - src_msg.msg_size > (src_ctx->page_count * FFA_PAGE_SIZE - - src_msg.msg_offset) ) + src_msg.msg_size =3D=3D 0 || src_msg.msg_offset > tx_size || + src_msg.msg_size > (tx_size - src_msg.msg_offset) ) { ret =3D FFA_RET_INVALID_PARAMETERS; goto out; @@ -206,12 +208,12 @@ int32_t ffa_handle_msg_send2(struct cpu_user_regs *re= gs) else if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) ) { /* Message for a VM */ - ret =3D ffa_msg_send2_vm(dst_id, src_ctx->tx, &src_msg); + ret =3D ffa_msg_send2_vm(dst_id, tx_buf, &src_msg); } else ret =3D FFA_RET_INVALID_PARAMETERS; =20 out: - spin_unlock(&src_ctx->tx_lock); + ffa_tx_release(src_ctx); return ret; } diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinf= o.c index 145b869957b0..16c905cb12b8 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -224,6 +224,7 @@ void ffa_handle_partition_info_get(struct cpu_user_regs= *regs) get_user_reg(regs, 4), }; 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 @@ -268,12 +269,11 @@ void ffa_handle_partition_info_get(struct cpu_user_re= gs *regs) } =20 /* Get the RX buffer to write the list of partitions */ - ret =3D ffa_rx_acquire(d); + ret =3D ffa_rx_acquire(ctx, &dst_buf, &buf_size); if ( ret !=3D FFA_RET_OK ) goto out; =20 - dst_buf =3D ctx->rx; - end_buf =3D ctx->rx + ctx->page_count * FFA_PAGE_SIZE; + end_buf =3D dst_buf + buf_size; =20 /* An entry should be smaller than a page */ BUILD_BUG_ON(sizeof(struct ffa_partition_info_1_1) > FFA_PAGE_SIZE); @@ -304,7 +304,7 @@ void ffa_handle_partition_info_get(struct cpu_user_regs= *regs) =20 out_rx_release: if ( ret ) - ffa_rx_release(d); + ffa_rx_release(ctx); out: if ( ret ) ffa_set_regs_error(regs, ret); diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 8797a62abd01..0d1bab6cc700 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -444,8 +444,10 @@ void ffa_rxtx_domain_destroy(struct domain *d); int32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count); int32_t ffa_handle_rxtx_unmap(void); -int32_t ffa_rx_acquire(struct domain *d); -int32_t ffa_rx_release(struct domain *d); +int32_t ffa_rx_acquire(struct ffa_ctx *ctx, void **buf, size_t *buf_size); +int32_t ffa_rx_release(struct ffa_ctx *ctx); +int32_t ffa_tx_acquire(struct ffa_ctx *ctx, const void **buf, size_t *buf_= size); +int32_t ffa_tx_release(struct ffa_ctx *ctx); =20 void ffa_notif_init(void); void ffa_notif_init_interrupt(void); diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index e325eae07bda..f79f2cf406aa 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -257,10 +257,9 @@ int32_t ffa_handle_rxtx_unmap(void) return rxtx_unmap(current->domain); } =20 -int32_t ffa_rx_acquire(struct domain *d) +int32_t ffa_rx_acquire(struct ffa_ctx *ctx, void **buf, size_t *buf_size) { int32_t ret =3D FFA_RET_OK; - struct ffa_ctx *ctx =3D d->arch.tee; =20 spin_lock(&ctx->rx_lock); =20 @@ -278,21 +277,22 @@ int32_t ffa_rx_acquire(struct domain *d) =20 if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) { - ret =3D ffa_simple_call(FFA_RX_ACQUIRE, ffa_get_vm_id(d), 0, 0, 0); + ret =3D ffa_simple_call(FFA_RX_ACQUIRE, ctx->ffa_id, 0, 0, 0); if ( ret !=3D FFA_RET_OK ) goto out; } ctx->rx_is_free =3D false; + *buf =3D ctx->rx; + *buf_size =3D ctx->page_count * FFA_PAGE_SIZE; out: spin_unlock(&ctx->rx_lock); =20 return ret; } =20 -int32_t ffa_rx_release(struct domain *d) +int32_t ffa_rx_release(struct ffa_ctx *ctx) { int32_t ret =3D FFA_RET_DENIED; - struct ffa_ctx *ctx =3D d->arch.tee; =20 spin_lock(&ctx->rx_lock); =20 @@ -301,7 +301,7 @@ int32_t ffa_rx_release(struct domain *d) =20 if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) { - ret =3D ffa_simple_call(FFA_RX_RELEASE, ffa_get_vm_id(d), 0, 0, 0); + ret =3D ffa_simple_call(FFA_RX_RELEASE, ctx->ffa_id, 0, 0, 0); if ( ret !=3D FFA_RET_OK ) goto out; } @@ -313,6 +313,37 @@ out: return ret; } =20 +int32_t ffa_tx_acquire(struct ffa_ctx *ctx, const void **buf, size_t *buf_= size) +{ + int32_t ret =3D FFA_RET_DENIED; + + if ( !spin_trylock(&ctx->tx_lock) ) + return FFA_RET_BUSY; + + if ( !ctx->page_count ) + goto err_unlock; + + if ( !ctx->tx ) + goto err_unlock; + + *buf =3D ctx->tx; + *buf_size =3D ctx->page_count * FFA_PAGE_SIZE; + return FFA_RET_OK; + +err_unlock: + spin_unlock(&ctx->tx_lock); + + return ret; +} + +int32_t ffa_tx_release(struct ffa_ctx *ctx) +{ + ASSERT(spin_is_locked(&ctx->tx_lock)); + + spin_unlock(&ctx->tx_lock); + return FFA_RET_OK; +} + int32_t ffa_rxtx_domain_init(struct domain *d) { struct ffa_ctx *ctx =3D d->arch.tee; diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index e275d3769d9b..b862578c553c 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -460,6 +460,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) struct ffa_mem_transaction_int trans; struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; + const void *tx_buf; + size_t tx_size; struct ffa_shm_mem *shm =3D NULL; register_t handle_hi =3D 0; register_t handle_lo =3D 0; @@ -498,16 +500,14 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_set_ret; } =20 - if ( !spin_trylock(&ctx->tx_lock) ) - { - ret =3D FFA_RET_BUSY; + ret =3D ffa_tx_acquire(ctx, &tx_buf, &tx_size); + if ( ret !=3D FFA_RET_OK ) goto out_set_ret; - } =20 - if ( frag_len > ctx->page_count * FFA_PAGE_SIZE ) + if ( frag_len > tx_size ) goto out_unlock; =20 - ret =3D read_mem_transaction(ACCESS_ONCE(ctx->guest_vers), ctx->tx, + ret =3D read_mem_transaction(ACCESS_ONCE(ctx->guest_vers), tx_buf, frag_len, &trans); if ( ret ) goto out_unlock; @@ -535,7 +535,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) if ( trans.mem_access_offs + trans.mem_access_size > frag_len ) goto out_unlock; =20 - mem_access =3D ctx->tx + trans.mem_access_offs; + mem_access =3D tx_buf + trans.mem_access_offs; =20 dst_id =3D ACCESS_ONCE(mem_access->access_perm.endpoint_id); if ( !FFA_ID_IS_SECURE(dst_id) ) @@ -558,7 +558,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; } =20 - region_descr =3D ctx->tx + region_offs; + region_descr =3D tx_buf + region_offs; range_count =3D ACCESS_ONCE(region_descr->address_range_count); page_count =3D ACCESS_ONCE(region_descr->total_page_count); =20 @@ -605,7 +605,7 @@ out: if ( ret ) free_ffa_shm_mem(d, shm); out_unlock: - spin_unlock(&ctx->tx_lock); + ffa_tx_release(ctx); =20 out_set_ret: if ( ret =3D=3D 0) --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931092914352.30275385917673; Fri, 5 Dec 2025 02:38:12 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178641.1502434 (Exim 4.92) (envelope-from ) id 1vRTCB-0007Lc-IW; Fri, 05 Dec 2025 10:37:51 +0000 Received: by outflank-mailman (output) from mailman id 1178641.1502434; 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-0007LC-Dl; Fri, 05 Dec 2025 10:37:51 +0000 Received: by outflank-mailman (input) for mailman id 1178641; Fri, 05 Dec 2025 10:37:49 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTC9-0005Ju-Tk 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-flk1.inumbo.com (Halon) with ESMTP id 70e7667f-d1c6-11f0-980a-7dc792cee155; Fri, 05 Dec 2025 11:37:47 +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 F234F1063; Fri, 5 Dec 2025 02:37:39 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 484DF3F86F; Fri, 5 Dec 2025 02:37:46 -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: 70e7667f-d1c6-11f0-980a-7dc792cee155 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 07/12] xen/arm: ffa: use signed 32-bit status codes Date: Fri, 5 Dec 2025 11:36:40 +0100 Message-ID: <5f4cf1aefa11c0883a312384854a8c43b096d3e8.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: 1764931093858019200 Content-Type: text/plain; charset="utf-8" The FF-A spec defines return status values as signed 32-bit integers. Align the Xen mediator with this requirement by: - switching the FF-A helpers (ffa_handle_mem_reclaim(), partition info init, notification ops, dispatcher glue, etc.) to int32_t return types so callers cannot silently truncate negative values - masking SMCCC responses/exits in ffa_get_version(), ffa_get_ret_code() and ffa_set_regs_error() to 32 bits before storing them in guest registers - updating notifier, shared-memory reclaim, partition-info and dispatcher call sites to use the new prototypes so the entire FF-A path propagates spec-compliant 32-bit signed error codes While there, tidy up the FF-A notification helpers by using GENMASK(15, 0) for endpoint extraction and fix the secure-endpoint check in ffa_handle_notification_set() to apply the mask to the endpoint ID before calling FFA_ID_IS_SECURE(), instead of testing the wrong halfword of src_dst. Fixes: 911b305e7bdab ("xen/arm: ffa: Enable VM to VM without firmware") Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - add Jens R-b --- xen/arch/arm/tee/ffa.c | 12 +++++++----- xen/arch/arm/tee/ffa_notif.c | 14 +++++++------- xen/arch/arm/tee/ffa_partinfo.c | 4 ++-- xen/arch/arm/tee/ffa_private.h | 21 +++++++++++---------- xen/arch/arm/tee/ffa_shm.c | 4 ++-- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 69a5e1e876ce..2c09d10ae6a1 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -129,12 +129,14 @@ static bool ffa_get_version(uint32_t *vers) .a1 =3D FFA_MY_VERSION, }; struct arm_smccc_1_2_regs resp; + int32_t ret; =20 arm_smccc_1_2_smc(&arg, &resp); - if ( resp.a0 =3D=3D FFA_RET_NOT_SUPPORTED ) + ret =3D resp.a0 & GENMASK_ULL(31, 0); + if ( ret =3D=3D FFA_RET_NOT_SUPPORTED ) return false; =20 - *vers =3D resp.a0; + *vers =3D resp.a0 & GENMASK_ULL(31, 0); =20 return true; } @@ -310,7 +312,7 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) uint32_t fid =3D get_user_reg(regs, 0); struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; - int e; + int32_t e; =20 if ( !ctx ) return false; @@ -382,8 +384,8 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) =20 default: gprintk(XENLOG_ERR, "ffa: unhandled fid 0x%x\n", fid); - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); - return true; + e =3D FFA_RET_NOT_SUPPORTED; + break; } =20 if ( e ) diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c index 86bef6b3b2ab..37b05747cd21 100644 --- a/xen/arch/arm/tee/ffa_notif.c +++ b/xen/arch/arm/tee/ffa_notif.c @@ -19,7 +19,7 @@ static bool __ro_after_init fw_notif_enabled; static unsigned int __ro_after_init notif_sri_irq; =20 -int ffa_handle_notification_bind(struct cpu_user_regs *regs) +int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs) { struct domain *d =3D current->domain; uint32_t src_dst =3D get_user_reg(regs, 1); @@ -27,7 +27,7 @@ int ffa_handle_notification_bind(struct cpu_user_regs *re= gs) uint32_t bitmap_lo =3D get_user_reg(regs, 3); uint32_t bitmap_hi =3D get_user_reg(regs, 4); =20 - if ( (src_dst & 0xFFFFU) !=3D ffa_get_vm_id(d) ) + if ( (src_dst & GENMASK(15, 0)) !=3D ffa_get_vm_id(d) ) return FFA_RET_INVALID_PARAMETERS; =20 if ( flags ) /* Only global notifications are supported */ @@ -40,14 +40,14 @@ int ffa_handle_notification_bind(struct cpu_user_regs *= regs) return FFA_RET_NOT_SUPPORTED; } =20 -int ffa_handle_notification_unbind(struct cpu_user_regs *regs) +int32_t ffa_handle_notification_unbind(struct cpu_user_regs *regs) { struct domain *d =3D current->domain; uint32_t src_dst =3D get_user_reg(regs, 1); uint32_t bitmap_lo =3D get_user_reg(regs, 3); uint32_t bitmap_hi =3D get_user_reg(regs, 4); =20 - if ( (src_dst & 0xFFFFU) !=3D ffa_get_vm_id(d) ) + if ( (src_dst & GENMASK(15, 0)) !=3D ffa_get_vm_id(d) ) return FFA_RET_INVALID_PARAMETERS; =20 if ( FFA_ID_IS_SECURE(src_dst >> 16) && fw_notif_enabled ) @@ -106,7 +106,7 @@ void ffa_handle_notification_get(struct cpu_user_regs *= regs) return; } =20 - if ( (recv & 0xFFFFU) !=3D ffa_get_vm_id(d) ) + if ( (recv & GENMASK(15, 0)) !=3D ffa_get_vm_id(d) ) { ffa_set_regs_error(regs, FFA_RET_INVALID_PARAMETERS); return; @@ -162,7 +162,7 @@ void ffa_handle_notification_get(struct cpu_user_regs *= regs) ffa_set_regs(regs, FFA_SUCCESS_32, 0, w2, w3, w4, w5, w6, w7); } =20 -int ffa_handle_notification_set(struct cpu_user_regs *regs) +int32_t ffa_handle_notification_set(struct cpu_user_regs *regs) { struct domain *d =3D current->domain; uint32_t src_dst =3D get_user_reg(regs, 1); @@ -173,7 +173,7 @@ int ffa_handle_notification_set(struct cpu_user_regs *r= egs) if ( (src_dst >> 16) !=3D ffa_get_vm_id(d) ) return FFA_RET_INVALID_PARAMETERS; =20 - if ( FFA_ID_IS_SECURE(src_dst >> 16) && fw_notif_enabled ) + if ( FFA_ID_IS_SECURE(src_dst & GENMASK(15, 0)) && fw_notif_enabled ) return ffa_simple_call(FFA_NOTIFICATION_SET, src_dst, flags, bitma= p_lo, bitmap_hi); =20 diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinf= o.c index 16c905cb12b8..c9faf5415853 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -448,7 +448,7 @@ bool ffa_partinfo_init(void) bool ret =3D false; uint32_t fpi_size; uint32_t count; - int e; + int32_t e; void *spmc_rx; =20 if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) || @@ -515,7 +515,7 @@ static void vm_destroy_bitmap_init(struct ffa_ctx *ctx, } } =20 -int ffa_partinfo_domain_init(struct domain *d) +int32_t ffa_partinfo_domain_init(struct domain *d) { unsigned int count =3D BITS_TO_LONGS(subscr_vm_destroyed_count); struct ffa_ctx *ctx =3D d->arch.tee; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 0d1bab6cc700..a18e56b05bbb 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -31,9 +31,9 @@ =20 /* FFA_VERSION helpers */ #define FFA_VERSION_MAJOR_SHIFT 16U -#define FFA_VERSION_MAJOR_MASK 0x7FFFU +#define FFA_VERSION_MAJOR_MASK GENMASK(14, 0) #define FFA_VERSION_MINOR_SHIFT 0U -#define FFA_VERSION_MINOR_MASK 0xFFFFU +#define FFA_VERSION_MINOR_MASK GENMASK(15, 0) #define MAKE_FFA_VERSION(major, minor) \ ((((major) & FFA_VERSION_MAJOR_MASK) << FFA_VERSION_MAJOR_SHIFT) |= \ ((minor) & FFA_VERSION_MINOR_MASK)) @@ -425,10 +425,10 @@ extern atomic_t ffa_vm_count; =20 bool ffa_shm_domain_destroy(struct domain *d); void ffa_handle_mem_share(struct cpu_user_regs *regs); -int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags); +int32_t ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags); =20 bool ffa_partinfo_init(void); -int ffa_partinfo_domain_init(struct domain *d); +int32_t ffa_partinfo_domain_init(struct domain *d); bool ffa_partinfo_domain_destroy(struct domain *d); void ffa_handle_partition_info_get(struct cpu_user_regs *regs); =20 @@ -454,11 +454,11 @@ void ffa_notif_init_interrupt(void); int ffa_notif_domain_init(struct domain *d); void ffa_notif_domain_destroy(struct domain *d); =20 -int ffa_handle_notification_bind(struct cpu_user_regs *regs); -int ffa_handle_notification_unbind(struct cpu_user_regs *regs); +int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs); +int32_t ffa_handle_notification_unbind(struct cpu_user_regs *regs); void ffa_handle_notification_info_get(struct cpu_user_regs *regs); void ffa_handle_notification_get(struct cpu_user_regs *regs); -int ffa_handle_notification_set(struct cpu_user_regs *regs); +int32_t ffa_handle_notification_set(struct cpu_user_regs *regs); =20 #ifdef CONFIG_FFA_VM_TO_VM void ffa_raise_rx_buffer_full(struct domain *d); @@ -524,9 +524,10 @@ static inline void ffa_set_regs(struct cpu_user_regs *= regs, register_t v0, } =20 static inline void ffa_set_regs_error(struct cpu_user_regs *regs, - uint32_t error_code) + int32_t error_code) { - ffa_set_regs(regs, FFA_ERROR, 0, error_code, 0, 0, 0, 0, 0); + ffa_set_regs(regs, FFA_ERROR, 0, error_code & GENMASK_ULL(31, 0), 0, 0= , 0, + 0, 0); } =20 static inline void ffa_set_regs_success(struct cpu_user_regs *regs, @@ -541,7 +542,7 @@ static inline int32_t ffa_get_ret_code(const struct arm= _smccc_1_2_regs *resp) { case FFA_ERROR: if ( resp->a2 ) - return resp->a2; + return resp->a2 & GENMASK_ULL(31, 0); else return FFA_RET_NOT_SUPPORTED; case FFA_SUCCESS_32: diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index b862578c553c..8282bacf85d3 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -626,14 +626,14 @@ static struct ffa_shm_mem *find_shm_mem(struct ffa_ct= x *ctx, uint64_t handle) return NULL; } =20 -int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags) +int32_t ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags) { struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; struct ffa_shm_mem *shm; register_t handle_hi; register_t handle_lo; - int ret; + int32_t ret; =20 if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) return FFA_RET_NOT_SUPPORTED; --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 From nobody Fri Dec 12 19:30:14 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 1764931092520990.5080106160103; Fri, 5 Dec 2025 02:38:12 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178644.1502452 (Exim 4.92) (envelope-from ) id 1vRTCD-0007mm-B3; Fri, 05 Dec 2025 10:37:53 +0000 Received: by outflank-mailman (output) from mailman id 1178644.1502452; Fri, 05 Dec 2025 10:37:53 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTCD-0007ko-3f; Fri, 05 Dec 2025 10:37:53 +0000 Received: by outflank-mailman (input) for mailman id 1178644; Fri, 05 Dec 2025 10:37:51 +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 1vRTCB-0005j7-5K for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:51 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 727d3404-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:50 +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 A1C251575; Fri, 5 Dec 2025 02:37:42 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id ED5BD3F86F; Fri, 5 Dec 2025 02:37:48 -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: 727d3404-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 09/12] xen/arm: ffa: Add FFA_RUN support Date: Fri, 5 Dec 2025 11:36:42 +0100 Message-ID: <9e205ba6bdd6d053dfbf8cf7892d347512acdb2e.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: 1764931093780019200 Content-Type: text/plain; charset="utf-8" Add FFA_RUN support and remove mention that YIELD and INTERRUPT are not supported in the comment as we will now return them. Make FFA_FEATURE answer supported for RUN, YIELD and INTERRUPT. Share the SMCCC plumbing used by SEND_DIRECT and RUN via a common ffa_finish_direct_req_run() helper so canonical success and error cases are handled in one place. The dispatcher now routes FFA_RUN through ffa_handle_run(), and direct requests bail out early if a guest targets itself or a non-secure endpoint. This simplifies the direct path while adding support for INTERRUPT or YIELD answers from secure world. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - Rework commit message to clearly mention that we add FFA_RUN support - Remove mentions of FFA_MSG_YIELD/INTERRUPT/RUN not being supported - Report YIELD, INTERRUPT an RUN as supported in ffa_features handling --- xen/arch/arm/tee/ffa.c | 9 ++- xen/arch/arm/tee/ffa_msg.c | 111 ++++++++++++++++++++++++--------- xen/arch/arm/tee/ffa_private.h | 1 + 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 2c09d10ae6a1..0f07efe5a7b3 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -24,9 +24,6 @@ * o FFA_MEM_DONATE_* and FFA_MEM_LEND_* - Used when tranferring ownership * or access of a memory region * o FFA_MSG_SEND2 and FFA_MSG_WAIT - Used for indirect messaging - * o FFA_MSG_YIELD - * o FFA_INTERRUPT - Used to report preemption - * o FFA_RUN * * Limitations in the implemented FF-A interfaces: * o FFA_RXTX_MAP_*: @@ -266,6 +263,9 @@ static void handle_features(struct cpu_user_regs *regs) case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: case FFA_MSG_SEND2: + case FFA_RUN: + case FFA_INTERRUPT: + case FFA_MSG_YIELD: ffa_set_regs_success(regs, 0, 0); break; case FFA_MEM_SHARE_64: @@ -353,6 +353,9 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) case FFA_MSG_SEND_DIRECT_REQ_64: ffa_handle_msg_send_direct_req(regs, fid); return true; + case FFA_RUN: + ffa_handle_run(regs, fid); + return true; case FFA_MSG_SEND2: e =3D ffa_handle_msg_send2(regs); break; diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index d60eed6d8811..5a4cb1bb8295 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -21,42 +21,74 @@ struct ffa_part_msg_rxtx { uint32_t msg_size; }; =20 -void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t f= id) +static void ffa_finish_direct_req_run(struct cpu_user_regs *regs, + struct arm_smccc_1_2_regs *req) { - struct arm_smccc_1_2_regs arg =3D { .a0 =3D fid, }; struct arm_smccc_1_2_regs resp =3D { }; - struct domain *d =3D current->domain; - uint32_t src_dst; uint64_t mask; =20 - if ( smccc_is_conv_64(fid) ) + arm_smccc_1_2_smc(req, &resp); + + switch ( resp.a0 ) + { + case FFA_ERROR: + case FFA_SUCCESS_32: + case FFA_SUCCESS_64: + case FFA_MSG_SEND_DIRECT_RESP_32: + case FFA_MSG_SEND_DIRECT_RESP_64: + case FFA_MSG_YIELD: + case FFA_INTERRUPT: + break; + default: + /* Bad fid, report back to the caller. */ + ffa_set_regs_error(regs, FFA_RET_ABORTED); + return; + } + + if ( smccc_is_conv_64(resp.a0) ) mask =3D GENMASK_ULL(63, 0); else mask =3D GENMASK_ULL(31, 0); =20 + ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & = mask, + resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, + resp.a7 & mask); +} + +void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t f= id) +{ + struct arm_smccc_1_2_regs arg =3D { .a0 =3D fid, }; + struct domain *d =3D current->domain; + uint32_t src_dst; + uint64_t mask; + int32_t ret; + if ( !ffa_fw_supports_fid(fid) ) { - resp.a0 =3D FFA_ERROR; - resp.a2 =3D FFA_RET_NOT_SUPPORTED; + ret =3D FFA_RET_NOT_SUPPORTED; goto out; } =20 src_dst =3D get_user_reg(regs, 1); - if ( (src_dst >> 16) !=3D ffa_get_vm_id(d) ) + if ( (src_dst >> 16) !=3D ffa_get_vm_id(d) || + (src_dst & GENMASK(15,0)) =3D=3D ffa_get_vm_id(d) ) { - resp.a0 =3D FFA_ERROR; - resp.a2 =3D FFA_RET_INVALID_PARAMETERS; + ret =3D FFA_RET_INVALID_PARAMETERS; goto out; } =20 /* we do not support direct messages to VMs */ if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) { - resp.a0 =3D FFA_ERROR; - resp.a2 =3D FFA_RET_NOT_SUPPORTED; + ret =3D FFA_RET_NOT_SUPPORTED; goto out; } =20 + if ( smccc_is_conv_64(fid) ) + mask =3D GENMASK_ULL(63, 0); + else + mask =3D GENMASK_ULL(31, 0); + arg.a1 =3D src_dst; arg.a2 =3D get_user_reg(regs, 2) & mask; arg.a3 =3D get_user_reg(regs, 3) & mask; @@ -65,27 +97,11 @@ void ffa_handle_msg_send_direct_req(struct cpu_user_reg= s *regs, uint32_t fid) arg.a6 =3D get_user_reg(regs, 6) & mask; arg.a7 =3D get_user_reg(regs, 7) & mask; =20 - arm_smccc_1_2_smc(&arg, &resp); - switch ( resp.a0 ) - { - case FFA_ERROR: - case FFA_SUCCESS_32: - case FFA_SUCCESS_64: - case FFA_MSG_SEND_DIRECT_RESP_32: - case FFA_MSG_SEND_DIRECT_RESP_64: - break; - default: - /* Bad fid, report back to the caller. */ - memset(&resp, 0, sizeof(resp)); - resp.a0 =3D FFA_ERROR; - resp.a1 =3D src_dst; - resp.a2 =3D FFA_RET_ABORTED; - } + ffa_finish_direct_req_run(regs, &arg); + return; =20 out: - ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & = mask, - resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, - resp.a7 & mask); + ffa_set_regs_error(regs, ret); } =20 static int32_t ffa_msg_send2_vm(uint16_t dst_id, const void *src_buf, @@ -217,3 +233,36 @@ out: ffa_tx_release(src_ctx); return ret; } + +void ffa_handle_run(struct cpu_user_regs *regs, uint32_t fid) +{ + struct arm_smccc_1_2_regs arg =3D { .a0 =3D fid, }; + uint32_t dst =3D get_user_reg(regs, 1); + int32_t ret; + + if ( !ffa_fw_supports_fid(fid) ) + { + ret =3D FFA_RET_NOT_SUPPORTED; + goto out; + } + + /* + * We do not support FFA_RUN to VMs. + * Destination endpoint ID is in bits [31:16], bits[15:0] contain the + * vCPU ID. + */ + if ( !FFA_ID_IS_SECURE(dst >> 16) ) + { + ret =3D FFA_RET_NOT_SUPPORTED; + goto out; + } + + arg.a1 =3D dst; + + ffa_finish_direct_req_run(regs, &arg); + + return; + +out: + ffa_set_regs_error(regs, ret); +} diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index d883114948b1..030e6724743c 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -474,6 +474,7 @@ static inline void ffa_raise_rx_buffer_full(struct doma= in *d) =20 void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t f= id); int32_t ffa_handle_msg_send2(struct cpu_user_regs *regs); +void ffa_handle_run(struct cpu_user_regs *regs, uint32_t fid); =20 #ifdef CONFIG_FFA_VM_TO_VM static inline uint16_t get_ffa_vm_count(void) --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931098118349.5424719777502; Fri, 5 Dec 2025 02:38:18 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178646.1502464 (Exim 4.92) (envelope-from ) id 1vRTCF-0008Bc-2H; Fri, 05 Dec 2025 10:37:55 +0000 Received: by outflank-mailman (output) from mailman id 1178646.1502464; Fri, 05 Dec 2025 10:37:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTCE-0008Au-SS; Fri, 05 Dec 2025 10:37:54 +0000 Received: by outflank-mailman (input) for mailman id 1178646; Fri, 05 Dec 2025 10:37:54 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTCD-0005Ju-T7 for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:53 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 734c913f-d1c6-11f0-980a-7dc792cee155; Fri, 05 Dec 2025 11:37:51 +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 EBF9F1063; Fri, 5 Dec 2025 02:37:43 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 463BF3F86F; Fri, 5 Dec 2025 02:37:50 -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: 734c913f-d1c6-11f0-980a-7dc792cee155 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 10/12] xen/arm: ffa: add v1.2 SEND2 header layout Date: Fri, 5 Dec 2025 11:36:43 +0100 Message-ID: X-Mailer: git-send-email 2.51.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1764931099938019200 Content-Type: text/plain; charset="utf-8" Teach the SEND2 path about the distinct FF-A v1.1 and v1.2 RX/TX header layouts so we can propagate the 128-bit UUIDs introduced in v1.2. VM-to-VM SEND2 calls now build the larger v1.2 header, zeroing the UUID fields for v1.1 senders, and the dispatcher validates messages using the v1.1 header layout to keep legacy guests working. While there, make the code more robust by checking that the send is not trying to send a message to himself. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - Mention self send check in commit message - check header size depending on sender FF-A version and make sure 1.2 has enough space for 1.2 header - Simplify the code by setting uuid field of the header to Nil-UUID when testing the caller version and remove the need to pass the context to the send2_vm function - Use ACCESS_ONCE when reading sender ffa version --- xen/arch/arm/tee/ffa_msg.c | 58 ++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index 5a4cb1bb8295..c3552a3ae36d 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -13,7 +13,7 @@ #include "ffa_private.h" =20 /* Encoding of partition message in RX/TX buffer */ -struct ffa_part_msg_rxtx { +struct ffa_part_msg_rxtx_1_1 { uint32_t flags; uint32_t reserved; uint32_t msg_offset; @@ -21,6 +21,16 @@ struct ffa_part_msg_rxtx { uint32_t msg_size; }; =20 +struct ffa_part_msg_rxtx_1_2 { + uint32_t flags; + uint32_t reserved; + uint32_t msg_offset; + uint32_t send_recv_id; + uint32_t msg_size; + uint32_t reserved2; + uint64_t uuid[2]; +}; + static void ffa_finish_direct_req_run(struct cpu_user_regs *regs, struct arm_smccc_1_2_regs *req) { @@ -105,11 +115,11 @@ out: } =20 static int32_t ffa_msg_send2_vm(uint16_t dst_id, const void *src_buf, - struct ffa_part_msg_rxtx *src_msg) + struct ffa_part_msg_rxtx_1_2 *src_msg) { struct domain *dst_d; struct ffa_ctx *dst_ctx; - struct ffa_part_msg_rxtx *dst_msg; + struct ffa_part_msg_rxtx_1_2 *dst_msg; void *rx_buf; size_t rx_size; int err; @@ -143,7 +153,7 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, const = void *src_buf, goto out_unlock; =20 /* we need to have enough space in the destination buffer */ - if ( (rx_size - sizeof(struct ffa_part_msg_rxtx)) < src_msg->msg_size ) + if ( (rx_size - sizeof(struct ffa_part_msg_rxtx_1_2)) < src_msg->msg_s= ize ) { ret =3D FFA_RET_NO_MEMORY; ffa_rx_release(dst_ctx); @@ -155,11 +165,14 @@ static int32_t ffa_msg_send2_vm(uint16_t dst_id, cons= t void *src_buf, /* prepare destination header */ dst_msg->flags =3D 0; dst_msg->reserved =3D 0; - dst_msg->msg_offset =3D sizeof(struct ffa_part_msg_rxtx); + dst_msg->msg_offset =3D sizeof(struct ffa_part_msg_rxtx_1_2); dst_msg->send_recv_id =3D src_msg->send_recv_id; dst_msg->msg_size =3D src_msg->msg_size; + dst_msg->reserved2 =3D 0; + dst_msg->uuid[0] =3D src_msg->uuid[0]; + dst_msg->uuid[1] =3D src_msg->uuid[1]; =20 - memcpy(rx_buf + sizeof(struct ffa_part_msg_rxtx), + memcpy(rx_buf + sizeof(struct ffa_part_msg_rxtx_1_2), src_buf + src_msg->msg_offset, src_msg->msg_size); =20 /* receiver rx buffer will be released by the receiver*/ @@ -178,11 +191,17 @@ int32_t ffa_handle_msg_send2(struct cpu_user_regs *re= gs) struct ffa_ctx *src_ctx =3D src_d->arch.tee; const void *tx_buf; size_t tx_size; - struct ffa_part_msg_rxtx src_msg; + /* + * src_msg is interpreted as v1.2 header, but: + * - for v1.1 guests, uuid[] is ignored and may contain payload bytes + * - for v1.2 guests, uuid[] carries the FF-A v1.2 UUID fields + */ + struct ffa_part_msg_rxtx_1_2 src_msg; uint16_t dst_id, src_id; int32_t ret; =20 - BUILD_BUG_ON(sizeof(struct ffa_part_msg_rxtx) >=3D FFA_PAGE_SIZE); + BUILD_BUG_ON(sizeof(struct ffa_part_msg_rxtx_1_1) >=3D FFA_PAGE_SIZE); + BUILD_BUG_ON(sizeof(struct ffa_part_msg_rxtx_1_2) >=3D FFA_PAGE_SIZE); =20 ret =3D ffa_tx_acquire(src_ctx, &tx_buf, &tx_size); if ( ret !=3D FFA_RET_OK ) @@ -194,15 +213,32 @@ int32_t ffa_handle_msg_send2(struct cpu_user_regs *re= gs) src_id =3D src_msg.send_recv_id >> 16; dst_id =3D src_msg.send_recv_id & GENMASK(15,0); =20 - if ( src_id !=3D ffa_get_vm_id(src_d) ) + if ( src_id !=3D ffa_get_vm_id(src_d) || + dst_id =3D=3D ffa_get_vm_id(src_d) ) + { + ret =3D FFA_RET_INVALID_PARAMETERS; + goto out; + } + + if ( ACCESS_ONCE(src_ctx->guest_vers) < FFA_VERSION_1_2 ) + { + if (src_msg.msg_offset < sizeof(struct ffa_part_msg_rxtx_1_1)) + { + ret =3D FFA_RET_INVALID_PARAMETERS; + goto out; + } + /* Set uuid to Nil UUID for v1.1 guests */ + src_msg.uuid[0] =3D 0; + src_msg.uuid[1] =3D 0; + } + else if ( src_msg.msg_offset < sizeof(struct ffa_part_msg_rxtx_1_2) ) { ret =3D FFA_RET_INVALID_PARAMETERS; goto out; } =20 /* check source message fits in buffer */ - if ( src_msg.msg_offset < sizeof(struct ffa_part_msg_rxtx) || - src_msg.msg_size =3D=3D 0 || src_msg.msg_offset > tx_size || + if ( src_msg.msg_size =3D=3D 0 || src_msg.msg_offset > tx_size || src_msg.msg_size > (tx_size - src_msg.msg_offset) ) { ret =3D FFA_RET_INVALID_PARAMETERS; --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 176493131678152.94579268616542; Fri, 5 Dec 2025 02:41:56 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178748.1502483 (Exim 4.92) (envelope-from ) id 1vRTFt-0003zn-JR; Fri, 05 Dec 2025 10:41:41 +0000 Received: by outflank-mailman (output) from mailman id 1178748.1502483; Fri, 05 Dec 2025 10:41:41 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTFt-0003zg-Gt; Fri, 05 Dec 2025 10:41:41 +0000 Received: by outflank-mailman (input) for mailman id 1178748; Fri, 05 Dec 2025 10:41:40 +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 1vRTCD-0005j7-Tn for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:53 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 7417b842-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:53 +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 438AD1575; Fri, 5 Dec 2025 02:37:45 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 902FC3F86F; Fri, 5 Dec 2025 02:37:51 -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: 7417b842-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 11/12] xen/arm: ffa: add MSG_SEND_DIRECT_REQ2 support Date: Fri, 5 Dec 2025 11:36:44 +0100 Message-ID: <55a3df6c73581e7e77a76230cd445ccb16608269.1764930353.git.bertrand.marquis@arm.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1764931317505019200 Extend the direct-request path so FF-A v1.2 guests can issue FFA_MSG_SEND_DIRECT_REQ2 and receive the matching RESP2. The handler now marshals registers x8=E2=80=93x17, and ffa_finish_direct_req_run() copies back the 17-register response used by FFA_MSG_SEND_DIRECT_RESP2. The new opcode is exposed via FFA_FEATURES and gated on guests that negotiated v1.2. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - use ACCESS_ONCE to read guest_vers --- xen/arch/arm/tee/ffa.c | 20 +++++++++++++++++++ xen/arch/arm/tee/ffa_msg.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 0f07efe5a7b3..2c6443a7f6a4 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -237,6 +237,8 @@ out_continue: static void handle_features(struct cpu_user_regs *regs) { uint32_t a1 =3D get_user_reg(regs, 1); + struct domain *d =3D current->domain; + struct ffa_ctx *ctx =3D d->arch.tee; unsigned int n; =20 for ( n =3D 2; n <=3D 7; n++ ) @@ -268,6 +270,16 @@ static void handle_features(struct cpu_user_regs *regs) case FFA_MSG_YIELD: ffa_set_regs_success(regs, 0, 0); break; + case FFA_MSG_SEND_DIRECT_REQ2: + if ( ACCESS_ONCE(ctx->guest_vers) >=3D FFA_VERSION_1_2 ) + { + ffa_set_regs_success(regs, 0, 0); + } + else + { + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + } + break; case FFA_MEM_SHARE_64: case FFA_MEM_SHARE_32: /* @@ -353,6 +365,14 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) case FFA_MSG_SEND_DIRECT_REQ_64: ffa_handle_msg_send_direct_req(regs, fid); return true; + case FFA_MSG_SEND_DIRECT_REQ2: + if ( ACCESS_ONCE(ctx->guest_vers) >=3D FFA_VERSION_1_2 ) + { + ffa_handle_msg_send_direct_req(regs, fid); + return true; + } + e =3D FFA_RET_NOT_SUPPORTED; + break; case FFA_RUN: ffa_handle_run(regs, fid); return true; diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index c3552a3ae36d..4e26596461a9 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -49,6 +49,30 @@ static void ffa_finish_direct_req_run(struct cpu_user_re= gs *regs, case FFA_MSG_YIELD: case FFA_INTERRUPT: break; + case FFA_MSG_SEND_DIRECT_RESP2: + /* + * REQ2 / RESP2 use a 17-register payload (x1=E2=80=93x17). Copy a= ll of them + * back to the guest context. + */ + set_user_reg(regs, 0, resp.a0); + set_user_reg(regs, 1, resp.a1); + set_user_reg(regs, 2, resp.a2); + set_user_reg(regs, 3, resp.a3); + set_user_reg(regs, 4, resp.a4); + set_user_reg(regs, 5, resp.a5); + set_user_reg(regs, 6, resp.a6); + set_user_reg(regs, 7, resp.a7); + set_user_reg(regs, 8, resp.a8); + set_user_reg(regs, 9, resp.a9); + set_user_reg(regs, 10, resp.a10); + set_user_reg(regs, 11, resp.a11); + set_user_reg(regs, 12, resp.a12); + set_user_reg(regs, 13, resp.a13); + set_user_reg(regs, 14, resp.a14); + set_user_reg(regs, 15, resp.a15); + set_user_reg(regs, 16, resp.a16); + set_user_reg(regs, 17, resp.a17); + return; default: /* Bad fid, report back to the caller. */ ffa_set_regs_error(regs, FFA_RET_ABORTED); @@ -107,6 +131,21 @@ void ffa_handle_msg_send_direct_req(struct cpu_user_re= gs *regs, uint32_t fid) arg.a6 =3D get_user_reg(regs, 6) & mask; arg.a7 =3D get_user_reg(regs, 7) & mask; =20 + if ( fid =3D=3D FFA_MSG_SEND_DIRECT_REQ2 ) + { + /* 17 registers are used for REQ2 */ + arg.a8 =3D get_user_reg(regs, 8); + arg.a9 =3D get_user_reg(regs, 9); + arg.a10 =3D get_user_reg(regs, 10); + arg.a11 =3D get_user_reg(regs, 11); + arg.a12 =3D get_user_reg(regs, 12); + arg.a13 =3D get_user_reg(regs, 13); + arg.a14 =3D get_user_reg(regs, 14); + arg.a15 =3D get_user_reg(regs, 15); + arg.a16 =3D get_user_reg(regs, 16); + arg.a17 =3D get_user_reg(regs, 17); + } + ffa_finish_direct_req_run(regs, &arg); return; =20 --=20 2.51.2 From nobody Fri Dec 12 19:30:14 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 1764931315138505.7029319070722; Fri, 5 Dec 2025 02:41:55 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1178738.1502474 (Exim 4.92) (envelope-from ) id 1vRTFs-0003lc-Ec; Fri, 05 Dec 2025 10:41:40 +0000 Received: by outflank-mailman (output) from mailman id 1178738.1502474; Fri, 05 Dec 2025 10:41:40 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vRTFs-0003lV-Aa; Fri, 05 Dec 2025 10:41:40 +0000 Received: by outflank-mailman (input) for mailman id 1178738; Fri, 05 Dec 2025 10:41:38 +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 1vRTCF-0005j7-1U for xen-devel@lists.xenproject.org; Fri, 05 Dec 2025 10:37:55 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 74d3ab7c-d1c6-11f0-9d1b-b5c5bf9af7f9; Fri, 05 Dec 2025 11:37:54 +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 8AEF6339; Fri, 5 Dec 2025 02:37:46 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.45.211]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D91F33F86F; Fri, 5 Dec 2025 02:37:52 -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: 74d3ab7c-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 12/12] xen/arm: ffa: advertise FF-A v1.2 Date: Fri, 5 Dec 2025 11:36:45 +0100 Message-ID: <8412f616340976de6aa5f7da585cdc3dfd919732.1764930353.git.bertrand.marquis@arm.com> X-Mailer: git-send-email 2.51.2 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1764931315540019200 Expose the RX/TX MAP capacity field only once a guest has negotiated FF-A v1.2. While there, drop the stale include. To comply with the wider v1.2 register ABI, zero registers x8=E2=80=93x17 w= hen responding to a v1.2 VM. The dispatcher also rejects SMCCC64 calls from AArch32 guests. Finally, bump Xen's FF-A version to 1.2. Signed-off-by: Bertrand Marquis Reviewed-by: Jens Wiklander --- Changes in v1: - Remove advertising of YIELD/INTERRUPT/RUN which has now moved to patch adding FFA_RUN support and adapt commit message - Use ACCESS_ONCE to read guest_vers - Use is_64bit_domain instead of ctx->is_64bit --- xen/arch/arm/tee/ffa.c | 19 +++++++++++++++++-- xen/arch/arm/tee/ffa_private.h | 29 ++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index 2c6443a7f6a4..ed18e76080d0 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -65,7 +65,6 @@ #include #include #include -#include #include =20 #include "ffa_private.h" @@ -296,7 +295,16 @@ static void handle_features(struct cpu_user_regs *regs) * differs from FFA_PAGE_SIZE (SZ_4K). */ BUILD_BUG_ON(PAGE_SIZE !=3D FFA_PAGE_SIZE); - ffa_set_regs_success(regs, 0, 0); + + /* + * From FFA v1.2, we can give the maximum number of pages we suppo= rt + * for the RX/TX buffers. + */ + if ( ACCESS_ONCE(ctx->guest_vers) < FFA_VERSION_1_2 ) + ffa_set_regs_success(regs, 0, 0); + else + ffa_set_regs_success(regs, FFA_MAX_RXTX_PAGE_COUNT << 16, 0); + break; case FFA_FEATURE_NOTIF_PEND_INTR: ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); @@ -329,6 +337,13 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) if ( !ctx ) return false; =20 + if ( !is_64bit_domain(d) && smccc_is_conv_64(fid) ) + { + /* 32bit guests should only use 32bit convention calls */ + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + return true; + } + /* A version must be negotiated first */ if ( !ACCESS_ONCE(ctx->guest_vers) ) { diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index 030e6724743c..1b5aebd6ef6b 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -53,7 +53,7 @@ * that particular guest or SP. */ #define FFA_MY_VERSION_MAJOR 1U -#define FFA_MY_VERSION_MINOR 1U +#define FFA_MY_VERSION_MINOR 2U #define FFA_MY_VERSION MAKE_FFA_VERSION(FFA_MY_VERSION_MAJOR, \ FFA_MY_VERSION_MINOR) =20 @@ -518,14 +518,25 @@ static inline void ffa_set_regs(struct cpu_user_regs = *regs, register_t v0, register_t v4, register_t v5, register_t v= 6, register_t v7) { - set_user_reg(regs, 0, v0); - set_user_reg(regs, 1, v1); - set_user_reg(regs, 2, v2); - set_user_reg(regs, 3, v3); - set_user_reg(regs, 4, v4); - set_user_reg(regs, 5, v5); - set_user_reg(regs, 6, v6); - set_user_reg(regs, 7, v7); + struct domain *d =3D current->domain; + struct ffa_ctx *ctx =3D d->arch.tee; + int i; + + set_user_reg(regs, 0, v0); + set_user_reg(regs, 1, v1); + set_user_reg(regs, 2, v2); + set_user_reg(regs, 3, v3); + set_user_reg(regs, 4, v4); + set_user_reg(regs, 5, v5); + set_user_reg(regs, 6, v6); + set_user_reg(regs, 7, v7); + + if ( ctx && ACCESS_ONCE(ctx->guest_vers) >=3D FFA_VERSION_1_2 && + is_64bit_domain(d) ) + { + for (i =3D 8; i <=3D 17; i++) + set_user_reg(regs, i, 0); + } } =20 static inline void ffa_set_regs_error(struct cpu_user_regs *regs, --=20 2.51.2