diff options
| -rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 4 | ||||
| -rw-r--r-- | arch/x86/kvm/emulate.c | 53 | ||||
| -rw-r--r-- | arch/x86/kvm/svm.c | 5 | ||||
| -rw-r--r-- | arch/x86/kvm/vmx.c | 8 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 6 |
6 files changed, 61 insertions, 17 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index 7b9cfc4878af..df437b68f42b 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
| @@ -388,7 +388,7 @@ bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt); | |||
| 388 | #define EMULATION_INTERCEPTED 2 | 388 | #define EMULATION_INTERCEPTED 2 |
| 389 | int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); | 389 | int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); |
| 390 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | 390 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, |
| 391 | u16 tss_selector, int reason, | 391 | u16 tss_selector, int idt_index, int reason, |
| 392 | bool has_error_code, u32 error_code); | 392 | bool has_error_code, u32 error_code); |
| 393 | int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); | 393 | int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); |
| 394 | #endif /* _ASM_X86_KVM_X86_EMULATE_H */ | 394 | #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 74c9edf2bb18..e216ba066e79 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -768,8 +768,8 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu); | |||
| 768 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); | 768 | void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); |
| 769 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); | 769 | int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); |
| 770 | 770 | ||
| 771 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, | 771 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, |
| 772 | bool has_error_code, u32 error_code); | 772 | int reason, bool has_error_code, u32 error_code); |
| 773 | 773 | ||
| 774 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); | 774 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); |
| 775 | int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | 775 | int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 71450aca3b86..fa310a48591c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
| @@ -1152,6 +1152,22 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, | |||
| 1152 | return 1; | 1152 | return 1; |
| 1153 | } | 1153 | } |
| 1154 | 1154 | ||
| 1155 | static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, | ||
| 1156 | u16 index, struct desc_struct *desc) | ||
| 1157 | { | ||
| 1158 | struct desc_ptr dt; | ||
| 1159 | ulong addr; | ||
| 1160 | |||
| 1161 | ctxt->ops->get_idt(ctxt, &dt); | ||
| 1162 | |||
| 1163 | if (dt.size < index * 8 + 7) | ||
| 1164 | return emulate_gp(ctxt, index << 3 | 0x2); | ||
| 1165 | |||
| 1166 | addr = dt.address + index * 8; | ||
| 1167 | return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, | ||
| 1168 | &ctxt->exception); | ||
| 1169 | } | ||
| 1170 | |||
| 1155 | static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, | 1171 | static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, |
| 1156 | u16 selector, struct desc_ptr *dt) | 1172 | u16 selector, struct desc_ptr *dt) |
| 1157 | { | 1173 | { |
| @@ -2421,7 +2437,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, | |||
| 2421 | } | 2437 | } |
| 2422 | 2438 | ||
| 2423 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | 2439 | static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, |
| 2424 | u16 tss_selector, int reason, | 2440 | u16 tss_selector, int idt_index, int reason, |
| 2425 | bool has_error_code, u32 error_code) | 2441 | bool has_error_code, u32 error_code) |
| 2426 | { | 2442 | { |
| 2427 | struct x86_emulate_ops *ops = ctxt->ops; | 2443 | struct x86_emulate_ops *ops = ctxt->ops; |
| @@ -2443,12 +2459,35 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | |||
| 2443 | 2459 | ||
| 2444 | /* FIXME: check that next_tss_desc is tss */ | 2460 | /* FIXME: check that next_tss_desc is tss */ |
| 2445 | 2461 | ||
| 2446 | if (reason != TASK_SWITCH_IRET) { | 2462 | /* |
| 2447 | if ((tss_selector & 3) > next_tss_desc.dpl || | 2463 | * Check privileges. The three cases are task switch caused by... |
| 2448 | ops->cpl(ctxt) > next_tss_desc.dpl) | 2464 | * |
| 2449 | return emulate_gp(ctxt, 0); | 2465 | * 1. jmp/call/int to task gate: Check against DPL of the task gate |
| 2466 | * 2. Exception/IRQ/iret: No check is performed | ||
| 2467 | * 3. jmp/call to TSS: Check agains DPL of the TSS | ||
| 2468 | */ | ||
| 2469 | if (reason == TASK_SWITCH_GATE) { | ||
| 2470 | if (idt_index != -1) { | ||
| 2471 | /* Software interrupts */ | ||
| 2472 | struct desc_struct task_gate_desc; | ||
| 2473 | int dpl; | ||
| 2474 | |||
| 2475 | ret = read_interrupt_descriptor(ctxt, idt_index, | ||
| 2476 | &task_gate_desc); | ||
| 2477 | if (ret != X86EMUL_CONTINUE) | ||
| 2478 | return ret; | ||
| 2479 | |||
| 2480 | dpl = task_gate_desc.dpl; | ||
| 2481 | if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl) | ||
| 2482 | return emulate_gp(ctxt, (idt_index << 3) | 0x2); | ||
| 2483 | } | ||
| 2484 | } else if (reason != TASK_SWITCH_IRET) { | ||
| 2485 | int dpl = next_tss_desc.dpl; | ||
| 2486 | if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl) | ||
| 2487 | return emulate_gp(ctxt, tss_selector); | ||
| 2450 | } | 2488 | } |
| 2451 | 2489 | ||
| 2490 | |||
| 2452 | desc_limit = desc_limit_scaled(&next_tss_desc); | 2491 | desc_limit = desc_limit_scaled(&next_tss_desc); |
| 2453 | if (!next_tss_desc.p || | 2492 | if (!next_tss_desc.p || |
| 2454 | ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || | 2493 | ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || |
| @@ -2501,7 +2540,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | |||
| 2501 | } | 2540 | } |
| 2502 | 2541 | ||
| 2503 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | 2542 | int emulator_task_switch(struct x86_emulate_ctxt *ctxt, |
| 2504 | u16 tss_selector, int reason, | 2543 | u16 tss_selector, int idt_index, int reason, |
| 2505 | bool has_error_code, u32 error_code) | 2544 | bool has_error_code, u32 error_code) |
| 2506 | { | 2545 | { |
| 2507 | int rc; | 2546 | int rc; |
| @@ -2509,7 +2548,7 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
| 2509 | ctxt->_eip = ctxt->eip; | 2548 | ctxt->_eip = ctxt->eip; |
| 2510 | ctxt->dst.type = OP_NONE; | 2549 | ctxt->dst.type = OP_NONE; |
| 2511 | 2550 | ||
| 2512 | rc = emulator_do_task_switch(ctxt, tss_selector, reason, | 2551 | rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason, |
| 2513 | has_error_code, error_code); | 2552 | has_error_code, error_code); |
| 2514 | 2553 | ||
| 2515 | if (rc == X86EMUL_CONTINUE) | 2554 | if (rc == X86EMUL_CONTINUE) |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 0b7690ee20bd..95cdeaf9c718 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
| @@ -2799,7 +2799,10 @@ static int task_switch_interception(struct vcpu_svm *svm) | |||
| 2799 | (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) | 2799 | (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) |
| 2800 | skip_emulated_instruction(&svm->vcpu); | 2800 | skip_emulated_instruction(&svm->vcpu); |
| 2801 | 2801 | ||
| 2802 | if (kvm_task_switch(&svm->vcpu, tss_selector, reason, | 2802 | if (int_type != SVM_EXITINTINFO_TYPE_SOFT) |
| 2803 | int_vec = -1; | ||
| 2804 | |||
| 2805 | if (kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason, | ||
| 2803 | has_error_code, error_code) == EMULATE_FAIL) { | 2806 | has_error_code, error_code) == EMULATE_FAIL) { |
| 2804 | svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | 2807 | svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR; |
| 2805 | svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; | 2808 | svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index d2bd719925a6..124a0952a040 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -4658,9 +4658,10 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | |||
| 4658 | bool has_error_code = false; | 4658 | bool has_error_code = false; |
| 4659 | u32 error_code = 0; | 4659 | u32 error_code = 0; |
| 4660 | u16 tss_selector; | 4660 | u16 tss_selector; |
| 4661 | int reason, type, idt_v; | 4661 | int reason, type, idt_v, idt_index; |
| 4662 | 4662 | ||
| 4663 | idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK); | 4663 | idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK); |
| 4664 | idt_index = (vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK); | ||
| 4664 | type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK); | 4665 | type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK); |
| 4665 | 4666 | ||
| 4666 | exit_qualification = vmcs_readl(EXIT_QUALIFICATION); | 4667 | exit_qualification = vmcs_readl(EXIT_QUALIFICATION); |
| @@ -4698,8 +4699,9 @@ static int handle_task_switch(struct kvm_vcpu *vcpu) | |||
| 4698 | type != INTR_TYPE_NMI_INTR)) | 4699 | type != INTR_TYPE_NMI_INTR)) |
| 4699 | skip_emulated_instruction(vcpu); | 4700 | skip_emulated_instruction(vcpu); |
| 4700 | 4701 | ||
| 4701 | if (kvm_task_switch(vcpu, tss_selector, reason, | 4702 | if (kvm_task_switch(vcpu, tss_selector, |
| 4702 | has_error_code, error_code) == EMULATE_FAIL) { | 4703 | type == INTR_TYPE_SOFT_INTR ? idt_index : -1, reason, |
| 4704 | has_error_code, error_code) == EMULATE_FAIL) { | ||
| 4703 | vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | 4705 | vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; |
| 4704 | vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; | 4706 | vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; |
| 4705 | vcpu->run->internal.ndata = 0; | 4707 | vcpu->run->internal.ndata = 0; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ca74c1dadf3a..490a1b1a255f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -5655,15 +5655,15 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | |||
| 5655 | return 0; | 5655 | return 0; |
| 5656 | } | 5656 | } |
| 5657 | 5657 | ||
| 5658 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, | 5658 | int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, |
| 5659 | bool has_error_code, u32 error_code) | 5659 | int reason, bool has_error_code, u32 error_code) |
| 5660 | { | 5660 | { |
| 5661 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 5661 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
| 5662 | int ret; | 5662 | int ret; |
| 5663 | 5663 | ||
| 5664 | init_emulate_ctxt(vcpu); | 5664 | init_emulate_ctxt(vcpu); |
| 5665 | 5665 | ||
| 5666 | ret = emulator_task_switch(ctxt, tss_selector, reason, | 5666 | ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason, |
| 5667 | has_error_code, error_code); | 5667 | has_error_code, error_code); |
| 5668 | 5668 | ||
| 5669 | if (ret) | 5669 | if (ret) |
