diff mbox series

[03/10] xen/arm: ffa: fix version negotiation

Message ID 716e806316f8249611c8268f781efbea19273b4a.1726676338.git.bertrand.marquis@arm.com (mailing list archive)
State New
Headers show
Series xen/arm: ffa: Improvements and fixes | expand

Commit Message

Bertrand Marquis Sept. 19, 2024, 12:19 p.m. UTC
Fix FFA version negotiation with the firmware to follow the
specification guidance more closely.
When the firmware returns OK we can have several cases:
- the version requested is accepted but the firmware supports a greater
  one in the same major.
- the firmware supports a greater major version. It could still return
  OK even if the version requested is not accepted. Reject it.
- the firmware supports a lower version. It will return OK and give that
  version. Check if we support it and use it or reject it if we do not.

Adapt the code to:
- reject any version lower than the one we support or not with the same
  major version
- use the version returned if in our supported range (currently 1.1
  only)
- use 1.1 if the version returned is greater.

Also adapt the handling of version requests from VM:
- return an error for a different major
- return 1.1 for a version >= 1.1
- return 1.0 if 1.0 was requested

Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com>
---
 xen/arch/arm/tee/ffa.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
index 7ff2529b2055..1f602f25d097 100644
--- a/xen/arch/arm/tee/ffa.c
+++ b/xen/arch/arm/tee/ffa.c
@@ -141,13 +141,24 @@  static void handle_version(struct cpu_user_regs *regs)
     struct ffa_ctx *ctx = d->arch.tee;
     uint32_t vers = get_user_reg(regs, 1);
 
-    if ( vers < FFA_VERSION_1_1 )
-        vers = FFA_VERSION_1_0;
-    else
-        vers = FFA_VERSION_1_1;
+    /**
+     * As of now we only support 1.0 or 1.1.
+     * For any 1.x >= 1.1 return OK with 1.1
+     * For 1.0 return OK with 1.0
+     * For anything else return an error.
+     */
+    if ( (vers >> FFA_VERSION_MAJOR_SHIFT) == FFA_MY_VERSION_MAJOR )
+    {
+        if ( vers < FFA_VERSION_1_1 )
+            vers = FFA_VERSION_1_0;
+        else
+            vers = FFA_VERSION_1_1;
 
-    ctx->guest_vers = vers;
-    ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
+        ctx->guest_vers = vers;
+        ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0);
+    }
+    else
+        ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
 }
 
 static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid)
@@ -530,7 +541,8 @@  static bool ffa_probe(void)
         goto err_no_fw;
     }
 
-    if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION )
+    if ( vers < FFA_MIN_SPMC_VERSION ||
+              (vers >> FFA_VERSION_MAJOR_SHIFT) != FFA_MY_VERSION_MAJOR )
     {
         printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers);
         goto err_no_fw;
@@ -542,7 +554,17 @@  static bool ffa_probe(void)
     printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n",
            major_vers, minor_vers);
 
-    ffa_fw_version = vers;
+    /**
+     * If the call succeed and the version returned is higher or equal to
+     * the one Xen requested, the version requested by Xen will be the one
+     * used. If the version returned is lower but compatible with Xen, Xen
+     * will use that version instead.
+     * A version with a different major is rejected before.
+     */
+    if ( vers > FFA_MY_VERSION )
+        ffa_fw_version = FFA_MY_VERSION;
+    else
+        ffa_fw_version = vers;
 
     for ( int i = 0; i < ARRAY_SIZE(ffa_fw_feat_needed); i++ )
     {