aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
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
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')
-rw-r--r--arch/x86/include/asm/svm.h1
-rw-r--r--arch/x86/kvm/svm.c25
-rw-r--r--arch/x86/kvm/vmx.c38
-rw-r--r--arch/x86/kvm/x86.c5
4 files changed, 51 insertions, 18 deletions
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 82ada75f3ebf..85574b7c1bc1 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -225,6 +225,7 @@ struct __attribute__ ((__packed__)) vmcb {
225#define SVM_EVTINJ_VALID_ERR (1 << 11) 225#define SVM_EVTINJ_VALID_ERR (1 << 11)
226 226
227#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK 227#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
228#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK
228 229
229#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR 230#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
230#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI 231#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index de741043c5b1..bba67b70c4b0 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1825,17 +1825,28 @@ static int task_switch_interception(struct vcpu_svm *svm,
1825 struct kvm_run *kvm_run) 1825 struct kvm_run *kvm_run)
1826{ 1826{
1827 u16 tss_selector; 1827 u16 tss_selector;
1828 int reason;
1829 int int_type = svm->vmcb->control.exit_int_info &
1830 SVM_EXITINTINFO_TYPE_MASK;
1828 1831
1829 tss_selector = (u16)svm->vmcb->control.exit_info_1; 1832 tss_selector = (u16)svm->vmcb->control.exit_info_1;
1833
1830 if (svm->vmcb->control.exit_info_2 & 1834 if (svm->vmcb->control.exit_info_2 &
1831 (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET)) 1835 (1ULL << SVM_EXITINFOSHIFT_TS_REASON_IRET))
1832 return kvm_task_switch(&svm->vcpu, tss_selector, 1836 reason = TASK_SWITCH_IRET;
1833 TASK_SWITCH_IRET); 1837 else if (svm->vmcb->control.exit_info_2 &
1834 if (svm->vmcb->control.exit_info_2 & 1838 (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP))
1835 (1ULL << SVM_EXITINFOSHIFT_TS_REASON_JMP)) 1839 reason = TASK_SWITCH_JMP;
1836 return kvm_task_switch(&svm->vcpu, tss_selector, 1840 else if (svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID)
1837 TASK_SWITCH_JMP); 1841 reason = TASK_SWITCH_GATE;
1838 return kvm_task_switch(&svm->vcpu, tss_selector, TASK_SWITCH_CALL); 1842 else
1843 reason = TASK_SWITCH_CALL;
1844
1845
1846 if (reason != TASK_SWITCH_GATE || int_type == SVM_EXITINTINFO_TYPE_SOFT)
1847 skip_emulated_instruction(&svm->vcpu);
1848
1849 return kvm_task_switch(&svm->vcpu, tss_selector, reason);
1839} 1850}
1840 1851
1841static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) 1852static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
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 /*
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index adcf73871a9d..bb04f11bf70f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3935,7 +3935,10 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
3935 kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT); 3935 kvm_x86_ops->set_rflags(vcpu, eflags & ~X86_EFLAGS_NT);
3936 } 3936 }
3937 3937
3938 kvm_x86_ops->skip_emulated_instruction(vcpu); 3938 /* set back link to prev task only if NT bit is set in eflags
3939 note that old_tss_sel is not used afetr this point */
3940 if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
3941 old_tss_sel = 0xffff;
3939 3942
3940 /* set back link to prev task only if NT bit is set in eflags 3943 /* set back link to prev task only if NT bit is set in eflags
3941 note that old_tss_sel is not used afetr this point */ 3944 note that old_tss_sel is not used afetr this point */