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

Re: [PATCH v2 6/6] xen/arm: ffa: Deliver VM-to-VM notifications locally


  • To: Jens Wiklander <jens.wiklander@xxxxxxxxxx>
  • From: Bertrand Marquis <Bertrand.Marquis@xxxxxxx>
  • Date: Mon, 11 May 2026 13:16:11 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 4.158.2.129) smtp.rcpttodomain=linaro.org smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=arm.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com])
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Kme/demMMAAaZm77U98WvERpvK8HXjHbB+VmpkFcDO8=; b=xC4OIJUj1OVm3cAGbJs10AnUTVMR+4RhSU9nhav/tg5uJmY+R7n/llF0BFoGd78okNJPcvGnproo7jnL4xHkeaIuPRNAV5IGrDdZPb50b5iz1iBHRXgvN2xqJfZMnvlrw9JShZZXABVVuYAkPzddK49Qjz79E/Iea07YKIchwoXukuBzcsHMEtgmQPz4f+6wRClGPRKbQGZ/kM3L6BBmOzwJ5/CACjWJVbfC01vr879USMsqRsZgiVyoXKBvMBsTh+HQrS/fTkffGTODl0dPUsGobYyqbXAC3HG/Pt06YfQVYTcWQ+0fc5heFLLImYDoX/CYsJPeRdvAVFam4/L1fA==
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Kme/demMMAAaZm77U98WvERpvK8HXjHbB+VmpkFcDO8=; b=IrWJRbZIqkZIVH980FK0G/wxuBzKfz4bL6CsW2/dBn6gnrbhqHMB2XQKFbXtov/s2M/POP8+jcVwMLf0kUVRmNLcLVBV0DjxbR8dLF1hSCQtORMGTiz4mFRwswI9fRDwOvikA3GBnLkqbi7AnP4phKq30b8c6rrfmPofyXOoxCI+7E65hhLCiflWi77Hv4L5dkXVfBwZbh+wOKgJMzNtyEtnLN4QSkf7HleQtAHMJnSgXDBWDDY+MXCCxGVuYFE0+aFZohvRummqGLkzuZnZFoFkM970iaGLDUgA8m3I9s73fRI7ZVAWLbGEcdGCwrGaquXMMwoRc+LmfDz24x8r5A==
  • Arc-seal: i=2; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=pass; b=V10aPhv4UutPAXwpqe5hWTY4nsTmsPzRjnJb3GwgaboXm5q4H/ZfmLoUEqRejnd3HZ4YMiUOU4vi+8m2OwLMrknhJ6jkNe81QY9KFWT0KJ5/LX33+071LmCkdzFgk7kMsG7oje58TM+T4bXNZzFGLwhAWoW/LaPzFdBsyaD4teywur3F1j/XwAxsL9bq7QzQZU/BolhsWS/KQQJsFL9PVbsX5oDnWiaR3G4guWuV0kKZhlB5p5ewWcaC/TmO4Uwzk691UeL52FhGr4TCexDk9cQy6SI8huQtxZNmxj7dzI9LkF2gvDHJCaFskf6wmzhmi00CYANlsW2Gl4XcMfRGkQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=uIW7FWZnxO/vA+5rojw0DCku0oOhuN6a84V8H6f0hBI4pXJLAaKLRBeowEh/PMU0l6/rzN2RHba5OmBzxn3xViqiSwnvjkSIj4tQ703qG3ZLuJo7xP/PDkpkkU4vdOjjfw1oBhSY3Vlvh72YZqExHB+VDRiBFV4Unwv4UGURlS3fuQ2sZkWGITJVRe+IoFHkxDRLl7UAv2+ejvNcpDcjXdkGaFYSuHWA6YivAIyuWYW+BGgpzAKHd91HkAZj8jy4Q0mgMHyif1z/tTotUVx0c+nYaVtSei02BN+9cpzWhVXXB71G+F8+bhXYVVCz8eXJ3fE0r/tbjxauJ0A/yTx+og==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"; dkim=pass header.s=selector1 header.d=arm.com header.i="@arm.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>
  • Delivery-date: Mon, 11 May 2026 13:17:36 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Thread-index: AQHc15tBfAqUtgqv9kG77vlVw6CxULX/MgaAgAmvYgA=
  • Thread-topic: [PATCH v2 6/6] xen/arm: ffa: Deliver VM-to-VM notifications locally

