diff options
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/svm.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 22 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 11 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 12 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 6 |
7 files changed, 48 insertions, 10 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index a1319c82050e..0b2729bf2070 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -230,6 +230,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, | |||
230 | struct x86_emulate_ops *ops); | 230 | struct x86_emulate_ops *ops); |
231 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | 231 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, |
232 | struct x86_emulate_ops *ops, | 232 | struct x86_emulate_ops *ops, |
233 | u16 tss_selector, int reason); | 233 | u16 tss_selector, int reason, |
234 | bool has_error_code, u32 error_code); | ||
234 | 235 | ||
235 | #endif /* _ASM_X86_KVM_X86_EMULATE_H */ | 236 | #endif /* _ASM_X86_KVM_X86_EMULATE_H */ |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 5d5e0a9afcf2..3602728d54de 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -595,7 +595,8 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, | |||
595 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); | 595 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); |
596 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); | 596 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); |
597 | 597 | ||
598 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason); | 598 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, |
599 | bool has_error_code, u32 error_code); | ||
599 | 600 | ||
600 | void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); | 601 | void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); |
601 | void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | 602 | void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); |
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 1d91d05f9368..0e831059ac5a 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h | |||
@@ -244,6 +244,7 @@ struct __attribute__ ((__packed__)) vmcb { | |||
244 | 244 | ||
245 | #define SVM_EXITINFOSHIFT_TS_REASON_IRET 36 | 245 | #define SVM_EXITINFOSHIFT_TS_REASON_IRET 36 |
246 | #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 | 246 | #define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 |
247 | #define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44 | ||
247 | 248 | ||
248 | #define SVM_EXIT_READ_CR0 0x000 | 249 | #define SVM_EXIT_READ_CR0 0x000 |
249 | #define SVM_EXIT_READ_CR3 0x003 | 250 | #define SVM_EXIT_READ_CR3 0x003 |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index aace5659bbe0..585d0ef4a5f6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2344,8 +2344,9 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, | |||
2344 | } | 2344 | } |
2345 | 2345 | ||
2346 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | 2346 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, |
2347 | struct x86_emulate_ops *ops, | 2347 | struct x86_emulate_ops *ops, |
2348 | u16 tss_selector, int reason) | 2348 | u16 tss_selector, int reason, |
2349 | bool has_error_code, u32 error_code) | ||
2349 | { | 2350 | { |
2350 | struct desc_struct curr_tss_desc, next_tss_desc; | 2351 | struct desc_struct curr_tss_desc, next_tss_desc; |
2351 | int ret; | 2352 | int ret; |
@@ -2418,12 +2419,22 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2418 | ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); | 2419 | ops->set_cached_descriptor(&next_tss_desc, VCPU_SREG_TR, ctxt->vcpu); |
2419 | ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); | 2420 | ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu); |
2420 | 2421 | ||
2422 | if (has_error_code) { | ||
2423 | struct decode_cache *c = &ctxt->decode; | ||
2424 | |||
2425 | c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; | ||
2426 | c->lock_prefix = 0; | ||
2427 | c->src.val = (unsigned long) error_code; | ||
2428 | emulate_push(ctxt); | ||
2429 | } | ||
2430 | |||
2421 | return ret; | 2431 | return ret; |
2422 | } | 2432 | } |
2423 | 2433 | ||
2424 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | 2434 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, |
2425 | struct x86_emulate_ops *ops, | 2435 | struct x86_emulate_ops *ops, |
2426 | u16 tss_selector, int reason) | 2436 | u16 tss_selector, int reason, |
2437 | bool has_error_code, u32 error_code) | ||
2427 | { | 2438 | { |
2428 | struct decode_cache *c = &ctxt->decode; | 2439 | struct decode_cache *c = &ctxt->decode; |
2429 | int rc; | 2440 | int rc; |
@@ -2431,12 +2442,15 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2431 | memset(c, 0, sizeof(struct decode_cache)); | 2442 | memset(c, 0, sizeof(struct decode_cache)); |
2432 | c->eip = ctxt->eip; | 2443 | c->eip = ctxt->eip; |
2433 | memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); | 2444 | memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); |
2445 | c->dst.type = OP_NONE; | ||
2434 | 2446 | ||
2435 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason); | 2447 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, |
2448 | has_error_code, error_code); | ||
2436 | 2449 | ||
2437 | if (rc == X86EMUL_CONTINUE) { | 2450 | if (rc == X86EMUL_CONTINUE) { |
2438 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); | 2451 | memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs); |
2439 | kvm_rip_write(ctxt->vcpu, c->eip); | 2452 | kvm_rip_write(ctxt->vcpu, c->eip); |
2453 | rc = writeback(ctxt, ops); | ||
2440 | } | 2454 | } |
2441 | 2455 | ||
2442 | return rc; | 2456 | return rc; |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 87b36fbbfec8..78af52222fd2 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2222,6 +2222,8 @@ static int task_switch_interception(struct vcpu_svm *svm) | |||
2222 | svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK; | 2222 | svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK; |
2223 | uint32_t idt_v = | 2223 | uint32_t idt_v = |
2224 | svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID; | 2224 | svm->vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID; |
2225 | bool has_error_code = false; | ||
2226 | u32 error_code = 0; | ||
2225 | 2227 | ||
2226 | tss_selector = (u16)svm->vmcb->control.exit_info_1; | 2228 | tss_selector = (u16)svm->vmcb->control.exit_info_1; |
2227 | 2229 | ||
@@ -2242,6 +2244,12 @@ static int task_switch_interception(struct vcpu_svm *svm) | |||
2242 | svm->vcpu.arch.nmi_injected = false; | 2244 | svm->vcpu.arch.nmi_injected = false; |
2243 | break; | 2245 | break; |
2244 | case SVM_EXITINTINFO_TYPE_EXEPT: | 2246 | case SVM_EXITINTINFO_TYPE_EXEPT: |
2247 | if (svm->vmcb->control.exit_info_2 & | ||
2248 | (1ULL << SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE)) { | ||
2249 | has_error_code = true; | ||
2250 | error_code = | ||
2251 | (u32)svm->vmcb->control.exit_info_2; | ||
2252 | } | ||
2245 | kvm_clear_exception_queue(&svm->vcpu); | 2253 | kvm_clear_exception_queue(&svm->vcpu); |
2246 | break; | 2254 | break; |
2247 | case SVM_EXITINTINFO_TYPE_INTR: | 2255 | case SVM_EXITINTINFO_TYPE_INTR: |
@@ -2258,7 +2266,8 @@ static int task_switch_interception(struct vcpu_svm *svm) | |||
2258 | (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) | 2266 | (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) |
2259 | skip_emulated_instruction(&svm->vcpu); | 2267 | skip_emulated_instruction(&svm->vcpu); |
2260 | 2268 | ||
2261 | return kvm_task_switch(&svm->vcpu, tss_selector, reason); | 2269 | return kvm_task_switch(&svm->vcpu, tss_selector, reason, |
2270 | has_error_code, error_code); | ||
2262 | } | 2271 | } |
2263 | 2272 | ||
2264 | static int cpuid_interception(struct vcpu_svm *svm) | 2273 | static int cpuid_interception(struct vcpu_svm *svm) |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fb4a8869bb99..1b38d8a88cf7 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3271,6 +3271,8 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | |||
3271 | { | 3271 | { |
3272 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 3272 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
3273 | unsigned long exit_qualification; | 3273 | unsigned long exit_qualification; |
3274 | bool has_error_code = false; | ||
3275 | u32 error_code = 0; | ||
3274 | u16 tss_selector; | 3276 | u16 tss_selector; |
3275 | int reason, type, idt_v; | 3277 | int reason, type, idt_v; |
3276 | 3278 | ||
@@ -3293,6 +3295,13 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | |||
3293 | kvm_clear_interrupt_queue(vcpu); | 3295 | kvm_clear_interrupt_queue(vcpu); |
3294 | break; | 3296 | break; |
3295 | case INTR_TYPE_HARD_EXCEPTION: | 3297 | case INTR_TYPE_HARD_EXCEPTION: |
3298 | if (vmx->idt_vectoring_info & | ||
3299 | VECTORING_INFO_DELIVER_CODE_MASK) { | ||
3300 | has_error_code = true; | ||
3301 | error_code = | ||
3302 | vmcs_read32(IDT_VECTORING_ERROR_CODE); | ||
3303 | } | ||
3304 | /* fall through */ | ||
3296 | case INTR_TYPE_SOFT_EXCEPTION: | 3305 | case INTR_TYPE_SOFT_EXCEPTION: |
3297 | kvm_clear_exception_queue(vcpu); | 3306 | kvm_clear_exception_queue(vcpu); |
3298 | break; | 3307 | break; |
@@ -3307,7 +3316,8 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | |||
3307 | type != INTR_TYPE_NMI_INTR)) | 3316 | type != INTR_TYPE_NMI_INTR)) |
3308 | skip_emulated_instruction(vcpu); | 3317 | skip_emulated_instruction(vcpu); |
3309 | 3318 | ||
3310 | if (!kvm_task_switch(vcpu, tss_selector, reason)) | 3319 | if (!kvm_task_switch(vcpu, tss_selector, reason, has_error_code, |
3320 | error_code)) | ||
3311 | return 0; | 3321 | return 0; |
3312 | 3322 | ||
3313 | /* clear all local breakpoint enable flags */ | 3323 | /* clear all local breakpoint enable flags */ |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 40991527f54a..58a295c6bf62 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4778,7 +4778,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | |||
4778 | return 0; | 4778 | return 0; |
4779 | } | 4779 | } |
4780 | 4780 | ||
4781 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) | 4781 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, |
4782 | bool has_error_code, u32 error_code) | ||
4782 | { | 4783 | { |
4783 | int cs_db, cs_l, ret; | 4784 | int cs_db, cs_l, ret; |
4784 | cache_all_regs(vcpu); | 4785 | cache_all_regs(vcpu); |
@@ -4796,7 +4797,8 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) | |||
4796 | ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; | 4797 | ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; |
4797 | 4798 | ||
4798 | ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops, | 4799 | ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops, |
4799 | tss_selector, reason); | 4800 | tss_selector, reason, has_error_code, |
4801 | error_code); | ||
4800 | 4802 | ||
4801 | if (ret == X86EMUL_CONTINUE) | 4803 | if (ret == X86EMUL_CONTINUE) |
4802 | kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); | 4804 | kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags); |