[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 5/6] xen/arm: ffa: Track VM notification bindings locally



VM-to-VM notifications need receiver-side bind state so Xen can validate
which sender owns each notification bit. Non-secure BIND and UNBIND
requests currently have no local state and cannot enforce that contract.

Add per-bit VM notification binding state to struct ffa_ctx_notif and
use it to handle non-secure BIND and UNBIND requests when
CONFIG_FFA_VM_TO_VM is enabled. The update helper validates the whole
request under notif_lock before mutating anything, denies bind or
unbind when a bit is pending, rejects rebinding to a different sender,
and keeps rebinding to the same sender idempotent.

Promote vm_pending to a bitmap so the bind logic can reason per
notification ID, use that bitmap directly when reporting pending state,
and initialize and clear the new VM notification state during domain
init and teardown.

Functional impact: when CONFIG_FFA_VM_TO_VM is enabled, Xen tracks VM
notification bindings locally and validates non-secure bind and unbind
requests against that state.

Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx>
---
 xen/arch/arm/tee/ffa_notif.c   | 97 ++++++++++++++++++++++++++++++----
 xen/arch/arm/tee/ffa_private.h | 15 ++++--
 2 files changed, 99 insertions(+), 13 deletions(-)

diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
index fff00ca2baec..4def701f0130 100644
--- a/xen/arch/arm/tee/ffa_notif.c
+++ b/xen/arch/arm/tee/ffa_notif.c
@@ -56,6 +56,54 @@ static int32_t ffa_notif_parse_params(uint16_t dom_id, 
uint16_t caller_id,
     return FFA_RET_OK;
 }
 
