diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-03-30 09:03:13 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:37 -0400 |
commit | 37b96e988053c4dd21811b0408a12f8f60b4d0c8 (patch) | |
tree | 8f738a60f749f535a843eedf9dd343d83c9c724c /arch/x86/kvm/vmx.c | |
parent | 7b4a25cb296e2a73d2e87a4af65361d45d450a27 (diff) |
KVM: VMX: Rewrite vmx_complete_interrupt()'s twisted maze of if() statements
...with a more straightforward switch().
Also fix a bug when NMI could be dropped on exit. Although this should
never happen in practice, since NMIs can only be injected, never triggered
internally by the guest like exceptions.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r-- | arch/x86/kvm/vmx.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 631f9b720971..577aa9551a97 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3277,7 +3277,6 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) | |||
3277 | u8 vector; | 3277 | u8 vector; |
3278 | int type; | 3278 | int type; |
3279 | bool idtv_info_valid; | 3279 | bool idtv_info_valid; |
3280 | u32 error; | ||
3281 | 3280 | ||
3282 | idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; | 3281 | idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; |
3283 | exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); | 3282 | exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); |
@@ -3302,34 +3301,42 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) | |||
3302 | vmx->vnmi_blocked_time += | 3301 | vmx->vnmi_blocked_time += |
3303 | ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time)); | 3302 | ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time)); |
3304 | 3303 | ||
3304 | vmx->vcpu.arch.nmi_injected = false; | ||
3305 | kvm_clear_exception_queue(&vmx->vcpu); | ||
3306 | kvm_clear_interrupt_queue(&vmx->vcpu); | ||
3307 | |||
3308 | if (!idtv_info_valid) | ||
3309 | return; | ||
3310 | |||
3305 | vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; | 3311 | vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK; |
3306 | type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; | 3312 | type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK; |
3307 | if (vmx->vcpu.arch.nmi_injected) { | 3313 | |
3314 | switch(type) { | ||
3315 | case INTR_TYPE_NMI_INTR: | ||
3316 | vmx->vcpu.arch.nmi_injected = true; | ||
3308 | /* | 3317 | /* |
3309 | * SDM 3: 27.7.1.2 (September 2008) | 3318 | * SDM 3: 27.7.1.2 (September 2008) |
3310 | * Clear bit "block by NMI" before VM entry if a NMI delivery | 3319 | * Clear bit "block by NMI" before VM entry if a NMI |
3311 | * faulted. | 3320 | * delivery faulted. |
3312 | */ | 3321 | */ |
3313 | if (idtv_info_valid && type == INTR_TYPE_NMI_INTR) | 3322 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, |
3314 | vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, | 3323 | GUEST_INTR_STATE_NMI); |
3315 | GUEST_INTR_STATE_NMI); | 3324 | break; |
3316 | else | 3325 | case INTR_TYPE_HARD_EXCEPTION: |
3317 | vmx->vcpu.arch.nmi_injected = false; | 3326 | case INTR_TYPE_SOFT_EXCEPTION: |
3318 | } | ||
3319 | kvm_clear_exception_queue(&vmx->vcpu); | ||
3320 | if (idtv_info_valid && (type == INTR_TYPE_HARD_EXCEPTION || | ||
3321 | type == INTR_TYPE_SOFT_EXCEPTION)) { | ||
3322 | if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { | 3327 | if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) { |
3323 | error = vmcs_read32(IDT_VECTORING_ERROR_CODE); | 3328 | u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE); |
3324 | kvm_queue_exception_e(&vmx->vcpu, vector, error); | 3329 | kvm_queue_exception_e(&vmx->vcpu, vector, err); |
3325 | } else | 3330 | } else |
3326 | kvm_queue_exception(&vmx->vcpu, vector); | 3331 | kvm_queue_exception(&vmx->vcpu, vector); |
3327 | vmx->idt_vectoring_info = 0; | 3332 | vmx->idt_vectoring_info = 0; |
3328 | } | 3333 | break; |
3329 | kvm_clear_interrupt_queue(&vmx->vcpu); | 3334 | case INTR_TYPE_EXT_INTR: |
3330 | if (idtv_info_valid && type == INTR_TYPE_EXT_INTR) { | ||
3331 | kvm_queue_interrupt(&vmx->vcpu, vector); | 3335 | kvm_queue_interrupt(&vmx->vcpu, vector); |
3332 | vmx->idt_vectoring_info = 0; | 3336 | vmx->idt_vectoring_info = 0; |
3337 | break; | ||
3338 | default: | ||
3339 | break; | ||
3333 | } | 3340 | } |
3334 | } | 3341 | } |
3335 | 3342 | ||