From nobody Sat Feb 7 09:12:18 2026 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 1765824059828855.8306010245235; Mon, 15 Dec 2025 10:40:59 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187129.1508554 (Exim 4.92) (envelope-from ) id 1vV9ti-0003RC-0C; Mon, 15 Dec 2025 14:50:02 +0000 Received: by outflank-mailman (output) from mailman id 1187129.1508554; Mon, 15 Dec 2025 14:50:01 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9th-0003QU-RZ; Mon, 15 Dec 2025 14:50:01 +0000 Received: by outflank-mailman (input) for mailman id 1187129; Mon, 15 Dec 2025 14:50:00 +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 1vV9tg-00038W-Sl for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:00 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 53d1d595-d9c5-11f0-9cce-f158ae23cfc8; Mon, 15 Dec 2025 15:49:58 +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 05410497; Mon, 15 Dec 2025 06:49:51 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 27E293F694; Mon, 15 Dec 2025 06:49:57 -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: 53d1d595-d9c5-11f0-9cce-f158ae23cfc8 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 01/12] xen/arm: ffa: add FF-A v1.2 function IDs Date: Mon, 15 Dec 2025 15:49:18 +0100 Message-ID: <7718cc9bbd5ba3be37e15cf5e605ac9af7d3b6e8.1765807707.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: 1765824061329154100 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 v2: - Add Jens R-b 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 Sat Feb 7 09:12:18 2026 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 1765824048326426.31726420492043; Mon, 15 Dec 2025 10:40:48 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187130.1508564 (Exim 4.92) (envelope-from ) id 1vV9tj-0003qL-5y; Mon, 15 Dec 2025 14:50:03 +0000 Received: by outflank-mailman (output) from mailman id 1187130.1508564; Mon, 15 Dec 2025 14:50:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tj-0003pr-2e; Mon, 15 Dec 2025 14:50:03 +0000 Received: by outflank-mailman (input) for mailman id 1187130; Mon, 15 Dec 2025 14:50:01 +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 1vV9th-0003Ov-Na for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:01 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 54a551e0-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:00 +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 68A98FEC; Mon, 15 Dec 2025 06:49:52 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7767D3F694; Mon, 15 Dec 2025 06:49:58 -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: 54a551e0-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 02/12] xen/arm: ffa: per-VM FFA_VERSION negotiation state Date: Mon, 15 Dec 2025 15:49:19 +0100 Message-ID: <359051357e82739378c2ebfb5461d27951d42e7b.1765807707.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: 1765824049258158500 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 Reviewed-by: Jens Wiklander --- Changes in v2: - add comment on top of guest_vers to instruct to always use ACCESS_ONCE to access it. 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 | 27 +++++++-- xen/arch/arm/tee/ffa_shm.c | 3 +- 5 files changed, 106 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..8ef214344711 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,27 @@ 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. + * Must always be accessed using ACCESS_ONCE(). + */ + 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 Sat Feb 7 09:12:18 2026 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 1765824102222315.77935173205015; Mon, 15 Dec 2025 10:41:42 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187131.1508569 (Exim 4.92) (envelope-from ) id 1vV9tj-0003tm-GC; Mon, 15 Dec 2025 14:50:03 +0000 Received: by outflank-mailman (output) from mailman id 1187131.1508569; Mon, 15 Dec 2025 14:50:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tj-0003tE-A4; Mon, 15 Dec 2025 14:50:03 +0000 Received: by outflank-mailman (input) for mailman id 1187131; Mon, 15 Dec 2025 14:50:02 +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 1vV9th-0003Ov-Uo for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:01 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 555d1f67-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:01 +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 B94041655; Mon, 15 Dec 2025 06:49:53 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D7B503F694; Mon, 15 Dec 2025 06:49:59 -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: 555d1f67-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 03/12] xen/arm: ffa: Fix is_64bit init Date: Mon, 15 Dec 2025 15:49:20 +0100 Message-ID: <983cdb4effeaa0d72ff02f3a7b561f1570646ea0.1765807707.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: 1765824104111154100 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 Reviewed-by: Jens Wiklander --- Changes in v2: - add Jens R-b 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 8ef214344711..96794ecebe4b 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 Sat Feb 7 09:12:18 2026 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 1765824065622318.3687292961929; Mon, 15 Dec 2025 10:41:05 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187132.1508583 (Exim 4.92) (envelope-from ) id 1vV9tm-0004sH-Vf; Mon, 15 Dec 2025 14:50:06 +0000 Received: by outflank-mailman (output) from mailman id 1187132.1508583; Mon, 15 Dec 2025 14:50:06 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tm-0004rp-QV; Mon, 15 Dec 2025 14:50:06 +0000 Received: by outflank-mailman (input) for mailman id 1187132; Mon, 15 Dec 2025 14:50:05 +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 1vV9tl-00038W-1G for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:05 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 564167ba-d9c5-11f0-9cce-f158ae23cfc8; Mon, 15 Dec 2025 15:50:03 +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 2711F497; Mon, 15 Dec 2025 06:49:55 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 33BD23F694; Mon, 15 Dec 2025 06:50:01 -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: 564167ba-d9c5-11f0-9cce-f158ae23cfc8 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 04/12] xen/arm: ffa: harden RX/TX mapping Date: Mon, 15 Dec 2025 15:49:21 +0100 Message-ID: <5c8d22e3c3db0a62aa14f000fe4867614bc78456.1765807707.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: 1765824067289158500 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 v2: - add Jens R-b 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 96794ecebe4b..0bb5a84553ce 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -439,10 +439,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 Sat Feb 7 09:12:18 2026 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 1765824073668894.9402108786948; Mon, 15 Dec 2025 10:41:13 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187133.1508589 (Exim 4.92) (envelope-from ) id 1vV9tn-0004vP-7L; Mon, 15 Dec 2025 14:50:07 +0000 Received: by outflank-mailman (output) from mailman id 1187133.1508589; Mon, 15 Dec 2025 14:50:07 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tn-0004uJ-1i; Mon, 15 Dec 2025 14:50:07 +0000 Received: by outflank-mailman (input) for mailman id 1187133; Mon, 15 Dec 2025 14:50:05 +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 1vV9tl-0003Ov-0B for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:05 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 5709fbfe-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:04 +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 843C2FEC; Mon, 15 Dec 2025 06:49:56 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 963F53F694; Mon, 15 Dec 2025 06:50:02 -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: 5709fbfe-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 05/12] xen/arm: ffa: rework SPMC RX/TX buffer management Date: Mon, 15 Dec 2025 15:49:22 +0100 Message-ID: <9810a2728cfd8541d6aa680c7af7728324e6a1dd.1765807707.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: 1765824075666154100 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 Reviewed-by: Jens Wiklander --- Changes in v2: - remove invalid ASSERT in SPMC RX/TX acquire as it is expected that the buffer are already taken and the spinlock is here to serialize. 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 | 126 +++++++++++++++++++++++++------- xen/arch/arm/tee/ffa_shm.c | 29 +++++--- 5 files changed, 149 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 0bb5a84553ce..4c97041829a9 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -416,10 +416,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; @@ -437,8 +433,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, @@ -568,11 +569,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..63203b22b84c 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,108 @@ void ffa_rxtx_domain_destroy(struct domain *d) rxtx_unmap(d); } =20 -void ffa_rxtx_destroy(void) +void *ffa_rxtx_spmc_rx_acquire(void) +{ + 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; + spin_lock(&ffa_spmc_tx_lock); =20 - if ( ffa_tx ) + 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); =20 - ffa_tx =3D alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUN= T), 0); - if ( !ffa_tx ) - goto err; + ffa_spmc_rx =3D alloc_xenheap_pages( + get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); + if ( !ffa_spmc_rx ) + goto exit; =20 - e =3D ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT); + ffa_spmc_tx =3D alloc_xenheap_pages( + get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); + if ( !ffa_spmc_tx ) + goto exit; + + e =3D ffa_rxtx_map(__pa(ffa_spmc_tx), __pa(ffa_spmc_rx), + FFA_RXTX_PAGE_COUNT); if ( e ) - goto err; + goto exit; + + ret =3D true; =20 - return true; +exit: + spin_unlock(&ffa_spmc_tx_lock); + spin_unlock(&ffa_spmc_rx_lock); =20 -err: - ffa_rxtx_destroy(); + if ( !ret ) + ffa_rxtx_spmc_destroy(); =20 - return false; + 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 Sat Feb 7 09:12:18 2026 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 1765824057225872.1780471313828; Mon, 15 Dec 2025 10:40:57 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187135.1508595 (Exim 4.92) (envelope-from ) id 1vV9tn-00054r-S7; Mon, 15 Dec 2025 14:50:07 +0000 Received: by outflank-mailman (output) from mailman id 1187135.1508595; Mon, 15 Dec 2025 14:50:07 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tn-000539-HD; Mon, 15 Dec 2025 14:50:07 +0000 Received: by outflank-mailman (input) for mailman id 1187135; Mon, 15 Dec 2025 14:50:06 +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 1vV9tm-0003Ov-Az for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:06 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 57da5539-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:05 +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 DB1E9497; Mon, 15 Dec 2025 06:49:57 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 000E93F694; Mon, 15 Dec 2025 06:50:03 -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: 57da5539-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 06/12] xen/arm: ffa: rework VM RX/TX buffer management Date: Mon, 15 Dec 2025 15:49:23 +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: 1765824059424154100 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 v2: - add Jens R-b 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 4c97041829a9..904ad1df733b 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -445,8 +445,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 63203b22b84c..7d8bb4f4d031 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 Sat Feb 7 09:12:18 2026 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 1765824121767472.6130823393453; Mon, 15 Dec 2025 10:42:01 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187137.1508613 (Exim 4.92) (envelope-from ) id 1vV9tq-0005qy-07; Mon, 15 Dec 2025 14:50:10 +0000 Received: by outflank-mailman (output) from mailman id 1187137.1508613; Mon, 15 Dec 2025 14:50:09 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tp-0005qb-SE; Mon, 15 Dec 2025 14:50:09 +0000 Received: by outflank-mailman (input) for mailman id 1187137; Mon, 15 Dec 2025 14:50:07 +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 1vV9tn-0003Ov-KL for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:07 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 58ac9a9d-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:07 +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 4B70C1655; Mon, 15 Dec 2025 06:49:59 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5BB703F694; Mon, 15 Dec 2025 06:50:05 -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: 58ac9a9d-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 07/12] xen/arm: ffa: use signed 32-bit status codes Date: Mon, 15 Dec 2025 15:49:24 +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: 1765824123736158500 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 v2: - no changes 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 904ad1df733b..c274177029de 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)) @@ -426,10 +426,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 @@ -455,11 +455,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); @@ -525,9 +525,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, @@ -542,7 +543,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 Sat Feb 7 09:12:18 2026 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 1765824062377381.34655789154033; Mon, 15 Dec 2025 10:41:02 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187138.1508620 (Exim 4.92) (envelope-from ) id 1vV9tq-0005uw-Lk; Mon, 15 Dec 2025 14:50:10 +0000 Received: by outflank-mailman (output) from mailman id 1187138.1508620; Mon, 15 Dec 2025 14:50:10 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tq-0005tz-7Y; Mon, 15 Dec 2025 14:50:10 +0000 Received: by outflank-mailman (input) for mailman id 1187138; Mon, 15 Dec 2025 14:50:09 +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 1vV9tp-0003Ov-3d for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:09 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 598bf526-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:08 +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 B004A497; Mon, 15 Dec 2025 06:50:00 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BD48A3F694; Mon, 15 Dec 2025 06:50:06 -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: 598bf526-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 08/12] xen/arm: ffa: add UUID helpers for partition info Date: Mon, 15 Dec 2025 15:49:25 +0100 Message-ID: <671ef6011b32690bf5d5f9b4826e593ae5114378.1765807707.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: 1765824065506154100 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 v2: - add Jens R-b 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 c274177029de..fb5212bd2820 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 @@ -581,4 +585,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 Sat Feb 7 09:12:18 2026 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 1765824191719745.4429743026027; Mon, 15 Dec 2025 10:43:11 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187144.1508643 (Exim 4.92) (envelope-from ) id 1vV9tv-0006rS-5q; Mon, 15 Dec 2025 14:50:15 +0000 Received: by outflank-mailman (output) from mailman id 1187144.1508643; Mon, 15 Dec 2025 14:50:15 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tv-0006r1-2F; Mon, 15 Dec 2025 14:50:15 +0000 Received: by outflank-mailman (input) for mailman id 1187144; Mon, 15 Dec 2025 14:50:13 +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 1vV9tt-00038W-EG for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:13 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 5a6ca86e-d9c5-11f0-9cce-f158ae23cfc8; Mon, 15 Dec 2025 15:50:10 +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 1B5EFFEC; Mon, 15 Dec 2025 06:50:02 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 2F4BD3F694; Mon, 15 Dec 2025 06:50:08 -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: 5a6ca86e-d9c5-11f0-9cce-f158ae23cfc8 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 09/12] xen/arm: ffa: Add FFA_RUN support Date: Mon, 15 Dec 2025 15:49:26 +0100 Message-ID: <74e819101a77d27da29eed023cd71505e55bd9a4.1765807707.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: 1765824193549154100 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 v2: - add Jens R-b 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 fb5212bd2820..1fbd3fc3a696 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -475,6 +475,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 Sat Feb 7 09:12:18 2026 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 1765824163340702.0666308022111; Mon, 15 Dec 2025 10:42:43 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187141.1508634 (Exim 4.92) (envelope-from ) id 1vV9tt-0006Zu-Ql; Mon, 15 Dec 2025 14:50:13 +0000 Received: by outflank-mailman (output) from mailman id 1187141.1508634; Mon, 15 Dec 2025 14:50:13 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tt-0006Zd-Mj; Mon, 15 Dec 2025 14:50:13 +0000 Received: by outflank-mailman (input) for mailman id 1187141; Mon, 15 Dec 2025 14:50:12 +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 1vV9tr-0003Ov-VB for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:11 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 5b33f6d5-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:11 +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 72A61165C; Mon, 15 Dec 2025 06:50:03 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 8A8883F694; Mon, 15 Dec 2025 06:50:09 -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: 5b33f6d5-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 10/12] xen/arm: ffa: add v1.2 SEND2 header layout Date: Mon, 15 Dec 2025 15:49:27 +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: 1765824165166154100 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 v2: - add Jens R-b 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 Sat Feb 7 09:12:18 2026 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 176582415789128.06009155811182; Mon, 15 Dec 2025 10:42:37 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187242.1508665 (Exim 4.92) (envelope-from ) id 1vVA1v-0002En-JO; Mon, 15 Dec 2025 14:58:31 +0000 Received: by outflank-mailman (output) from mailman id 1187242.1508665; Mon, 15 Dec 2025 14:58:31 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vVA1v-0002Eg-Cv; Mon, 15 Dec 2025 14:58:31 +0000 Received: by outflank-mailman (input) for mailman id 1187242; Mon, 15 Dec 2025 14:58:30 +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 1vV9tt-0003Ov-9Q for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:13 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id 5bff03ce-d9c5-11f0-b15b-2bf370ae4941; Mon, 15 Dec 2025 15:50:12 +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 C8A6D1684; Mon, 15 Dec 2025 06:50:04 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DFF4B3F694; Mon, 15 Dec 2025 06:50:10 -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: 5bff03ce-d9c5-11f0-b15b-2bf370ae4941 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 11/12] xen/arm: ffa: add MSG_SEND_DIRECT_REQ2 support Date: Mon, 15 Dec 2025 15:49:28 +0100 Message-ID: <41e25208492954f7e74cb8aaae0eed7b53af8b64.1765807707.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: 1765824159704158500 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 v2: - add Jens R-b 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 Sat Feb 7 09:12:18 2026 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 176581545336366.22760462180315; Mon, 15 Dec 2025 08:17:33 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1187149.1508655 (Exim 4.92) (envelope-from ) id 1vV9tx-0007Nj-PH; Mon, 15 Dec 2025 14:50:17 +0000 Received: by outflank-mailman (output) from mailman id 1187149.1508655; Mon, 15 Dec 2025 14:50:17 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vV9tx-0007NA-F5; Mon, 15 Dec 2025 14:50:17 +0000 Received: by outflank-mailman (input) for mailman id 1187149; Mon, 15 Dec 2025 14:50:16 +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 1vV9tw-00038W-EW for xen-devel@lists.xenproject.org; Mon, 15 Dec 2025 14:50:16 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 5cd05a89-d9c5-11f0-9cce-f158ae23cfc8; Mon, 15 Dec 2025 15:50:14 +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 2D31D497; Mon, 15 Dec 2025 06:50:06 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.46.206]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 47E563F694; Mon, 15 Dec 2025 06:50:12 -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: 5cd05a89-d9c5-11f0-9cce-f158ae23cfc8 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: jens.wiklander@linaro.org, Volodymyr Babchuk , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH v2 12/12] xen/arm: ffa: advertise FF-A v1.2 Date: Mon, 15 Dec 2025 15:49:29 +0100 Message-ID: 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: 1765815456375158500 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 v2: - add Jens R-b 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 1fbd3fc3a696..282c105f3bce 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 @@ -519,14 +519,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