aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-03-30 09:03:29 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:38 -0400
commit64a7ec066813443440bfc9f60a9e76a47cfa6b2b (patch)
treed6d3461ba7667ac2801350d5b3b518e84b5df0f6 /arch/x86/kvm/vmx.c
parentb237ac37a149e8b56436fabf093532483bff13b0 (diff)
KVM: Fix unneeded instruction skipping during task switching.
There is no need to skip instruction if the reason for a task switch is a task gate in IDT and access to it is caused by an external even. The problem is currently solved only for VMX since there is no reliable way to skip an instruction in SVM. We should emulate it instead. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index e4ad9d3c0636..c6997c0e8ca6 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3038,22 +3038,40 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3038 struct vcpu_vmx *vmx = to_vmx(vcpu); 3038 struct vcpu_vmx *vmx = to_vmx(vcpu);
3039 unsigned long exit_qualification; 3039 unsigned long exit_qualification;
3040 u16 tss_selector; 3040 u16 tss_selector;
3041 int reason; 3041 int reason, type, idt_v;
3042
3043 idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
3044 type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
3042 3045
3043 exit_qualification = vmcs_readl(EXIT_QUALIFICATION); 3046 exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
3044 3047
3045 reason = (u32)exit_qualification >> 30; 3048 reason = (u32)exit_qualification >> 30;
3046 if (reason == TASK_SWITCH_GATE && vmx->vcpu.arch.nmi_injected && 3049 if (reason == TASK_SWITCH_GATE && idt_v) {
3047 (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && 3050 switch (type) {
3048 (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK) 3051 case INTR_TYPE_NMI_INTR:
3049 == INTR_TYPE_NMI_INTR) { 3052 vcpu->arch.nmi_injected = false;
3050 vcpu->arch.nmi_injected = false; 3053 if (cpu_has_virtual_nmis())
3051 if (cpu_has_virtual_nmis()) 3054 vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
3052 vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, 3055 GUEST_INTR_STATE_NMI);
3053 GUEST_INTR_STATE_NMI); 3056 break;
3057 case INTR_TYPE_EXT_INTR:
3058 kvm_clear_interrupt_queue(vcpu);
3059 break;
3060 case INTR_TYPE_HARD_EXCEPTION:
3061 case INTR_TYPE_SOFT_EXCEPTION:
3062 kvm_clear_exception_queue(vcpu);
3063 break;
3064 default:
3065 break;
3066 }
3054 } 3067 }
3055 tss_selector = exit_qualification; 3068 tss_selector = exit_qualification;
3056 3069
3070 if (!idt_v || (type != INTR_TYPE_HARD_EXCEPTION &&
3071 type != INTR_TYPE_EXT_INTR &&
3072 type != INTR_TYPE_NMI_INTR))
3073 skip_emulated_instruction(vcpu);
3074
3057 if (!kvm_task_switch(vcpu, tss_selector, reason)) 3075 if (!kvm_task_switch(vcpu, tss_selector, reason))
3058 return 0; 3076 return 0;
3059 3077
@@ -3306,7 +3324,7 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
3306 vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; 3324 vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
3307 type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; 3325 type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
3308 3326
3309 switch(type) { 3327 switch (type) {
3310 case INTR_TYPE_NMI_INTR: 3328 case INTR_TYPE_NMI_INTR:
3311 vmx->vcpu.arch.nmi_injected = true; 3329 vmx->vcpu.arch.nmi_injected = true;
3312 /* 3330 /*