From nobody Mon Feb 9 20:36:24 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 1770140356433443.9691066110943; Tue, 3 Feb 2026 09:39:16 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1219540.1528428 (Exim 4.92) (envelope-from ) id 1vnKMU-0001H8-3D; Tue, 03 Feb 2026 17:38:50 +0000 Received: by outflank-mailman (output) from mailman id 1219540.1528428; Tue, 03 Feb 2026 17:38:50 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vnKMT-0001Fc-US; Tue, 03 Feb 2026 17:38:49 +0000 Received: by outflank-mailman (input) for mailman id 1219540; Tue, 03 Feb 2026 17:38:49 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vnKMT-0000Zt-4y for xen-devel@lists.xenproject.org; Tue, 03 Feb 2026 17:38:49 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-flk1.inumbo.com (Halon) with ESMTP id 315067dd-0127-11f1-9ccf-f158ae23cfc8; Tue, 03 Feb 2026 18:38:47 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 000A0150C; Tue, 3 Feb 2026 09:38:39 -0800 (PST) Received: from C3HXLD123V.arm.com (unknown [10.57.54.220]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5699A3F632; Tue, 3 Feb 2026 09:38:45 -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: 315067dd-0127-11f1-9ccf-f158ae23cfc8 From: Bertrand Marquis To: xen-devel@lists.xenproject.org Cc: Volodymyr Babchuk , Jens Wiklander , Stefano Stabellini , Julien Grall , Michal Orzel Subject: [PATCH 04/12] xen/arm: ffa: Add FF-A 1.2 endpoint memory access descriptors Date: Tue, 3 Feb 2026 18:37:59 +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: 1770140359187154100 Content-Type: text/plain; charset="utf-8" FF-A 1.2 extends the endpoint memory access descriptor (EMAD) from 16 to 32 bytes, adding implementation-defined (IMPDEF) fields and reserved space. The MEM_SHARE path currently assumes the 1.1 EMAD size and rejects the 1.2 layout. Add FF-A 1.2 EMAD support to MEM_SHARE: - define ffa_mem_access_1_2 and store IMPDEF payload in ffa_shm_mem - emit 1.2 EMADs to the SPMC for FF-A 1.2 guests, forwarding IMPDEF - refactor header parsing into read_mem_transaction() for 1.0/1.1+ - detect EMAD format by mem_access_size to allow 1.1 on 1.2 guests Functional impact: MEM_SHARE supports FF-A 1.2 EMADs. Signed-off-by: Bertrand Marquis --- xen/arch/arm/tee/ffa_shm.c | 108 +++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 22 deletions(-) diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index 4c0b45cde6ee..905a64e3db01 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -30,6 +30,14 @@ struct ffa_mem_access { uint64_t reserved; }; =20 +/* Endpoint memory access descriptor (FF-A 1.2) */ +struct ffa_mem_access_1_2 { + struct ffa_mem_access_perm access_perm; + uint32_t region_offs; + uint8_t impdef[16]; + uint8_t reserved[8]; +}; + /* Lend, donate or share memory transaction descriptor */ struct ffa_mem_transaction_1_0 { uint16_t sender_id; @@ -73,7 +81,7 @@ struct ffa_mem_transaction_1_1 { /* * The parts needed from struct ffa_mem_transaction_1_0 or struct * ffa_mem_transaction_1_1, used to provide an abstraction of difference in - * data structures between version 1.0 and 1.1. This is just an internal + * data structures between version 1.0 and 1.2. This is just an internal * interface and can be changed without changing any ABI. */ struct ffa_mem_transaction_int { @@ -92,6 +100,8 @@ struct ffa_shm_mem { uint16_t sender_id; uint16_t ep_id; /* endpoint, the one lending */ uint64_t handle; /* FFA_HANDLE_INVALID if not set yet */ + /* Endpoint memory access descriptor IMPDEF value (FF-A 1.2). */ + uint64_t impdef[2]; unsigned int page_count; struct page_info *pages[]; }; @@ -297,17 +307,21 @@ static void init_range(struct ffa_address_range *addr= _range, * This function uses the ffa_spmc tx buffer to transmit the memory transa= ction * descriptor. */ -static int share_shm(struct ffa_shm_mem *shm) +static int share_shm(struct ffa_shm_mem *shm, uint32_t ffa_vers) { const uint32_t max_frag_len =3D FFA_RXTX_PAGE_COUNT * FFA_PAGE_SIZE; struct ffa_mem_access *mem_access_array; + struct ffa_mem_access_1_2 *mem_access_array_1_2; struct ffa_mem_transaction_1_1 *descr; struct ffa_address_range *addr_range; struct ffa_mem_region *region_descr; - const unsigned int region_count =3D 1; uint32_t frag_len; uint32_t tot_len; + uint32_t mem_access_size; + uint32_t mem_access_offs; + uint32_t region_offs; paddr_t last_pa; + uint32_t range_count; unsigned int n; paddr_t pa; int32_t ret; @@ -326,16 +340,35 @@ static int share_shm(struct ffa_shm_mem *shm) descr->handle =3D shm->handle; descr->mem_reg_attr =3D FFA_NORMAL_MEM_REG_ATTR; descr->mem_access_count =3D 1; - descr->mem_access_size =3D sizeof(*mem_access_array); - descr->mem_access_offs =3D MEM_ACCESS_OFFSET(0); + if ( ffa_vers >=3D FFA_VERSION_1_2 ) + mem_access_size =3D sizeof(struct ffa_mem_access_1_2); + else + mem_access_size =3D sizeof(struct ffa_mem_access); + mem_access_offs =3D sizeof(struct ffa_mem_transaction_1_1); + region_offs =3D mem_access_offs + mem_access_size; + descr->mem_access_size =3D mem_access_size; + descr->mem_access_offs =3D mem_access_offs; =20 - mem_access_array =3D buf + descr->mem_access_offs; - memset(mem_access_array, 0, sizeof(*mem_access_array)); - mem_access_array[0].access_perm.endpoint_id =3D shm->ep_id; - mem_access_array[0].access_perm.perm =3D FFA_MEM_ACC_RW; - mem_access_array[0].region_offs =3D REGION_OFFSET(descr->mem_access_co= unt, 0); + if ( ffa_vers >=3D FFA_VERSION_1_2 ) + { + mem_access_array_1_2 =3D buf + mem_access_offs; + memset(mem_access_array_1_2, 0, sizeof(*mem_access_array_1_2)); + mem_access_array_1_2[0].access_perm.endpoint_id =3D shm->ep_id; + mem_access_array_1_2[0].access_perm.perm =3D FFA_MEM_ACC_RW; + mem_access_array_1_2[0].region_offs =3D region_offs; + memcpy(mem_access_array_1_2[0].impdef, shm->impdef, + sizeof(mem_access_array_1_2[0].impdef)); + } + else + { + mem_access_array =3D buf + mem_access_offs; + memset(mem_access_array, 0, sizeof(*mem_access_array)); + mem_access_array[0].access_perm.endpoint_id =3D shm->ep_id; + mem_access_array[0].access_perm.perm =3D FFA_MEM_ACC_RW; + mem_access_array[0].region_offs =3D region_offs; + } =20 - region_descr =3D buf + mem_access_array[0].region_offs; + region_descr =3D buf + region_offs; memset(region_descr, 0, sizeof(*region_descr)); region_descr->total_page_count =3D shm->page_count; =20 @@ -349,8 +382,9 @@ static int share_shm(struct ffa_shm_mem *shm) region_descr->address_range_count++; } =20 - tot_len =3D ADDR_RANGE_OFFSET(descr->mem_access_count, region_count, - region_descr->address_range_count); + range_count =3D region_descr->address_range_count; + tot_len =3D region_offs + sizeof(*region_descr) + + range_count * sizeof(struct ffa_address_range); if ( tot_len > max_frag_len ) { ret =3D FFA_RET_NOT_SUPPORTED; @@ -358,7 +392,7 @@ static int share_shm(struct ffa_shm_mem *shm) } =20 addr_range =3D region_descr->address_range_array; - frag_len =3D ADDR_RANGE_OFFSET(descr->mem_access_count, region_count, = 1); + frag_len =3D region_offs + sizeof(*region_descr) + sizeof(*addr_range); last_pa =3D page_to_maddr(shm->pages[0]); init_range(addr_range, last_pa); for ( n =3D 1; n < shm->page_count; last_pa =3D pa, n++ ) @@ -448,6 +482,12 @@ static int read_mem_transaction(uint32_t ffa_vers, con= st void *buf, size_t blen, if ( size * count + offs > blen ) return FFA_RET_INVALID_PARAMETERS; =20 + if ( size < sizeof(struct ffa_mem_access) ) + return FFA_RET_INVALID_PARAMETERS; + + if ( offs & 0xF ) + return FFA_RET_INVALID_PARAMETERS; + trans->mem_reg_attr =3D mem_reg_attr; trans->flags =3D flags; trans->mem_access_size =3D size; @@ -464,7 +504,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) uint64_t addr =3D get_user_reg(regs, 3); uint32_t page_count =3D get_user_reg(regs, 4); const struct ffa_mem_region *region_descr; - const struct ffa_mem_access *mem_access; + const struct ffa_mem_access_1_2 *mem_access; struct ffa_mem_transaction_int trans; struct domain *d =3D current->domain; struct ffa_ctx *ctx =3D d->arch.tee; @@ -474,9 +514,12 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) register_t handle_hi =3D 0; register_t handle_lo =3D 0; int ret =3D FFA_RET_DENIED; + uint32_t ffa_vers; uint32_t range_count; uint32_t region_offs; uint16_t dst_id; + uint8_t perm; + uint64_t impdef[2]; =20 if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) ) { @@ -515,8 +558,8 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) if ( frag_len > tx_size ) goto out_unlock; =20 - ret =3D read_mem_transaction(ACCESS_ONCE(ctx->guest_vers), tx_buf, - frag_len, &trans); + ffa_vers =3D ACCESS_ONCE(ctx->guest_vers); + ret =3D read_mem_transaction(ffa_vers, tx_buf, frag_len, &trans); if ( ret ) goto out_unlock; =20 @@ -545,13 +588,35 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; } =20 + if ( trans.mem_access_size < sizeof(struct ffa_mem_access) ) + { + ret =3D FFA_RET_INVALID_PARAMETERS; + goto out_unlock; + } + /* Check that it fits in the supplied data */ if ( trans.mem_access_offs + trans.mem_access_size > frag_len ) goto out_unlock; =20 mem_access =3D tx_buf + trans.mem_access_offs; - dst_id =3D ACCESS_ONCE(mem_access->access_perm.endpoint_id); + perm =3D ACCESS_ONCE(mem_access->access_perm.perm); + region_offs =3D ACCESS_ONCE(mem_access->region_offs); + + /* + * FF-A 1.2 introduced an extended mem_access descriptor with impdef + * fields, but guests can still use the 1.1 format if they don't need + * implementation-defined data. Detect which format is used based on + * the mem_access_size field rather than the negotiated FF-A version. + */ + if ( trans.mem_access_size >=3D sizeof(struct ffa_mem_access_1_2) ) + memcpy(impdef, mem_access->impdef, sizeof(impdef)); + else + { + impdef[0] =3D 0; + impdef[1] =3D 0; + } + if ( !FFA_ID_IS_SECURE(dst_id) ) { /* we do not support sharing with VMs */ @@ -559,13 +624,11 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; } =20 - if ( ACCESS_ONCE(mem_access->access_perm.perm) !=3D FFA_MEM_ACC_RW ) + if ( perm !=3D FFA_MEM_ACC_RW ) { ret =3D FFA_RET_NOT_SUPPORTED; goto out_unlock; } - - region_offs =3D ACCESS_ONCE(mem_access->region_offs); if ( sizeof(*region_descr) + region_offs > frag_len ) { ret =3D FFA_RET_NOT_SUPPORTED; @@ -590,6 +653,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) } shm->sender_id =3D trans.sender_id; shm->ep_id =3D dst_id; + memcpy(shm->impdef, impdef, sizeof(shm->impdef)); =20 /* * Check that the Composite memory region descriptor fits. @@ -605,7 +669,7 @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) if ( ret ) goto out; =20 - ret =3D share_shm(shm); + ret =3D share_shm(shm, ffa_vers); if ( ret ) goto out; =20 --=20 2.50.1 (Apple Git-155)