if (!vgic_irq_is_edge(vcpu, irq))
                vlr.state |= LR_EOI_INT;
 
+       if (vlr.irq >= VGIC_NR_SGIS) {
+               struct irq_phys_map *map;
+               map = vgic_irq_map_search(vcpu, irq);
+
+               /*
+                * If we have a mapping, and the virtual interrupt is
+                * being injected, then we must set the state to
+                * active in the physical world. Otherwise the
+                * physical interrupt will fire and the guest will
+                * exit before processing the virtual interrupt.
+                */
+               if (map) {
+                       int ret;
+
+                       BUG_ON(!map->active);
+                       vlr.hwirq = map->phys_irq;
+                       vlr.state |= LR_HW;
+                       vlr.state &= ~LR_EOI_INT;
+
+                       ret = irq_set_irqchip_state(map->irq,
+                                                   IRQCHIP_STATE_ACTIVE,
+                                                   true);
+                       WARN_ON(ret);
+
+                       /*
+                        * Make sure we're not going to sample this
+                        * again, as a HW-backed interrupt cannot be
+                        * in the PENDING_ACTIVE stage.
+                        */
+                       vgic_irq_set_queued(vcpu, irq);
+               }
+       }
+
        vgic_set_lr(vcpu, lr_nr, vlr);
        vgic_sync_lr_elrsr(vcpu, lr_nr, vlr);
 }
        return level_pending;
 }
 
+/*
+ * Save the physical active state, and reset it to inactive.
+ *
+ * Return 1 if HW interrupt went from active to inactive, and 0 otherwise.
+ */
+static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)
+{
+       struct irq_phys_map *map;
+       int ret;
+
+       if (!(vlr.state & LR_HW))
+               return 0;
+
+       map = vgic_irq_map_search(vcpu, vlr.irq);
+       BUG_ON(!map || !map->active);
+
+       ret = irq_get_irqchip_state(map->irq,
+                                   IRQCHIP_STATE_ACTIVE,
+                                   &map->active);
+
+       WARN_ON(ret);
+
+       if (map->active) {
+               ret = irq_set_irqchip_state(map->irq,
+                                           IRQCHIP_STATE_ACTIVE,
+                                           false);
+               WARN_ON(ret);
+               return 0;
+       }
+
+       return 1;
+}
+
 /* Sync back the VGIC state after a guest run */
 static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
        elrsr = vgic_get_elrsr(vcpu);
        elrsr_ptr = u64_to_bitmask(&elrsr);
 
-       /* Clear mappings for empty LRs */
-       for_each_set_bit(lr, elrsr_ptr, vgic->nr_lr) {
+       /* Deal with HW interrupts, and clear mappings for empty LRs */
+       for (lr = 0; lr < vgic->nr_lr; lr++) {
                struct vgic_lr vlr;
 
-               if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
+               if (!test_bit(lr, vgic_cpu->lr_used))
                        continue;
 
                vlr = vgic_get_lr(vcpu, lr);
+               if (vgic_sync_hwirq(vcpu, vlr)) {
+                       /*
+                        * So this is a HW interrupt that the guest
+                        * EOI-ed. Clean the LR state and allow the
+                        * interrupt to be sampled again.
+                        */
+                       vlr.state = 0;
+                       vlr.hwirq = 0;
+                       vgic_set_lr(vcpu, lr, vlr);
+                       vgic_irq_clear_queued(vcpu, vlr.irq);
+                       set_bit(lr, elrsr_ptr);
+               }
+
+               if (!test_bit(lr, elrsr_ptr))
+                       continue;
+
+               clear_bit(lr, vgic_cpu->lr_used);
 
                BUG_ON(vlr.irq >= dist->nr_irqs);
                vgic_cpu->vgic_irq_lr_map[vlr.irq] = LR_EMPTY;