@@ -439,6 +439,14 @@ int vgic_connect_hw_irq(struct domain *d, struct vcpu *v, unsigned int virq,
/* We are taking to rank lock to prevent parallel connections. */
vgic_lock_rank(v_target, rank, flags);
+ /* Return with error if the IRQ is being migrated. */
+ if( test_bit(GIC_IRQ_GUEST_MIGRATING, &p->status) )
+ {
+ vgic_unlock_rank(v_target, rank, flags);
+ return -EBUSY;
+ }
+
+ spin_lock(&v_target->arch.vgic.lock);
if ( connect )
{
@@ -456,12 +464,25 @@ int vgic_connect_hw_irq(struct domain *d, struct vcpu *v, unsigned int virq,
}
else
{
- if ( desc && p->desc != desc )
- ret = -EINVAL;
+ if ( d->is_dying )
+ {
+ if ( desc && p->desc != desc )
+ ret = -EINVAL;
+ else
+ p->desc = NULL;
+ }
else
- p->desc = NULL;
+ {
+ if ( (desc && p->desc != desc) ||
+ test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ||
+ test_bit(GIC_IRQ_GUEST_ACTIVE, &p->status) )
+ ret = -EINVAL;
+ else
+ p->desc = NULL;
+ }
}
+ spin_unlock(&v_target->arch.vgic.lock);
vgic_unlock_rank(v_target, rank, flags);
return ret;
@@ -159,24 +159,17 @@ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
ASSERT(test_bit(_IRQ_GUEST, &desc->status));
ASSERT(!is_lpi(virq));
- /*
- * Removing an interrupt while the domain is running may have
- * undesirable effect on the vGIC emulation.
- */
- if ( !d->is_dying )
- return -EBUSY;
-
desc->handler->shutdown(desc);
/* EOI the IRQ if it has not been done by the guest */
if ( test_bit(_IRQ_INPROGRESS, &desc->status) )
gic_hw_ops->deactivate_irq(desc);
- clear_bit(_IRQ_INPROGRESS, &desc->status);
ret = vgic_connect_hw_irq(d, NULL, virq, desc, false);
if ( ret )
return ret;
+ clear_bit(_IRQ_INPROGRESS, &desc->status);
clear_bit(_IRQ_GUEST, &desc->status);
desc->handler = &no_irq_type;
@@ -890,14 +890,30 @@ int vgic_connect_hw_irq(struct domain *d, struct vcpu *vcpu,
}
else /* remove a mapped IRQ */
{
- if ( desc && irq->hwintid != desc->irq )
+ if ( d->is_dying )
{
- ret = -EINVAL;
+ if ( desc && irq->hwintid != desc->irq )
+ {
+ ret = -EINVAL;
+ }
+ else
+ {
+ irq->hw = false;
+ irq->hwintid = 0;
+ }
}
else
{
- irq->hw = false;
- irq->hwintid = 0;
+ if ( (desc && irq->hwintid != desc->irq) ||
+ irq->active || irq->pending_latch )
+ {
+ ret = -EINVAL;
+ }
+ else
+ {
+ irq->hw = false;
+ irq->hwintid = 0;
+ }
}
}