diff options
| author | Marc Zyngier <maz@kernel.org> | 2025-11-20 17:25:19 +0000 |
|---|---|---|
| committer | Oliver Upton <oupton@kernel.org> | 2025-11-24 14:29:13 -0800 |
| commit | 295b69216558367e5e833eb6d92ab2b476a8ad64 (patch) | |
| tree | c6958e5568206fa745ed30eccd9be8e6070e6c5b | |
| parent | cd4f6ee99b28f10692c2444c8dc0bab77357a25e (diff) | |
KVM: arm64: GICv3: Add GICv2 SGI handling to deactivation primitive
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>
| -rw-r--r-- | arch/arm64/kvm/vgic/vgic-v3.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index d83edf02d072..9fcee5121fe5 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -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; } |
