Advertise RUN/YIELD/INTERRUPT via FFA_FEATURES now that the runtime
helpers are in place, and expose the RX/TX MAP capacity field only once
a guest has negotiated FF-A v1.2.
While there, drop the stale <asm/tee/ffa.h> include.
To comply with the wider v1.2 register ABI, zero registers x8–x17 when
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 <bertrand.marquis@arm.com>
---
xen/arch/arm/tee/ffa.c | 25 ++++++++++++++++++++-----
xen/arch/arm/tee/ffa_private.h | 28 +++++++++++++++++++---------
2 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 8b2f042287fc..c8fe97856d06 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_*:
@@ -68,7 +65,6 @@
#include <asm/event.h>
#include <asm/regs.h>
#include <asm/smccc.h>
-#include <asm/tee/ffa.h>
#include <asm/tee/tee.h>
#include "ffa_private.h"
@@ -262,6 +258,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_MSG_SEND_DIRECT_REQ2:
@@ -290,7 +289,16 @@ static void handle_features(struct cpu_user_regs *regs)
* differs from FFA_PAGE_SIZE (SZ_4K).
*/
BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE);
- ffa_set_regs_success(regs, 0, 0);
+
+ /*
+ * From FFA v1.2, we can give the maximum number of pages we support
+ * for the RX/TX buffers.
+ */
+ if ( 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);
@@ -323,6 +331,13 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
if ( !ctx )
return false;
+ 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 ( !ctx->guest_vers_negotiated )
{
diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
index a9a03c7c5d71..6afca2ea07ef 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)
@@ -505,14 +505,24 @@ static inline void ffa_set_regs(struct cpu_user_regs *regs, register_t v0,
register_t v4, register_t v5, register_t v6,
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 = current->domain;
+ struct ffa_ctx *ctx = 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 && ctx->guest_vers >= FFA_VERSION_1_2 && ctx->is_64bit )
+ {
+ for (i = 8; i <= 17; i++)
+ set_user_reg(regs, i, 0);
+ }
}
static inline void ffa_set_regs_error(struct cpu_user_regs *regs,
--
2.51.2
Hi Bertrand,
On Thu, Nov 27, 2025 at 4:53 PM Bertrand Marquis
<bertrand.marquis@arm.com> wrote:
>
> Advertise RUN/YIELD/INTERRUPT via FFA_FEATURES now that the runtime
> helpers are in place, and expose the RX/TX MAP capacity field only once
> a guest has negotiated FF-A v1.2.
>
> While there, drop the stale <asm/tee/ffa.h> include.
>
> To comply with the wider v1.2 register ABI, zero registers x8–x17 when
> 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 <bertrand.marquis@arm.com>
> ---
> xen/arch/arm/tee/ffa.c | 25 ++++++++++++++++++++-----
> xen/arch/arm/tee/ffa_private.h | 28 +++++++++++++++++++---------
> 2 files changed, 39 insertions(+), 14 deletions(-)
>
> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
> index 8b2f042287fc..c8fe97856d06 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_*:
> @@ -68,7 +65,6 @@
> #include <asm/event.h>
> #include <asm/regs.h>
> #include <asm/smccc.h>
> -#include <asm/tee/ffa.h>
> #include <asm/tee/tee.h>
>
> #include "ffa_private.h"
> @@ -262,6 +258,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_MSG_SEND_DIRECT_REQ2:
> @@ -290,7 +289,16 @@ static void handle_features(struct cpu_user_regs *regs)
> * differs from FFA_PAGE_SIZE (SZ_4K).
> */
> BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE);
> - ffa_set_regs_success(regs, 0, 0);
> +
> + /*
> + * From FFA v1.2, we can give the maximum number of pages we support
> + * for the RX/TX buffers.
> + */
> + if ( 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);
> @@ -323,6 +331,13 @@ static bool ffa_handle_call(struct cpu_user_regs *regs)
> if ( !ctx )
> return false;
>
> + if ( !is_64bit_domain(d) && smccc_is_conv_64(fid) )
You use ctx->is_64bit in ffa_set_regs() below, but here
is_64bit_domain(d). Which one do we prefer?
Cheers,
Jens
> + {
> + /* 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 ( !ctx->guest_vers_negotiated )
> {
> diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
> index a9a03c7c5d71..6afca2ea07ef 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)
>
> @@ -505,14 +505,24 @@ static inline void ffa_set_regs(struct cpu_user_regs *regs, register_t v0,
> register_t v4, register_t v5, register_t v6,
> 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 = current->domain;
> + struct ffa_ctx *ctx = 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 && ctx->guest_vers >= FFA_VERSION_1_2 && ctx->is_64bit )
> + {
> + for (i = 8; i <= 17; i++)
> + set_user_reg(regs, i, 0);
> + }
> }
>
> static inline void ffa_set_regs_error(struct cpu_user_regs *regs,
> --
> 2.51.2
>
Hi Jens, > On 4 Dec 2025, at 08:59, Jens Wiklander <jens.wiklander@linaro.org> wrote: > > Hi Bertrand, > > On Thu, Nov 27, 2025 at 4:53 PM Bertrand Marquis > <bertrand.marquis@arm.com> wrote: >> >> Advertise RUN/YIELD/INTERRUPT via FFA_FEATURES now that the runtime >> helpers are in place, and expose the RX/TX MAP capacity field only once >> a guest has negotiated FF-A v1.2. >> >> While there, drop the stale <asm/tee/ffa.h> include. >> >> To comply with the wider v1.2 register ABI, zero registers x8–x17 when >> 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 <bertrand.marquis@arm.com> >> --- >> xen/arch/arm/tee/ffa.c | 25 ++++++++++++++++++++----- >> xen/arch/arm/tee/ffa_private.h | 28 +++++++++++++++++++--------- >> 2 files changed, 39 insertions(+), 14 deletions(-) >> >> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c >> index 8b2f042287fc..c8fe97856d06 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_*: >> @@ -68,7 +65,6 @@ >> #include <asm/event.h> >> #include <asm/regs.h> >> #include <asm/smccc.h> >> -#include <asm/tee/ffa.h> >> #include <asm/tee/tee.h> >> >> #include "ffa_private.h" >> @@ -262,6 +258,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_MSG_SEND_DIRECT_REQ2: >> @@ -290,7 +289,16 @@ static void handle_features(struct cpu_user_regs *regs) >> * differs from FFA_PAGE_SIZE (SZ_4K). >> */ >> BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE); >> - ffa_set_regs_success(regs, 0, 0); >> + >> + /* >> + * From FFA v1.2, we can give the maximum number of pages we support >> + * for the RX/TX buffers. >> + */ >> + if ( 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); >> @@ -323,6 +331,13 @@ static bool ffa_handle_call(struct cpu_user_regs *regs) >> if ( !ctx ) >> return false; >> >> + if ( !is_64bit_domain(d) && smccc_is_conv_64(fid) ) > > You use ctx->is_64bit in ffa_set_regs() below, but here > is_64bit_domain(d). Which one do we prefer? It would definitely be more coherent to use ctx->is_64bit. I will fix that in next version. Cheers Bertrand
© 2016 - 2025 Red Hat, Inc.