+static int32_t ffa_notif_update_vm_binding(struct ffa_ctx *ctx,
+                                           uint16_t dest_id, uint64_t bitmap,
+                                           bool bind)
+{
+    unsigned int id;
+    int32_t ret = FFA_RET_OK;
+
+    spin_lock(&ctx->notif.notif_lock);
+
+    for ( id = 0; id < FFA_NUM_VM_NOTIF; id++ )
+    {
+        if ( !(bitmap & BIT(id, ULL)) )
+            continue;
+
+        if ( ctx->notif.vm_pending & BIT(id, ULL) )
+        {
+            ret = FFA_RET_DENIED;
+            goto out_unlock;
+        }
+
+        if ( bind )
+        {
+            if ( ctx->notif.vm_bind[id] != 0 &&
+                 ctx->notif.vm_bind[id] != dest_id )
+            {
+                ret = FFA_RET_DENIED;
+                goto out_unlock;
+            }
+        }
+        else if ( ctx->notif.vm_bind[id] != dest_id )
+        {
+            ret = FFA_RET_DENIED;
+            goto out_unlock;
+        }
+    }
+
+    for ( id = 0; id < FFA_NUM_VM_NOTIF; id++ )
+    {
+        if ( bitmap & BIT(id, ULL) )
+            ctx->notif.vm_bind[id] = bind ? dest_id : 0;
+    }
+
+out_unlock:
+    spin_unlock(&ctx->notif.notif_lock);
+
+    return ret;
+}
+
 int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs)
 {
     struct domain *d = current->domain;
@@ -76,11 +124,21 @@ int32_t ffa_handle_notification_bind(struct cpu_user_regs 
*regs)
     if ( ret )
         return ret;
 
-    if ( FFA_ID_IS_SECURE(dest_id) && fw_notif_enabled )
-        return ffa_simple_call(FFA_NOTIFICATION_BIND, src_dst, flags,
-                               bitmap_lo, bitmap_hi);
+    if ( FFA_ID_IS_SECURE(dest_id) )
+    {
+        if ( fw_notif_enabled )
+            return ffa_simple_call(FFA_NOTIFICATION_BIND, src_dst, flags,
+                                   bitmap_lo, bitmap_hi);
 
-    return FFA_RET_NOT_SUPPORTED;
+        return FFA_RET_NOT_SUPPORTED;
+    }
+
+    if ( !IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
+        return FFA_RET_NOT_SUPPORTED;
+
+    return ffa_notif_update_vm_binding(ctx, dest_id,
+                                       ((uint64_t)bitmap_hi << 32) | bitmap_lo,
+                                       true);
 }
 
 int32_t ffa_handle_notification_unbind(struct cpu_user_regs *regs)
@@ -99,11 +157,21 @@ int32_t ffa_handle_notification_unbind(struct 
cpu_user_regs *regs)
     if ( ret )
         return ret;
 
-    if ( FFA_ID_IS_SECURE(dest_id) && fw_notif_enabled )
-        return ffa_simple_call(FFA_NOTIFICATION_UNBIND, src_dst, 0, bitmap_lo,
-                               bitmap_hi);
+    if ( FFA_ID_IS_SECURE(dest_id) )
+    {
+        if ( fw_notif_enabled )
+            return ffa_simple_call(FFA_NOTIFICATION_UNBIND, src_dst, 0,
+                                   bitmap_lo, bitmap_hi);
 
-    return FFA_RET_NOT_SUPPORTED;
+        return FFA_RET_NOT_SUPPORTED;
+    }
+
+    if ( !IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
+        return FFA_RET_NOT_SUPPORTED;
+
+    return ffa_notif_update_vm_binding(ctx, dest_id,
+                                       ((uint64_t)bitmap_hi << 32) | bitmap_lo,
+                                       false);
 }
 
 void ffa_handle_notification_info_get(struct cpu_user_regs *regs)
@@ -125,9 +193,10 @@ void ffa_handle_notification_info_get(struct cpu_user_regs 
*regs)
 
     if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
     {
-        notif_pending |= test_and_clear_bool(ctx->notif.vm_pending);
-
         spin_lock(&ctx->notif.notif_lock);
+        if ( ctx->notif.vm_pending )
+            notif_pending = true;
+
         if ( ctx->notif.hyp_pending )
             notif_pending = true;
         spin_unlock(&ctx->notif.notif_lock);
@@ -497,10 +566,14 @@ void ffa_notif_init(void)
 int ffa_notif_domain_init(struct domain *d)
 {
     struct ffa_ctx *ctx = d->arch.tee;
+    unsigned int i;
     int32_t res;
 
     spin_lock_init(&ctx->notif.notif_lock);
     ctx->notif.secure_pending = false;
+    ctx->notif.vm_pending = 0;
+    for ( i = 0; i < FFA_NUM_VM_NOTIF; i++ )
+        ctx->notif.vm_bind[i] = 0;
     ctx->notif.hyp_pending = 0;
 
     if ( fw_notif_enabled )
@@ -516,9 +589,13 @@ int ffa_notif_domain_init(struct domain *d)
 void ffa_notif_domain_destroy(struct domain *d)
 {
     struct ffa_ctx *ctx = d->arch.tee;
+    unsigned int i;
 
     spin_lock(&ctx->notif.notif_lock);
     ctx->notif.secure_pending = false;
+    ctx->notif.vm_pending = 0;
+    for ( i = 0; i < FFA_NUM_VM_NOTIF; i++ )
+        ctx->notif.vm_bind[i] = 0;
     ctx->notif.hyp_pending = 0;
     spin_unlock(&ctx->notif.notif_lock);
 
diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
index 5693772481ed..6d83afb3d00a 100644
--- a/xen/arch/arm/tee/ffa_private.h
+++ b/xen/arch/arm/tee/ffa_private.h
@@ -236,6 +236,11 @@
 #define FFA_NOTIF_INFO_GET_ID_COUNT_MASK    0x1F
 
 #define FFA_NOTIF_RX_BUFFER_FULL        BIT(0, U)
+#define FFA_NUM_VM_NOTIF                64U
+
+#if FFA_NUM_VM_NOTIF > 64
+#error "FFA_NUM_VM_NOTIF must be <= 64"
+#endif
 
 /* Feature IDs used with FFA_FEATURES */
 #define FFA_FEATURE_NOTIF_PEND_INTR     0x1U
@@ -334,10 +339,14 @@ struct ffa_ctx_notif {
     bool secure_pending;
 
     /*
-     * True if domain is reported by FFA_NOTIFICATION_INFO_GET to have
-     * pending notifications from VMs (including framework ones).
+     * Bitmap of pending notifications from VMs (including framework ones).
+     */
+    uint64_t vm_pending;
+
+    /*
+     * Source endpoint bound to each VM notification ID (0 means unbound).
      */
-    bool vm_pending;
+    uint16_t vm_bind[FFA_NUM_VM_NOTIF];
 
     /*
      * Lock protecting the hypervisor-managed notification state.
-- 
2.53.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.