]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: vgic-v4: Restore pending state on host userspace write
authorMarc Zyngier <maz@kernel.org>
Sun, 17 Dec 2023 11:15:09 +0000 (11:15 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Jan 2024 22:52:49 +0000 (14:52 -0800)
commit 7b95382f965133ef61ce44aaabc518c16eb46909 upstream.

When the VMM writes to ISPENDR0 to set the state pending state of
an SGI, we fail to convey this to the HW if this SGI is already
backed by a GICv4.1 vSGI.

This is a bit of a corner case, as this would only occur if the
vgic state is changed on an already running VM, but this can
apparently happen across a guest reset driven by the VMM.

Fix this by always writing out the pending_latch value to the
HW, and reseting it to false.

Reported-by: Kunkun Jiang <jiangkunkun@huawei.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
Cc: stable@vger.kernel.org # 5.10+
Link: https://lore.kernel.org/r/7e7f2c0c-448b-10a9-8929-4b8f4f6e2a32@huawei.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/kvm/vgic/vgic-mmio-v3.c

index b94a6d1de35dffdd01a050fa68bd769d74fc9389..fd1fa2561520ea3be2d68fe7fb7c1a145e042bda 100644 (file)
@@ -363,19 +363,26 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
 
                raw_spin_lock_irqsave(&irq->irq_lock, flags);
-               if (test_bit(i, &val)) {
-                       /*
-                        * pending_latch is set irrespective of irq type
-                        * (level or edge) to avoid dependency that VM should
-                        * restore irq config before pending info.
-                        */
-                       irq->pending_latch = true;
-                       vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
-               } else {
+
+               /*
+                * pending_latch is set irrespective of irq type
+                * (level or edge) to avoid dependency that VM should
+                * restore irq config before pending info.
+                */
+               irq->pending_latch = test_bit(i, &val);
+
+               if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
+                       irq_set_irqchip_state(irq->host_irq,
+                                             IRQCHIP_STATE_PENDING,
+                                             irq->pending_latch);
                        irq->pending_latch = false;
-                       raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
                }
 
+               if (irq->pending_latch)
+                       vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
+               else
+                       raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
+
                vgic_put_irq(vcpu->kvm, irq);
        }