diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-05-11 06:35:50 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:58 -0400 |
commit | 66fd3f7f901f29a557a473af595bf11b270b9ac2 (patch) | |
tree | 6adc1e94de39238a357980068f599070428767d8 /arch/x86/kvm | |
parent | f629cf8485c9e1063fd8b915fa3bde80917400a1 (diff) |
KVM: Do not re-execute INTn instruction.
Re-inject event instead. This is what Intel suggest. Also use correct
instruction length when re-injecting soft fault/interrupt.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/svm.c | 8 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 32 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 11 | ||||
-rw-r--r-- | arch/x86/kvm/x86.h | 9 |
4 files changed, 43 insertions, 17 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 1315ce025e57..377c4f17d170 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2310,13 +2310,13 @@ static void svm_queue_irq(struct kvm_vcpu *vcpu, unsigned nr) | |||
2310 | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; | 2310 | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; |
2311 | } | 2311 | } |
2312 | 2312 | ||
2313 | static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) | 2313 | static void svm_set_irq(struct kvm_vcpu *vcpu) |
2314 | { | 2314 | { |
2315 | struct vcpu_svm *svm = to_svm(vcpu); | 2315 | struct vcpu_svm *svm = to_svm(vcpu); |
2316 | 2316 | ||
2317 | nested_svm_intr(svm); | 2317 | nested_svm_intr(svm); |
2318 | 2318 | ||
2319 | svm_queue_irq(vcpu, irq); | 2319 | svm_queue_irq(vcpu, vcpu->arch.interrupt.nr); |
2320 | } | 2320 | } |
2321 | 2321 | ||
2322 | static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) | 2322 | static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) |
@@ -2418,7 +2418,7 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) | |||
2418 | case SVM_EXITINTINFO_TYPE_EXEPT: | 2418 | case SVM_EXITINTINFO_TYPE_EXEPT: |
2419 | /* In case of software exception do not reinject an exception | 2419 | /* In case of software exception do not reinject an exception |
2420 | vector, but re-execute and instruction instead */ | 2420 | vector, but re-execute and instruction instead */ |
2421 | if (vector == BP_VECTOR || vector == OF_VECTOR) | 2421 | if (kvm_exception_is_soft(vector)) |
2422 | break; | 2422 | break; |
2423 | if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { | 2423 | if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { |
2424 | u32 err = svm->vmcb->control.exit_int_info_err; | 2424 | u32 err = svm->vmcb->control.exit_int_info_err; |
@@ -2428,7 +2428,7 @@ static void svm_complete_interrupts(struct vcpu_svm *svm) | |||
2428 | kvm_queue_exception(&svm->vcpu, vector); | 2428 | kvm_queue_exception(&svm->vcpu, vector); |
2429 | break; | 2429 | break; |
2430 | case SVM_EXITINTINFO_TYPE_INTR: | 2430 | case SVM_EXITINTINFO_TYPE_INTR: |
2431 | kvm_queue_interrupt(&svm->vcpu, vector); | 2431 | kvm_queue_interrupt(&svm->vcpu, vector, false); |
2432 | break; | 2432 | break; |
2433 | default: | 2433 | default: |
2434 | break; | 2434 | break; |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8981654ad061..29b49f09a019 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -801,8 +801,9 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | |||
801 | return; | 801 | return; |
802 | } | 802 | } |
803 | 803 | ||
804 | if (nr == BP_VECTOR || nr == OF_VECTOR) { | 804 | if (kvm_exception_is_soft(nr)) { |
805 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1); | 805 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, |
806 | vmx->vcpu.arch.event_exit_inst_len); | ||
806 | intr_info |= INTR_TYPE_SOFT_EXCEPTION; | 807 | intr_info |= INTR_TYPE_SOFT_EXCEPTION; |
807 | } else | 808 | } else |
808 | intr_info |= INTR_TYPE_HARD_EXCEPTION; | 809 | intr_info |= INTR_TYPE_HARD_EXCEPTION; |
@@ -2445,9 +2446,11 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu) | |||
2445 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); | 2446 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); |
2446 | } | 2447 | } |
2447 | 2448 | ||
2448 | static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) | 2449 | static void vmx_inject_irq(struct kvm_vcpu *vcpu) |
2449 | { | 2450 | { |
2450 | struct vcpu_vmx *vmx = to_vmx(vcpu); | 2451 | struct vcpu_vmx *vmx = to_vmx(vcpu); |
2452 | uint32_t intr; | ||
2453 | int irq = vcpu->arch.interrupt.nr; | ||
2451 | 2454 | ||
2452 | KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler); | 2455 | KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler); |
2453 | 2456 | ||
@@ -2462,8 +2465,14 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) | |||
2462 | kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); | 2465 | kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1); |
2463 | return; | 2466 | return; |
2464 | } | 2467 | } |
2465 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, | 2468 | intr = irq | INTR_INFO_VALID_MASK; |
2466 | irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); | 2469 | if (vcpu->arch.interrupt.soft) { |
2470 | intr |= INTR_TYPE_SOFT_INTR; | ||
2471 | vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, | ||
2472 | vmx->vcpu.arch.event_exit_inst_len); | ||
2473 | } else | ||
2474 | intr |= INTR_TYPE_EXT_INTR; | ||
2475 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr); | ||
2467 | } | 2476 | } |
2468 | 2477 | ||
2469 | static void vmx_inject_nmi(struct kvm_vcpu *vcpu) | 2478 | static void vmx_inject_nmi(struct kvm_vcpu *vcpu) |
@@ -3024,6 +3033,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
3024 | GUEST_INTR_STATE_NMI); | 3033 | GUEST_INTR_STATE_NMI); |
3025 | break; | 3034 | break; |
3026 | case INTR_TYPE_EXT_INTR: | 3035 | case INTR_TYPE_EXT_INTR: |
3036 | case INTR_TYPE_SOFT_INTR: | ||
3027 | kvm_clear_interrupt_queue(vcpu); | 3037 | kvm_clear_interrupt_queue(vcpu); |
3028 | break; | 3038 | break; |
3029 | case INTR_TYPE_HARD_EXCEPTION: | 3039 | case INTR_TYPE_HARD_EXCEPTION: |
@@ -3295,16 +3305,24 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) | |||
3295 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, | 3305 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, |
3296 | GUEST_INTR_STATE_NMI); | 3306 | GUEST_INTR_STATE_NMI); |
3297 | break; | 3307 | break; |
3298 | case INTR_TYPE_HARD_EXCEPTION: | ||
3299 | case INTR_TYPE_SOFT_EXCEPTION: | 3308 | case INTR_TYPE_SOFT_EXCEPTION: |
3309 | vmx->vcpu.arch.event_exit_inst_len = | ||
3310 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN); | ||
3311 | /* fall through */ | ||
3312 | case INTR_TYPE_HARD_EXCEPTION: | ||
3300 | if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { | 3313 | if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { |
3301 | u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE); | 3314 | u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE); |
3302 | kvm_queue_exception_e(&vmx->vcpu, vector, err); | 3315 | kvm_queue_exception_e(&vmx->vcpu, vector, err); |
3303 | } else | 3316 | } else |
3304 | kvm_queue_exception(&vmx->vcpu, vector); | 3317 | kvm_queue_exception(&vmx->vcpu, vector); |
3305 | break; | 3318 | break; |
3319 | case INTR_TYPE_SOFT_INTR: | ||
3320 | vmx->vcpu.arch.event_exit_inst_len = | ||
3321 | vmcs_read32(VM_EXIT_INSTRUCTION_LEN); | ||
3322 | /* fall through */ | ||
3306 | case INTR_TYPE_EXT_INTR: | 3323 | case INTR_TYPE_EXT_INTR: |
3307 | kvm_queue_interrupt(&vmx->vcpu, vector); | 3324 | kvm_queue_interrupt(&vmx->vcpu, vector, |
3325 | type == INTR_TYPE_SOFT_INTR); | ||
3308 | break; | 3326 | break; |
3309 | default: | 3327 | default: |
3310 | break; | 3328 | break; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 54eec3565485..73cfe87fba10 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1441,7 +1441,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, | |||
1441 | return -ENXIO; | 1441 | return -ENXIO; |
1442 | vcpu_load(vcpu); | 1442 | vcpu_load(vcpu); |
1443 | 1443 | ||
1444 | kvm_queue_interrupt(vcpu, irq->irq); | 1444 | kvm_queue_interrupt(vcpu, irq->irq, false); |
1445 | 1445 | ||
1446 | vcpu_put(vcpu); | 1446 | vcpu_put(vcpu); |
1447 | 1447 | ||
@@ -3161,7 +3161,7 @@ static void inject_irq(struct kvm_vcpu *vcpu) | |||
3161 | } | 3161 | } |
3162 | 3162 | ||
3163 | if (vcpu->arch.interrupt.pending) { | 3163 | if (vcpu->arch.interrupt.pending) { |
3164 | kvm_x86_ops->set_irq(vcpu, vcpu->arch.interrupt.nr); | 3164 | kvm_x86_ops->set_irq(vcpu); |
3165 | return; | 3165 | return; |
3166 | } | 3166 | } |
3167 | 3167 | ||
@@ -3174,8 +3174,9 @@ static void inject_irq(struct kvm_vcpu *vcpu) | |||
3174 | } | 3174 | } |
3175 | } else if (kvm_cpu_has_interrupt(vcpu)) { | 3175 | } else if (kvm_cpu_has_interrupt(vcpu)) { |
3176 | if (kvm_x86_ops->interrupt_allowed(vcpu)) { | 3176 | if (kvm_x86_ops->interrupt_allowed(vcpu)) { |
3177 | kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu)); | 3177 | kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu), |
3178 | kvm_x86_ops->set_irq(vcpu, vcpu->arch.interrupt.nr); | 3178 | false); |
3179 | kvm_x86_ops->set_irq(vcpu); | ||
3179 | } | 3180 | } |
3180 | } | 3181 | } |
3181 | } | 3182 | } |
@@ -4098,7 +4099,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | |||
4098 | pending_vec = find_first_bit( | 4099 | pending_vec = find_first_bit( |
4099 | (const unsigned long *)sregs->interrupt_bitmap, max_bits); | 4100 | (const unsigned long *)sregs->interrupt_bitmap, max_bits); |
4100 | if (pending_vec < max_bits) { | 4101 | if (pending_vec < max_bits) { |
4101 | kvm_queue_interrupt(vcpu, pending_vec); | 4102 | kvm_queue_interrupt(vcpu, pending_vec, false); |
4102 | pr_debug("Set back pending irq %d\n", pending_vec); | 4103 | pr_debug("Set back pending irq %d\n", pending_vec); |
4103 | if (irqchip_in_kernel(vcpu->kvm)) | 4104 | if (irqchip_in_kernel(vcpu->kvm)) |
4104 | kvm_pic_clear_isr_ack(vcpu->kvm); | 4105 | kvm_pic_clear_isr_ack(vcpu->kvm); |
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index c1f1a8ceba64..4c8e10af78e8 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h | |||
@@ -8,9 +8,11 @@ static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu) | |||
8 | vcpu->arch.exception.pending = false; | 8 | vcpu->arch.exception.pending = false; |
9 | } | 9 | } |
10 | 10 | ||
11 | static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector) | 11 | static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector, |
12 | bool soft) | ||
12 | { | 13 | { |
13 | vcpu->arch.interrupt.pending = true; | 14 | vcpu->arch.interrupt.pending = true; |
15 | vcpu->arch.interrupt.soft = soft; | ||
14 | vcpu->arch.interrupt.nr = vector; | 16 | vcpu->arch.interrupt.nr = vector; |
15 | } | 17 | } |
16 | 18 | ||
@@ -24,4 +26,9 @@ static inline bool kvm_event_needs_reinjection(struct kvm_vcpu *vcpu) | |||
24 | return vcpu->arch.exception.pending || vcpu->arch.interrupt.pending || | 26 | return vcpu->arch.exception.pending || vcpu->arch.interrupt.pending || |
25 | vcpu->arch.nmi_injected; | 27 | vcpu->arch.nmi_injected; |
26 | } | 28 | } |
29 | |||
30 | static inline bool kvm_exception_is_soft(unsigned int nr) | ||
31 | { | ||
32 | return (nr == BP_VECTOR) || (nr == OF_VECTOR); | ||
33 | } | ||
27 | #endif | 34 | #endif |