]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: GICv3: Add GICv2 SGI handling to deactivation primitive
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Nov 2025 17:25:19 +0000 (17:25 +0000)
committerOliver Upton <oupton@kernel.org>
Mon, 24 Nov 2025 22:29:13 +0000 (14:29 -0800)
The GICv2 SGIs require additional handling for deactivation, as they
are effectively multiple interrrupts muxed into one. Make sure we
check for the source CPU when deactivating.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-30-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
arch/arm64/kvm/vgic/vgic-v3.c

index d83edf02d0722a5cf325f493305ff03a5ddcda8a..9fcee5121fe5e9380cb01a0291b6e4c3376d3c09 100644 (file)
@@ -176,11 +176,20 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
 {
        struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
        struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
+       u32 model = vcpu->kvm->arch.vgic.vgic_model;
        struct kvm_vcpu *target_vcpu = NULL;
+       bool mmio = false, is_v2_sgi;
        struct vgic_irq *irq;
        unsigned long flags;
-       bool mmio = false;
        u64 lr = 0;
+       u8 cpuid;
+
+       /* Snapshot CPUID, and remove it from the INTID */
+       cpuid = FIELD_GET(GENMASK_ULL(12, 10), val);
+       val &= ~GENMASK_ULL(12, 10);
+
+       is_v2_sgi = (model == KVM_DEV_TYPE_ARM_VGIC_V2 &&
+                    val < VGIC_NR_SGIS);
 
        /*
         * We only deal with DIR when EOIMode==1, and only for SGI,
@@ -216,6 +225,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
         * - Or the irq is active, but not in an LR, and we can
         *   directly deactivate it by building a pseudo-LR, fold it,
         *   and queue a request to prune the resulting ap_list,
+        *
+        * Special care must be taken to match the source CPUID when
+        * deactivating a GICv2 SGI.
         */
        scoped_guard(raw_spinlock, &irq->irq_lock) {
                target_vcpu = irq->vcpu;
@@ -233,6 +245,12 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
                        goto put;
                }
 
+               /* GICv2 SGI: check that the cpuid matches */
+               if (is_v2_sgi && irq->active_source != cpuid) {
+                       target_vcpu = NULL;
+                       goto put;
+               }
+
                /* (with a Dalek voice) DEACTIVATE!!!! */
                lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
        }