diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/svm.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 25 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 38 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 5 |
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 | ||
1841 | static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | 1852 | static 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 */ |