diff options
Diffstat (limited to 'arch')
| -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); |
