Skip to content

Commit 629d369

Browse files
taosu-linuxsean-jc
authored andcommitted
KVM: x86: Clear bit12 of ICR after APIC-write VM-exit
When IPI virtualization is enabled, a WARN is triggered if bit12 of ICR MSR is set after APIC-write VM-exit. The reason is kvm_apic_send_ipi() thinks the APIC_ICR_BUSY bit should be cleared because KVM has no delay, but kvm_apic_write_nodecode() doesn't clear the APIC_ICR_BUSY bit. Under the x2APIC section, regarding ICR, the SDM says: It remains readable only to aid in debugging; however, software should not assume the value returned by reading the ICR is the last written value. I.e. the guest is allowed to set bit 12. However, the SDM also gives KVM free reign to do whatever it wants with the bit, so long as KVM's behavior doesn't confuse userspace or break KVM's ABI. Clear bit 12 so that it reads back as '0'. This approach is safer than "do nothing" and is consistent with the case where IPI virtualization is disabled or not supported, i.e., handle_fastpath_set_x2apic_icr_irqoff() -> kvm_x2apic_icr_write() Opportunistically replace the TODO with a comment calling out that eating the write is likely faster than a conditional branch around the busy bit. Link: https://lore.kernel.org/all/[email protected]/ Fixes: 5413bcb ("KVM: x86: Add support for vICR APIC-write VM-Exits in x2APIC mode") Cc: [email protected] Signed-off-by: Tao Su <[email protected]> Tested-by: Yi Lai <[email protected]> Reviewed-by: Chao Gao <[email protected]> Link: https://lore.kernel.org/r/[email protected] [sean: tweak changelog, replace TODO with comment, drop local "val"] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 9cfec6d commit 629d369

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

arch/x86/kvm/lapic.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,22 +2444,22 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
24442444
void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
24452445
{
24462446
struct kvm_lapic *apic = vcpu->arch.apic;
2447-
u64 val;
24482447

24492448
/*
2450-
* ICR is a single 64-bit register when x2APIC is enabled. For legacy
2451-
* xAPIC, ICR writes need to go down the common (slightly slower) path
2452-
* to get the upper half from ICR2.
2449+
* ICR is a single 64-bit register when x2APIC is enabled, all others
2450+
* registers hold 32-bit values. For legacy xAPIC, ICR writes need to
2451+
* go down the common path to get the upper half from ICR2.
2452+
*
2453+
* Note, using the write helpers may incur an unnecessary write to the
2454+
* virtual APIC state, but KVM needs to conditionally modify the value
2455+
* in certain cases, e.g. to clear the ICR busy bit. The cost of extra
2456+
* conditional branches is likely a wash relative to the cost of the
2457+
* maybe-unecessary write, and both are in the noise anyways.
24532458
*/
2454-
if (apic_x2apic_mode(apic) && offset == APIC_ICR) {
2455-
val = kvm_lapic_get_reg64(apic, APIC_ICR);
2456-
kvm_apic_send_ipi(apic, (u32)val, (u32)(val >> 32));
2457-
trace_kvm_apic_write(APIC_ICR, val);
2458-
} else {
2459-
/* TODO: optimize to just emulate side effect w/o one more write */
2460-
val = kvm_lapic_get_reg(apic, offset);
2461-
kvm_lapic_reg_write(apic, offset, (u32)val);
2462-
}
2459+
if (apic_x2apic_mode(apic) && offset == APIC_ICR)
2460+
kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR));
2461+
else
2462+
kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
24632463
}
24642464
EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode);
24652465

0 commit comments

Comments
 (0)