Hi Jens,

> On 5 May 2026, at 11:21, Jens Wiklander <jens.wiklander@xxxxxxxxxx> wrote:
> 
> Hi Bertrand,
> 
> On Wed, Apr 29, 2026 at 7:44 AM Bertrand Marquis
> <bertrand.marquis@xxxxxxx> wrote:
>> 
>> VM notification binding and pending tracking exist for non-secure
>> endpoints, but FFA_NOTIFICATION_SET still only forwards secure
>> destinations to the SPMC. Non-secure VMs therefore cannot receive
>> notifications from other VMs. Local NPI delivery also needs explicit
>> re-arm tracking so repeated raises are not lost while the interrupt is
>> already pending.
>> 
>> Add a local VM notification delivery path for non-secure destinations.
>> notification_set_vm() resolves the destination endpoint, verifies that
>> every requested bit is bound to the sender, sets the receiver's
>> vm_pending bitmap under notif_lock, and raises an NPI only when local
>> pending state is not already armed.
>> 
>> Track whether a local NPI is already armed with notif_irq_raised,
>> clear that state once both VM and hypervisor pending bitmaps are
>> drained, and keep notif_lock held across the VM notification injection
>> attempt. If no destination vCPU is online, leave the pending bits set
>> and keep notif_irq_raised clear so delivery can be retried later.
>> Also expose firmware notification availability so FFA_FEATURES only
>> advertises notification support when it is actually provided by the
>> firmware or by CONFIG_FFA_VM_TO_VM.
>> 
>> Functional impact: when CONFIG_FFA_VM_TO_VM is enabled, non-secure
>> FFA_NOTIFICATION_SET delivers VM-to-VM notifications locally and keeps
>> NPI delivery reliable across repeated raises.
>> 
>> Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx>
>> ---
>> Changes since v1:
>> - serialize notification_set_vm() state updates with the NPI attempt
>> - keep pending VM notifications set when local injection fails
>> ---
>> xen/arch/arm/tee/ffa.c         | 24 ++++++++--
>> xen/arch/arm/tee/ffa_notif.c   | 82 ++++++++++++++++++++++++++++++++--
>> xen/arch/arm/tee/ffa_private.h | 17 ++++---
>> 3 files changed, 107 insertions(+), 16 deletions(-)
>> 
>> diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c
>> index 1fe33f26454a..7fe021049cba 100644
>> --- a/xen/arch/arm/tee/ffa.c
>> +++ b/xen/arch/arm/tee/ffa.c
>> @@ -39,8 +39,13 @@
>>  * o FFA_MSG_SEND_DIRECT_REQ:
>>  *   - only supported from a VM to an SP
>>  * o FFA_NOTIFICATION_*:
>> + *   - only supported when firmware notifications are enabled or VM-to-VM
>> + *     support is built in
>>  *   - only supports global notifications, that is, per vCPU notifications
>> - *     are not supported
>> + *     are not supported and secure per-vCPU notification information is
>> + *     not forwarded
>> + *   - the source endpoint ID reported for a notification may no longer
>> + *     exist by the time the receiver consumes it
>>  *   - doesn't support signalling the secondary scheduler of pending
>>  *     notification for secure partitions
>>  *   - doesn't support notifications for Xen itself
>> @@ -245,6 +250,8 @@ static void handle_features(struct cpu_user_regs *regs)
>>     uint32_t a1 = get_user_reg(regs, 1);
>>     struct domain *d = current->domain;
>>     struct ffa_ctx *ctx = d->arch.tee;
>> +    bool notif_supported = IS_ENABLED(CONFIG_FFA_VM_TO_VM) ||
>> +                           ffa_notif_fw_enabled();
>> 
>>     /*
>>      * FFA_FEATURES defines w2 as input properties only for specific
>> @@ -343,10 +350,16 @@ static void handle_features(struct cpu_user_regs *regs)
>> 
>>         break;
>>     case FFA_FEATURE_NOTIF_PEND_INTR:
>> -        ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0);
>> +        if ( notif_supported )
>> +            ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0);
>> +        else
>> +            ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
>>         break;
>>     case FFA_FEATURE_SCHEDULE_RECV_INTR:
>> -        ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0);
>> +        if ( notif_supported )
>> +            ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0);
>> +        else
>> +            ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
>>         break;
>>     case FFA_PARTITION_INFO_GET_REGS:
>>         if ( ACCESS_ONCE(ctx->guest_vers) >= FFA_VERSION_1_2 )
>> @@ -361,7 +374,10 @@ static void handle_features(struct cpu_user_regs *regs)
>>     case FFA_NOTIFICATION_SET:
>>     case FFA_NOTIFICATION_INFO_GET_32:
>>     case FFA_NOTIFICATION_INFO_GET_64:
>> -        ffa_set_regs_success(regs, 0, 0);
>> +        if ( notif_supported )
>> +            ffa_set_regs_success(regs, 0, 0);
>> +        else
>> +            ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
>>         break;
>>     default:
>>         ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED);
>> diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
>> index a841c8f8d747..b29d948a7110 100644
>> --- a/xen/arch/arm/tee/ffa_notif.c
>> +++ b/xen/arch/arm/tee/ffa_notif.c
>> @@ -21,6 +21,11 @@ static bool __ro_after_init fw_notif_enabled;
>> static unsigned int __ro_after_init notif_sri_irq;
>> static DEFINE_SPINLOCK(notif_info_lock);
>> 
>> +bool ffa_notif_fw_enabled(void)
>> +{
>> +    return fw_notif_enabled;
>> +}
>> +
>> static bool inject_notif_pending(struct domain *d)
>> {
>>     struct vcpu *v;
>> @@ -107,6 +112,55 @@ out_unlock:
>>     return ret;
>> }
>> 
>> +/*
>> + * Deliver a VM-to-VM notification. ctx->notif.notif_lock protects
>> + * vm_bind/vm_pending so callers must not hold it already.
>> + */
>> +static int32_t notification_set_vm(uint16_t dst_id, uint16_t src_id,
>> +                                   uint32_t flags, uint64_t bitmap)
>> +{
>> +    struct domain *dst_d;
>> +    struct ffa_ctx *dst_ctx;
>> +    unsigned int id;
>> +    int32_t ret;
>> +
>> +    if ( flags )
>> +        return FFA_RET_INVALID_PARAMETERS;
>> +
>> +    ret = ffa_endpoint_domain_lookup(dst_id, &dst_d, &dst_ctx);
>> +    if ( ret )
>> +        return ret;
>> +
>> +    ret = FFA_RET_OK;
>> +
>> +    spin_lock(&dst_ctx->notif.notif_lock);
>> +
>> +    for ( id = 0; id < FFA_NUM_VM_NOTIF; id++ )
>> +    {
>> +        if ( !(bitmap & BIT(id, ULL)) )
>> +            continue;
>> +
>> +        if ( dst_ctx->notif.vm_bind[id] != src_id )
>> +        {
>> +            ret = FFA_RET_DENIED;
>> +            goto out_unlock;
>> +        }
>> +    }
>> +
>> +    dst_ctx->notif.vm_pending |= bitmap;
>> +    if ( !dst_ctx->notif.notif_irq_raised &&
>> +         (dst_ctx->notif.vm_pending || dst_ctx->notif.hyp_pending) &&
>> +         inject_notif_pending(dst_d) )
>> +        dst_ctx->notif.notif_irq_raised = true;
>> +
>> +out_unlock:
>> +    spin_unlock(&dst_ctx->notif.notif_lock);
>> +
>> +    rcu_unlock_domain(dst_d);
>> +
>> +    return ret;
>> +}
>> +
>> int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs)
>> {
>>     struct domain *d = current->domain;
>> @@ -288,6 +342,8 @@ void ffa_handle_notification_get(struct cpu_user_regs 
>> *regs)
>> 
>>     if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
>>     {
>> +        bool pending;
>> +
>>         spin_lock(&ctx->notif.notif_lock);
>> 
>>         if ( (flags & FFA_NOTIF_FLAG_BITMAP_HYP) && ctx->notif.hyp_pending )
>> @@ -298,6 +354,18 @@ void ffa_handle_notification_get(struct cpu_user_regs 
>> *regs)
>>                 ctx->notif.notif_irq_raised = false;
>>         }
>> 
>> +        if ( (flags & FFA_NOTIF_FLAG_BITMAP_VM) && ctx->notif.vm_pending )
>> +        {
>> +            w4 = (uint32_t)(ctx->notif.vm_pending & GENMASK(31, 0));
>> +            w5 = (uint32_t)((ctx->notif.vm_pending >> 32) & GENMASK(31, 0));
>> +            ctx->notif.vm_pending = 0;
>> +        }
>> +
>> +        pending = (ctx->notif.hyp_pending != 0) ||
>> +                  (ctx->notif.vm_pending != 0);
>> +        if ( !pending )
>> +            ctx->notif.notif_irq_raised = false;
> 
> This seems to take care of clearing notif_irq_raised for all cases. Do
> we still need the one just above this block (copied here):
>            if ( !ctx->notif.vm_pending )
>                ctx->notif.notif_irq_raised = false;
> ?

Yes you are right, this is now redundant.
I will drop it in v3.

Cheers
Bertrand

> 
> Cheers,
> Jens
> 
>> +
>>         spin_unlock(&ctx->notif.notif_lock);
>>     }
>> 
>> @@ -323,9 +391,17 @@ int32_t ffa_handle_notification_set(struct 
>> cpu_user_regs *regs)
>>     if ( flags )
>>         return FFA_RET_INVALID_PARAMETERS;
>> 
>> -    if ( FFA_ID_IS_SECURE(dest_id) && fw_notif_enabled )
>> -        return ffa_simple_call(FFA_NOTIFICATION_SET, src_dst, flags, 
>> bitmap_lo,
>> -                               bitmap_hi);
>> +    if ( FFA_ID_IS_SECURE(dest_id) )
>> +    {
>> +        if ( fw_notif_enabled )
>> +            return ffa_simple_call(FFA_NOTIFICATION_SET, src_dst, flags,
>> +                                   bitmap_lo, bitmap_hi);
>> +    }
>> +    else if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
>> +    {
>> +        return notification_set_vm(dest_id, caller_id, flags,
>> +                                   ((uint64_t)bitmap_hi << 32) | bitmap_lo);
>> +    }
>> 
>>     return FFA_RET_NOT_SUPPORTED;
>> }
>> diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
>> index 78a0a9815d56..923a071a9d7c 100644
>> --- a/xen/arch/arm/tee/ffa_private.h
>> +++ b/xen/arch/arm/tee/ffa_private.h
>> @@ -340,20 +340,18 @@ struct ffa_ctx_notif {
>>     uint64_t vm_pending;
>> 
>>     /*
>> -     * Source endpoint bound to each VM notification ID (0 means unbound).
>> +     * Tracks whether an NPI has been raised for local pending 
>> notifications.
>> +     * Protected by notif_lock.
>>      */
>> -    uint16_t vm_bind[FFA_NUM_VM_NOTIF];
>> +    bool notif_irq_raised;
>> 
>>     /*
>> -     * Lock protecting the hypervisor-managed notification state.
>> +     * Source endpoint bound to each VM notification ID (0 means unbound).
>>      */
>> -    spinlock_t notif_lock;
>> +    uint16_t vm_bind[FFA_NUM_VM_NOTIF];
>> 
>> -    /*
>> -     * Tracks whether a local notification pending interrupt was raised.
>> -     * Protected by notif_lock.
>> -     */
>> -    bool notif_irq_raised;
>> +    /* Lock protecting local notification state. */
>> +    spinlock_t notif_lock;
>> 
>>     /*
>>      * Bitmap of pending hypervisor notifications (for HYP bitmap queries).
>> @@ -495,6 +493,7 @@ void ffa_notif_init(void);
>> void ffa_notif_init_interrupt(void);
>> int ffa_notif_domain_init(struct domain *d);
>> void ffa_notif_domain_destroy(struct domain *d);
>> +bool ffa_notif_fw_enabled(void);
>> 
>> int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs);
>> int32_t ffa_handle_notification_unbind(struct cpu_user_regs *regs);
>> --
>> 2.53.0
>> 


 


Rackspace

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