aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2009-06-15 09:21:25 -0400
committerAvi Kivity <avi@redhat.com>2009-09-10 01:32:59 -0400
commit219b65dcf6c0bad83d51bfa12e25891c02de2414 (patch)
tree1117880afaa755b936949701400401b01f09c5fb
parentff092385e8285c03d8b148f42f46f98c5f4becd5 (diff)
KVM: SVM: Improve nested interrupt injection
While trying to get Hyper-V running, I realized that the interrupt injection mechanisms that are in place right now are not 100% correct. This patch makes nested SVM's interrupt injection behave more like on a real machine. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/svm.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index be699795d70f..456666183770 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1612,7 +1612,8 @@ static int nested_svm_vmexit_real(struct vcpu_svm *svm, void *arg1,
1612 /* Kill any pending exceptions */ 1612 /* Kill any pending exceptions */
1613 if (svm->vcpu.arch.exception.pending == true) 1613 if (svm->vcpu.arch.exception.pending == true)
1614 nsvm_printk("WARNING: Pending Exception\n"); 1614 nsvm_printk("WARNING: Pending Exception\n");
1615 svm->vcpu.arch.exception.pending = false; 1615 kvm_clear_exception_queue(&svm->vcpu);
1616 kvm_clear_interrupt_queue(&svm->vcpu);
1616 1617
1617 /* Restore selected save entries */ 1618 /* Restore selected save entries */
1618 svm->vmcb->save.es = hsave->save.es; 1619 svm->vmcb->save.es = hsave->save.es;
@@ -1680,7 +1681,8 @@ static int nested_svm_vmrun(struct vcpu_svm *svm, void *arg1,
1680 svm->nested_vmcb = svm->vmcb->save.rax; 1681 svm->nested_vmcb = svm->vmcb->save.rax;
1681 1682
1682 /* Clear internal status */ 1683 /* Clear internal status */
1683 svm->vcpu.arch.exception.pending = false; 1684 kvm_clear_exception_queue(&svm->vcpu);
1685 kvm_clear_interrupt_queue(&svm->vcpu);
1684 1686
1685 /* Save the old vmcb, so we don't need to pick what we save, but 1687 /* Save the old vmcb, so we don't need to pick what we save, but
1686 can restore everything when a VMEXIT occurs */ 1688 can restore everything when a VMEXIT occurs */
@@ -2362,21 +2364,14 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
2362 ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); 2364 ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
2363} 2365}
2364 2366
2365static void svm_queue_irq(struct kvm_vcpu *vcpu, unsigned nr)
2366{
2367 struct vcpu_svm *svm = to_svm(vcpu);
2368
2369 svm->vmcb->control.event_inj = nr |
2370 SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
2371}
2372
2373static void svm_set_irq(struct kvm_vcpu *vcpu) 2367static void svm_set_irq(struct kvm_vcpu *vcpu)
2374{ 2368{
2375 struct vcpu_svm *svm = to_svm(vcpu); 2369 struct vcpu_svm *svm = to_svm(vcpu);
2376 2370
2377 nested_svm_intr(svm); 2371 BUG_ON(!(svm->vcpu.arch.hflags & HF_GIF_MASK));
2378 2372
2379 svm_queue_irq(vcpu, vcpu->arch.interrupt.nr); 2373 svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr |
2374 SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
2380} 2375}
2381 2376
2382static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) 2377static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
@@ -2404,13 +2399,25 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
2404 struct vmcb *vmcb = svm->vmcb; 2399 struct vmcb *vmcb = svm->vmcb;
2405 return (vmcb->save.rflags & X86_EFLAGS_IF) && 2400 return (vmcb->save.rflags & X86_EFLAGS_IF) &&
2406 !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) && 2401 !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
2407 (svm->vcpu.arch.hflags & HF_GIF_MASK); 2402 (svm->vcpu.arch.hflags & HF_GIF_MASK) &&
2403 !is_nested(svm);
2408} 2404}
2409 2405
2410static void enable_irq_window(struct kvm_vcpu *vcpu) 2406static void enable_irq_window(struct kvm_vcpu *vcpu)
2411{ 2407{
2412 svm_set_vintr(to_svm(vcpu)); 2408 struct vcpu_svm *svm = to_svm(vcpu);
2413 svm_inject_irq(to_svm(vcpu), 0x0); 2409 nsvm_printk("Trying to open IRQ window\n");
2410
2411 nested_svm_intr(svm);
2412
2413 /* In case GIF=0 we can't rely on the CPU to tell us when
2414 * GIF becomes 1, because that's a separate STGI/VMRUN intercept.
2415 * The next time we get that intercept, this function will be
2416 * called again though and we'll get the vintr intercept. */
2417 if (svm->vcpu.arch.hflags & HF_GIF_MASK) {
2418 svm_set_vintr(svm);
2419 svm_inject_irq(svm, 0x0);
2420 }
2414} 2421}
2415 2422
2416static void enable_nmi_window(struct kvm_vcpu *vcpu) 2423static void enable_nmi_window(struct kvm_vcpu *vcpu)
@@ -2489,6 +2496,8 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
2489 case SVM_EXITINTINFO_TYPE_EXEPT: 2496 case SVM_EXITINTINFO_TYPE_EXEPT:
2490 /* In case of software exception do not reinject an exception 2497 /* In case of software exception do not reinject an exception
2491 vector, but re-execute and instruction instead */ 2498 vector, but re-execute and instruction instead */
2499 if (is_nested(svm))
2500 break;
2492 if (kvm_exception_is_soft(vector)) 2501 if (kvm_exception_is_soft(vector))
2493 break; 2502 break;
2494 if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { 2503 if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {