diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-03-23 06:12:11 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:33 -0400 |
commit | 78646121e9a2fcf7977cc15966420e572a450bc3 (patch) | |
tree | 55aeac260f4a43bef8e1bc1147f93a3f7e867ec7 | |
parent | 09cec754885f900f6aab23801878c0cd217ee1d6 (diff) |
KVM: Fix interrupt unhalting a vcpu when it shouldn't
kvm_vcpu_block() unhalts vpu on an interrupt/timer without checking
if interrupt window is actually opened.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 6 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 6 | ||||
-rw-r--r-- | arch/s390/kvm/interrupt.c | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 10 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 8 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 5 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 1 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 3 |
9 files changed, 44 insertions, 3 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index d2a90fd505b0..3bf0a345224a 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -1963,6 +1963,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) | |||
1963 | return 0; | 1963 | return 0; |
1964 | } | 1964 | } |
1965 | 1965 | ||
1966 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
1967 | { | ||
1968 | /* do real check here */ | ||
1969 | return 1; | ||
1970 | } | ||
1971 | |||
1966 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | 1972 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) |
1967 | { | 1973 | { |
1968 | return vcpu->arch.timer_fired; | 1974 | return vcpu->arch.timer_fired; |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 9057335fdc61..2cf915e51e7e 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -41,6 +41,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v) | |||
41 | return !!(v->arch.pending_exceptions); | 41 | return !!(v->arch.pending_exceptions); |
42 | } | 42 | } |
43 | 43 | ||
44 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
45 | { | ||
46 | /* do real check here */ | ||
47 | return 1; | ||
48 | } | ||
49 | |||
44 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) | 50 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) |
45 | { | 51 | { |
46 | return !(v->arch.msr & MSR_WE); | 52 | return !(v->arch.msr & MSR_WE); |
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 0189356fe209..4ed4c3a11485 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -318,6 +318,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) | |||
318 | return rc; | 318 | return rc; |
319 | } | 319 | } |
320 | 320 | ||
321 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
322 | { | ||
323 | /* do real check here */ | ||
324 | return 1; | ||
325 | } | ||
326 | |||
321 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | 327 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) |
322 | { | 328 | { |
323 | return 0; | 329 | return 0; |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 46276273a1a1..8351c4d00ac0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -521,7 +521,7 @@ struct kvm_x86_ops { | |||
521 | void (*inject_pending_irq)(struct kvm_vcpu *vcpu); | 521 | void (*inject_pending_irq)(struct kvm_vcpu *vcpu); |
522 | void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, | 522 | void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, |
523 | struct kvm_run *run); | 523 | struct kvm_run *run); |
524 | 524 | int (*interrupt_allowed)(struct kvm_vcpu *vcpu); | |
525 | int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); | 525 | int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); |
526 | int (*get_tdp_level)(void); | 526 | int (*get_tdp_level)(void); |
527 | int (*get_mt_mask_shift)(void); | 527 | int (*get_mt_mask_shift)(void); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index aa528dbad070..de741043c5b1 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2270,6 +2270,15 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) | |||
2270 | vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK; | 2270 | vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK; |
2271 | } | 2271 | } |
2272 | 2272 | ||
2273 | static int svm_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
2274 | { | ||
2275 | struct vcpu_svm *svm = to_svm(vcpu); | ||
2276 | struct vmcb *vmcb = svm->vmcb; | ||
2277 | return (vmcb->save.rflags & X86_EFLAGS_IF) && | ||
2278 | !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) && | ||
2279 | (svm->vcpu.arch.hflags & HF_GIF_MASK); | ||
2280 | } | ||
2281 | |||
2273 | static void svm_intr_assist(struct kvm_vcpu *vcpu) | 2282 | static void svm_intr_assist(struct kvm_vcpu *vcpu) |
2274 | { | 2283 | { |
2275 | struct vcpu_svm *svm = to_svm(vcpu); | 2284 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -2649,6 +2658,7 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
2649 | .exception_injected = svm_exception_injected, | 2658 | .exception_injected = svm_exception_injected, |
2650 | .inject_pending_irq = svm_intr_assist, | 2659 | .inject_pending_irq = svm_intr_assist, |
2651 | .inject_pending_vectors = do_interrupt_requests, | 2660 | .inject_pending_vectors = do_interrupt_requests, |
2661 | .interrupt_allowed = svm_interrupt_allowed, | ||
2652 | 2662 | ||
2653 | .set_tss_addr = svm_set_tss_addr, | 2663 | .set_tss_addr = svm_set_tss_addr, |
2654 | .get_tdp_level = get_npt_level, | 2664 | .get_tdp_level = get_npt_level, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index da6461d5dc84..b9e06b07aca1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2490,6 +2490,12 @@ static void vmx_update_window_states(struct kvm_vcpu *vcpu) | |||
2490 | GUEST_INTR_STATE_MOV_SS))); | 2490 | GUEST_INTR_STATE_MOV_SS))); |
2491 | } | 2491 | } |
2492 | 2492 | ||
2493 | static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
2494 | { | ||
2495 | vmx_update_window_states(vcpu); | ||
2496 | return vcpu->arch.interrupt_window_open; | ||
2497 | } | ||
2498 | |||
2493 | static void do_interrupt_requests(struct kvm_vcpu *vcpu, | 2499 | static void do_interrupt_requests(struct kvm_vcpu *vcpu, |
2494 | struct kvm_run *kvm_run) | 2500 | struct kvm_run *kvm_run) |
2495 | { | 2501 | { |
@@ -3691,7 +3697,7 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
3691 | .exception_injected = vmx_exception_injected, | 3697 | .exception_injected = vmx_exception_injected, |
3692 | .inject_pending_irq = vmx_intr_assist, | 3698 | .inject_pending_irq = vmx_intr_assist, |
3693 | .inject_pending_vectors = do_interrupt_requests, | 3699 | .inject_pending_vectors = do_interrupt_requests, |
3694 | 3700 | .interrupt_allowed = vmx_interrupt_allowed, | |
3695 | .set_tss_addr = vmx_set_tss_addr, | 3701 | .set_tss_addr = vmx_set_tss_addr, |
3696 | .get_tdp_level = get_ept_level, | 3702 | .get_tdp_level = get_ept_level, |
3697 | .get_mt_mask_shift = vmx_get_mt_mask_shift, | 3703 | .get_mt_mask_shift = vmx_get_mt_mask_shift, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8fca7a4e95a3..5bbcad345376 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4475,3 +4475,8 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | |||
4475 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); | 4475 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); |
4476 | put_cpu(); | 4476 | put_cpu(); |
4477 | } | 4477 | } |
4478 | |||
4479 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu) | ||
4480 | { | ||
4481 | return kvm_x86_ops->interrupt_allowed(vcpu); | ||
4482 | } | ||
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 40e49ede8f91..72d56844f388 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -298,6 +298,7 @@ int kvm_arch_hardware_setup(void); | |||
298 | void kvm_arch_hardware_unsetup(void); | 298 | void kvm_arch_hardware_unsetup(void); |
299 | void kvm_arch_check_processor_compat(void *rtn); | 299 | void kvm_arch_check_processor_compat(void *rtn); |
300 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); | 300 | int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu); |
301 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); | ||
301 | 302 | ||
302 | void kvm_free_physmem(struct kvm *kvm); | 303 | void kvm_free_physmem(struct kvm *kvm); |
303 | 304 | ||
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a1a4272fa57c..63d5fa2bc84a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -1610,7 +1610,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) | |||
1610 | for (;;) { | 1610 | for (;;) { |
1611 | prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); | 1611 | prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE); |
1612 | 1612 | ||
1613 | if (kvm_cpu_has_interrupt(vcpu) || | 1613 | if ((kvm_arch_interrupt_allowed(vcpu) && |
1614 | kvm_cpu_has_interrupt(vcpu)) || | ||
1614 | kvm_arch_vcpu_runnable(vcpu)) { | 1615 | kvm_arch_vcpu_runnable(vcpu)) { |
1615 | set_bit(KVM_REQ_UNHALT, &vcpu->requests); | 1616 | set_bit(KVM_REQ_UNHALT, &vcpu->requests); |
1616 | break; | 1617 | break; |