aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorWanpeng Li <wanpeng.li@linux.intel.com>2014-08-05 00:42:24 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-08-05 09:00:24 -0400
commit56cc2406d68c0f09505c389e276f27a99f495cbd (patch)
tree90e2d04ea45d9a22023ca6371dfc878cf4b70c2e /arch
parentf3380ca5d7edb5e31932998ab2e29dfdce39c5ed (diff)
KVM: nVMX: fix "acknowledge interrupt on exit" when APICv is in use
After commit 77b0f5d (KVM: nVMX: Ack and write vector info to intr_info if L1 asks us to), "Acknowledge interrupt on exit" behavior can be emulated. To do so, KVM will ask the APIC for the interrupt vector if during a nested vmexit if VM_EXIT_ACK_INTR_ON_EXIT is set. With APICv, kvm_get_apic_interrupt would return -1 and give the following WARNING: Call Trace: [<ffffffff81493563>] dump_stack+0x49/0x5e [<ffffffff8103f0eb>] warn_slowpath_common+0x7c/0x96 [<ffffffffa059709a>] ? nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [<ffffffff8103f11a>] warn_slowpath_null+0x15/0x17 [<ffffffffa059709a>] nested_vmx_vmexit+0xa4/0x233 [kvm_intel] [<ffffffffa0594295>] ? nested_vmx_exit_handled+0x6a/0x39e [kvm_intel] [<ffffffffa0537931>] ? kvm_apic_has_interrupt+0x80/0xd5 [kvm] [<ffffffffa05972ec>] vmx_check_nested_events+0xc3/0xd3 [kvm_intel] [<ffffffffa051ebe9>] inject_pending_event+0xd0/0x16e [kvm] [<ffffffffa051efa0>] vcpu_enter_guest+0x319/0x704 [kvm] To fix this, we cannot rely on the processor's virtual interrupt delivery, because "acknowledge interrupt on exit" must only update the virtual ISR/PPR/IRR registers (and SVI, which is just a cache of the virtual ISR) but it should not deliver the interrupt through the IDT. Thus, KVM has to deliver the interrupt "by hand", similar to the treatment of EOI in commit fc57ac2c9ca8 (KVM: lapic: sync highest ISR to hardware apic on EOI, 2014-05-14). The patch modifies kvm_cpu_get_interrupt to always acknowledge an interrupt; there are only two callers, and the other is not affected because it is never reached with kvm_apic_vid_enabled() == true. Then it modifies apic_set_isr and apic_clear_irr to update SVI and RVI in addition to the registers. Suggested-by: Paolo Bonzini <pbonzini@redhat.com> Suggested-by: "Zhang, Yang Z" <yang.z.zhang@intel.com> Tested-by: Liu, RongrongX <rongrongx.liu@intel.com> Tested-by: Felipe Reyes <freyes@suse.com> Fixes: 77b0f5d67ff2781f36831cba79674c3e97bd7acf Cc: stable@vger.kernel.org Signed-off-by: Wanpeng Li <wanpeng.li@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/irq.c2
-rw-r--r--arch/x86/kvm/lapic.c52
2 files changed, 40 insertions, 14 deletions
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index bd0da433e6d7..a1ec6a50a05a 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -108,7 +108,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
108 108
109 vector = kvm_cpu_get_extint(v); 109 vector = kvm_cpu_get_extint(v);
110 110
111 if (kvm_apic_vid_enabled(v->kvm) || vector != -1) 111 if (vector != -1)
112 return vector; /* PIC */ 112 return vector; /* PIC */
113 113
114 return kvm_get_apic_interrupt(v); /* APIC */ 114 return kvm_get_apic_interrupt(v); /* APIC */
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 3855103f71fd..08e8a899e005 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -352,25 +352,46 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
352 352
353static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) 353static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
354{ 354{
355 apic->irr_pending = false; 355 struct kvm_vcpu *vcpu;
356
357 vcpu = apic->vcpu;
358
356 apic_clear_vector(vec, apic->regs + APIC_IRR); 359 apic_clear_vector(vec, apic->regs + APIC_IRR);
357 if (apic_search_irr(apic) != -1) 360 if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
358 apic->irr_pending = true; 361 /* try to update RVI */
362 kvm_make_request(KVM_REQ_EVENT, vcpu);
363 else {
364 vec = apic_search_irr(apic);
365 apic->irr_pending = (vec != -1);
366 }
359} 367}
360 368
361static inline void apic_set_isr(int vec, struct kvm_lapic *apic) 369static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
362{ 370{
363 /* Note that we never get here with APIC virtualization enabled. */ 371 struct kvm_vcpu *vcpu;
372
373 if (__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
374 return;
375
376 vcpu = apic->vcpu;
364 377
365 if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
366 ++apic->isr_count;
367 BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
368 /* 378 /*
369 * ISR (in service register) bit is set when injecting an interrupt. 379 * With APIC virtualization enabled, all caching is disabled
370 * The highest vector is injected. Thus the latest bit set matches 380 * because the processor can modify ISR under the hood. Instead
371 * the highest bit in ISR. 381 * just set SVI.
372 */ 382 */
373 apic->highest_isr_cache = vec; 383 if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
384 kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
385 else {
386 ++apic->isr_count;
387 BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
388 /*
389 * ISR (in service register) bit is set when injecting an interrupt.
390 * The highest vector is injected. Thus the latest bit set matches
391 * the highest bit in ISR.
392 */
393 apic->highest_isr_cache = vec;
394 }
374} 395}
375 396
376static inline int apic_find_highest_isr(struct kvm_lapic *apic) 397static inline int apic_find_highest_isr(struct kvm_lapic *apic)
@@ -1627,11 +1648,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
1627 int vector = kvm_apic_has_interrupt(vcpu); 1648 int vector = kvm_apic_has_interrupt(vcpu);
1628 struct kvm_lapic *apic = vcpu->arch.apic; 1649 struct kvm_lapic *apic = vcpu->arch.apic;
1629 1650
1630 /* Note that we never get here with APIC virtualization enabled. */
1631
1632 if (vector == -1) 1651 if (vector == -1)
1633 return -1; 1652 return -1;
1634 1653
1654 /*
1655 * We get here even with APIC virtualization enabled, if doing
1656 * nested virtualization and L1 runs with the "acknowledge interrupt
1657 * on exit" mode. Then we cannot inject the interrupt via RVI,
1658 * because the process would deliver it through the IDT.
1659 */
1660
1635 apic_set_isr(vector, apic); 1661 apic_set_isr(vector, apic);
1636 apic_update_ppr(apic); 1662 apic_update_ppr(apic);
1637 apic_clear_irr(vector, apic); 1663 apic_clear_irr(vector, apic);