aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-05-11 06:35:50 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:58 -0400
commit66fd3f7f901f29a557a473af595bf11b270b9ac2 (patch)
tree6adc1e94de39238a357980068f599070428767d8 /arch/x86/kvm
parentf629cf8485c9e1063fd8b915fa3bde80917400a1 (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.c8
-rw-r--r--arch/x86/kvm/vmx.c32
-rw-r--r--arch/x86/kvm/x86.c11
-rw-r--r--arch/x86/kvm/x86.h9
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
2313static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) 2313static 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
2322static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) 2322static 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
2448static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) 2449static 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
2469static void vmx_inject_nmi(struct kvm_vcpu *vcpu) 2478static 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
11static inline void kvm_queue_interrupt(struct kvm_vcpu *vcpu, u8 vector) 11static 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
30static inline bool kvm_exception_is_soft(unsigned int nr)
31{
32 return (nr == BP_VECTOR) || (nr == OF_VECTOR);
33}
27#endif 34#endif