Skip to content

Commit f233646

Browse files
committed
Merge tag 'kvm-x86-apic-6.7' of https://github.com/kvm-x86/linux into HEAD
KVM x86 APIC changes for 6.7: - Purge VMX's posted interrupt descriptor *before* loading APIC state when handling KVM_SET_LAPIC. Purging the PID after loading APIC state results in lost APIC timer IRQs as the APIC timer can be armed as part of loading APIC state, i.e. can immediately pend an IRQ if the expiry is in the past. - Clear the ICR.BUSY bit when handling trap-like x2APIC writes. This avoids a WARN, due to KVM expecting the BUSY bit to be cleared when sending IPIs.
2 parents 140139c + 629d369 commit f233646

File tree

4 files changed

+21
-15
lines changed

4 files changed

+21
-15
lines changed

arch/x86/include/asm/kvm-x86-ops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ KVM_X86_OP_OPTIONAL(vcpu_blocking)
108108
KVM_X86_OP_OPTIONAL(vcpu_unblocking)
109109
KVM_X86_OP_OPTIONAL(pi_update_irte)
110110
KVM_X86_OP_OPTIONAL(pi_start_assignment)
111+
KVM_X86_OP_OPTIONAL(apicv_pre_state_restore)
111112
KVM_X86_OP_OPTIONAL(apicv_post_state_restore)
112113
KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrupt)
113114
KVM_X86_OP_OPTIONAL(set_hv_timer)

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,7 @@ struct kvm_x86_ops {
17081708
int (*pi_update_irte)(struct kvm *kvm, unsigned int host_irq,
17091709
uint32_t guest_irq, bool set);
17101710
void (*pi_start_assignment)(struct kvm *kvm);
1711+
void (*apicv_pre_state_restore)(struct kvm_vcpu *vcpu);
17111712
void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);
17121713
bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *vcpu);
17131714

arch/x86/kvm/lapic.c

Lines changed: 17 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

@@ -2670,6 +2670,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
26702670
u64 msr_val;
26712671
int i;
26722672

2673+
static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu);
2674+
26732675
if (!init_event) {
26742676
msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE;
26752677
if (kvm_vcpu_is_reset_bsp(vcpu))
@@ -2981,6 +2983,8 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
29812983
struct kvm_lapic *apic = vcpu->arch.apic;
29822984
int r;
29832985

2986+
static_call_cond(kvm_x86_apicv_pre_state_restore)(vcpu);
2987+
29842988
kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
29852989
/* set SPIV separately to get count of SW disabled APICs right */
29862990
apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));

arch/x86/kvm/vmx/vmx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6912,7 +6912,7 @@ static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
69126912
vmcs_write64(EOI_EXIT_BITMAP3, eoi_exit_bitmap[3]);
69136913
}
69146914

6915-
static void vmx_apicv_post_state_restore(struct kvm_vcpu *vcpu)
6915+
static void vmx_apicv_pre_state_restore(struct kvm_vcpu *vcpu)
69166916
{
69176917
struct vcpu_vmx *vmx = to_vmx(vcpu);
69186918

@@ -8286,7 +8286,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
82868286
.set_apic_access_page_addr = vmx_set_apic_access_page_addr,
82878287
.refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
82888288
.load_eoi_exitmap = vmx_load_eoi_exitmap,
8289-
.apicv_post_state_restore = vmx_apicv_post_state_restore,
8289+
.apicv_pre_state_restore = vmx_apicv_pre_state_restore,
82908290
.required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS,
82918291
.hwapic_irr_update = vmx_hwapic_irr_update,
82928292
.hwapic_isr_update = vmx_hwapic_isr_update,

0 commit comments

Comments
 (0)