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

[Xen-changelog] [xen master] arm: vgic: fix race between evtchn upcall and evtchnop_send



commit db453468d92369e7182663fb13e14d83ec4ce456
Author:     Ian Campbell <ian.campbell@xxxxxxxxxx>
AuthorDate: Wed Mar 6 08:54:34 2013 +0000
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Thu Apr 11 09:31:52 2013 +0100

    arm: vgic: fix race between evtchn upcall and evtchnop_send
    
    On ARM the evtchn upcall is done by using a local PPI interrupt. However the
    guest will clear the evtchn_upcall_pending bit before it EOIs that PPI 
(which
    happens late). This means vgic_vcpu_inject_irq (called via
    vcpu_mark_events_pending) sees the PPI as in flight and ends up not 
reinjecting
    it, if this happens after the guest has finished its event channel 
processing
    loop but before the EOI then we have lost the upcall.
    
    To fix this we need to check if an evtchn upcall is pending when returning 
to
    the guest and if so reinject the PPI.
    
    We therefore also need to call gic_restore_pending_irqs on the exit to guest
    path in order to pickup any newly inject IRQ and propagate it into a free 
LR.
    This doesn't currently support bumping a lower priority interrupt out of the
    LRs in order to inject a new higher priority interrupt. We don't yet 
implement
    interrupt prioritisation (and guests don't use it either) so this will do 
for
    now.
    
    Since gic_restore_pending_irqs is now called in the return to guest path it 
is
    called with interrupts disabled and accordingly must use the
    irqsave/irqrestore spinlock primitives.
    
    Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
    Acked-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
---
 xen/arch/arm/gic.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 5a380ca..4124b1d 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -513,17 +513,18 @@ static void gic_restore_pending_irqs(struct vcpu *v)
 {
     int i;
     struct pending_irq *p, *t;
+    unsigned long flags;
 
     list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
     {
         i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
         if ( i >= nr_lrs ) return;
 
-        spin_lock_irq(&gic.lock);
+        spin_lock_irqsave(&gic.lock, flags);
         gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
         list_del_init(&p->lr_queue);
         set_bit(i, &this_cpu(lr_mask));
-        spin_unlock_irq(&gic.lock);
+        spin_unlock_irqrestore(&gic.lock, flags);
     }
 
 }
@@ -546,6 +547,10 @@ static void gic_inject_irq_stop(void)
 
 void gic_inject(void)
 {
+    if ( vcpu_info(current, evtchn_upcall_pending) )
+        vgic_vcpu_inject_irq(current, VGIC_IRQ_EVTCHN_CALLBACK, 1);
+
+    gic_restore_pending_irqs(current);
     if (!this_cpu(lr_mask))
         gic_inject_irq_stop();
     else
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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