Skip to content

Commit 514946d

Browse files
Maxim Levitskybonzini
authored andcommitted
KVM: x86: VMX: __kvm_apic_update_irr must update the IRR atomically
If APICv is inhibited, then IPIs from peer vCPUs are done by atomically setting bits in IRR. This means, that when __kvm_apic_update_irr copies PIR to IRR, it has to modify IRR atomically as well. Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Message-Id: <20230726135945.260841-2-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 6eaae19 commit 514946d

1 file changed

Lines changed: 13 additions & 7 deletions

File tree

arch/x86/kvm/lapic.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -637,16 +637,22 @@ bool __kvm_apic_update_irr(u32 *pir, void *regs, int *max_irr)
637637
*max_irr = -1;
638638

639639
for (i = vec = 0; i <= 7; i++, vec += 32) {
640+
u32 *p_irr = (u32 *)(regs + APIC_IRR + i * 0x10);
641+
642+
irr_val = *p_irr;
640643
pir_val = READ_ONCE(pir[i]);
641-
irr_val = *((u32 *)(regs + APIC_IRR + i * 0x10));
644+
642645
if (pir_val) {
646+
pir_val = xchg(&pir[i], 0);
647+
643648
prev_irr_val = irr_val;
644-
irr_val |= xchg(&pir[i], 0);
645-
*((u32 *)(regs + APIC_IRR + i * 0x10)) = irr_val;
646-
if (prev_irr_val != irr_val) {
647-
max_updated_irr =
648-
__fls(irr_val ^ prev_irr_val) + vec;
649-
}
649+
do {
650+
irr_val = prev_irr_val | pir_val;
651+
} while (prev_irr_val != irr_val &&
652+
!try_cmpxchg(p_irr, &prev_irr_val, irr_val));
653+
654+
if (prev_irr_val != irr_val)
655+
max_updated_irr = __fls(irr_val ^ prev_irr_val) + vec;
650656
}
651657
if (irr_val)
652658
*max_irr = __fls(irr_val) + vec;

0 commit comments

Comments
 (0)