From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Yang, Sheng" Subject: [PATCH 2/2] KVM: VMX: Enable NMI with in-kernel irqchip Date: Thu, 15 May 2008 18:50:27 +0800 Message-ID: <200805151850.27483.sheng.yang@intel.com> Mime-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_zVBLIXQHX7cT4Kq" To: " kvm-devel" Return-path: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces@lists.sourceforge.net Errors-To: kvm-devel-bounces@lists.sourceforge.net List-Id: kvm.vger.kernel.org --Boundary-00=_zVBLIXQHX7cT4Kq Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline =46rom 069c50dca077796101af3eb5890e3fd31a72743f Mon Sep 17 00:00:00 2001 =46rom: Sheng Yang Date: Thu, 15 May 2008 18:23:25 +0800 Subject: [PATCH] KVM: VMX: Enable NMI with in-kernel irqchip Signed-off-by: Sheng Yang =2D-- arch/x86/kvm/vmx.c | 125 +++++++++++++++++++++++++++++++++++++---= =2D-- arch/x86/kvm/vmx.h | 12 ++++- arch/x86/kvm/x86.c | 1 + include/asm-x86/kvm_host.h | 1 + 4 files changed, 120 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e94a8c3..134c75e 100644 =2D-- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -264,6 +264,12 @@ static inline int cpu_has_vmx_vpid(void) SECONDARY_EXEC_ENABLE_VPID); } +static inline int cpu_has_virtual_nmis(void) +{ + return (vmcs_config.pin_based_exec_ctrl & + PIN_BASED_VIRTUAL_NMIS); +} + static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; @@ -1083,7 +1089,7 @@ static __init int setup_vmcs_config(struct vmcs_confi= g=20 *vmcs_conf) u32 _vmentry_control =3D 0; min =3D PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; =2D opt =3D 0; + opt =3D PIN_BASED_VIRTUAL_NMIS; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, &_pin_based_exec_control) < 0) return -EIO; @@ -2125,6 +2131,13 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, in= t=20 irq) irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } +static void vmx_inject_nmi(struct kvm_vcpu *vcpu) +{ + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR); + vcpu->arch.nmi_pending =3D 0; +} + static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { int word_index =3D __ffs(vcpu->arch.irq_summary); @@ -2648,6 +2661,19 @@ static int handle_ept_violation(struct kvm_vcpu *vcp= u,=20 struct kvm_run *kvm_run) return 1; } +static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_ru= n) +{ + u32 cpu_based_vm_exec_control; + + /* clear pending NMI */ + cpu_based_vm_exec_control =3D vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &=3D ~CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); + ++vcpu->stat.nmi_window_exits; + + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest=20 execution * may resume. Otherwise they set the kvm_run parameter to indicate what= =20 needs @@ -2658,6 +2684,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu= =20 *vcpu, [EXIT_REASON_EXCEPTION_NMI] =3D handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] =3D handle_external_interrupt, [EXIT_REASON_TRIPLE_FAULT] =3D handle_triple_fault, + [EXIT_REASON_NMI_WINDOW] =3D handle_nmi_window, [EXIT_REASON_IO_INSTRUCTION] =3D handle_io, [EXIT_REASON_CR_ACCESS] =3D handle_cr, [EXIT_REASON_DR_ACCESS] =3D handle_dr, @@ -2745,17 +2772,52 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } +static void enable_nmi_window(struct kvm_vcpu *vcpu) +{ + u32 cpu_based_vm_exec_control; + + if (!cpu_has_virtual_nmis()) + return; + + cpu_based_vm_exec_control =3D vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |=3D CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} + +static int vmx_nmi_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr =3D vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return !(guest_intr & (GUEST_INTR_STATE_NMI | + GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)); +} + +static int vmx_irq_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr =3D vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return (!(guest_intr & (GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)) && + (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); +} + +static void enable_intr_window(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.nmi_pending) + enable_nmi_window(vcpu); + else if (kvm_cpu_has_interrupt(vcpu)) + enable_irq_window(vcpu); +} + static void vmx_intr_assist(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx =3D to_vmx(vcpu); =2D u32 idtv_info_field, intr_info_field; =2D int has_ext_irq, interrupt_window_open; + u32 idtv_info_field, intr_info_field, exit_intr_info_field; int vector; update_tpr_threshold(vcpu); =2D has_ext_irq =3D kvm_cpu_has_interrupt(vcpu); intr_info_field =3D vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + exit_intr_info_field =3D vmcs_read32(VM_EXIT_INTR_INFO); idtv_info_field =3D vmx->idt_vectoring_info; if (intr_info_field & INTR_INFO_VALID_MASK) { if (idtv_info_field & INTR_INFO_VALID_MASK) { @@ -2763,8 +2825,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) if (printk_ratelimit()) printk(KERN_ERR "Fault when IDT_Vectoring\n"); } =2D if (has_ext_irq) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { @@ -2774,30 +2835,56 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) u8 vect =3D idtv_info_field & VECTORING_INFO_VECTOR_MASK; vmx_inject_irq(vcpu, vect); =2D if (unlikely(has_ext_irq)) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler); =2D vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + /* + * SDM 3: 25.7.1.2 + * Clear bit "block by NMI" before VM entry if a NMI delivery + * faulted. + */ + if ((idtv_info_field & VECTORING_INFO_TYPE_MASK) + =3D=3D INTR_TYPE_NMI_INTR && cpu_has_virtual_nmis()) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + ~GUEST_INTR_STATE_NMI); + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field + & ~INTR_INFO_RESVD_BITS_MASK); vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK)) vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, vmcs_read32(IDT_VECTORING_ERROR_CODE)); =2D if (unlikely(has_ext_irq)) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } =2D if (!has_ext_irq) + if (cpu_has_virtual_nmis()) { + /* + * SDM 3: 25.7.1.2 + * Re-set bit "block by NMI" before VM entry if vmexit caused by + * a guest IRET fault. + */ + if ((exit_intr_info_field & INTR_INFO_UNBLOCK_NMI) && + (exit_intr_info_field & INTR_INFO_VECTOR_MASK) !=3D 8) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) | + GUEST_INTR_STATE_NMI); + else if (vcpu->arch.nmi_pending) { + if (vmx_nmi_enabled(vcpu)) + vmx_inject_nmi(vcpu); + enable_intr_window(vcpu); + return; + } + + } + if (!kvm_cpu_has_interrupt(vcpu)) return; =2D interrupt_window_open =3D =2D ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && =2D (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) =3D=3D 0); =2D if (interrupt_window_open) { + if (vmx_irq_enabled(vcpu)) { vector =3D kvm_cpu_get_interrupt(vcpu); vmx_inject_irq(vcpu, vector); kvm_timer_intr_post(vcpu, vector); @@ -2958,7 +3045,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struc= t=20 kvm_run *kvm_run) fixup_rmode_irq(vmx); vcpu->arch.interrupt_window_open =3D =2D (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) =3D=3D 0; + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) =3D=3D 0; asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); vmx->launched =3D 1; @@ -2966,7 +3054,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struc= t=20 kvm_run *kvm_run) intr_info =3D vmcs_read32(VM_EXIT_INTR_INFO); /* We need to handle NMIs before interrupts are enabled */ =2D if ((intr_info & INTR_INFO_INTR_TYPE_MASK) =3D=3D 0x200) { /* nmi */ + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) =3D=3D 0x200 && + (intr_info & INTR_INFO_VALID_MASK)) { KVMTRACE_0D(NMI, vcpu, handler); asm("int $2"); } diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index 79d94c6..425a134 100644 =2D-- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h @@ -40,6 +40,7 @@ #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 #define CPU_BASED_CR8_STORE_EXITING 0x00100000 #define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 #define CPU_BASED_MOV_DR_EXITING 0x00800000 #define CPU_BASED_UNCOND_IO_EXITING 0x01000000 #define CPU_BASED_USE_IO_BITMAPS 0x02000000 @@ -216,7 +217,7 @@ enum vmcs_field { #define EXIT_REASON_TRIPLE_FAULT 2 #define EXIT_REASON_PENDING_INTERRUPT 7 =2D +#define EXIT_REASON_NMI_WINDOW 8 #define EXIT_REASON_TASK_SWITCH 9 #define EXIT_REASON_CPUID 10 #define EXIT_REASON_HLT 12 @@ -251,7 +252,9 @@ enum vmcs_field { #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ #define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_UNBLOCK_NMI 0x1000 /* 12 */ #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ +#define INTR_INFO_RESVD_BITS_MASK 0x7ffff000 #define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK #define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK @@ -259,9 +262,16 @@ enum vmcs_field { #define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ +#define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ #define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ +/* GUEST_INTERRUPTIBILITY_INFO flags. */ +#define GUEST_INTR_STATE_STI 0x00000001 +#define GUEST_INTR_STATE_MOV_SS 0x00000002 +#define GUEST_INTR_STATE_SMI 0x00000004 +#define GUEST_INTR_STATE_NMI 0x00000008 + /* * Exit Qualifications for MOV for Control Register Access */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8461da4..e537005 100644 =2D-- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -72,6 +72,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] =3D { { "mmio_exits", VCPU_STAT(mmio_exits) }, { "signal_exits", VCPU_STAT(signal_exits) }, { "irq_window", VCPU_STAT(irq_window_exits) }, + { "nmi_window", VCPU_STAT(nmi_window_exits) }, { "halt_exits", VCPU_STAT(halt_exits) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "hypercalls", VCPU_STAT(hypercalls) }, diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 567d739..28f2e91 100644 =2D-- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -344,6 +344,7 @@ struct kvm_vcpu_stat { u32 mmio_exits; u32 signal_exits; u32 irq_window_exits; + u32 nmi_window_exits; u32 halt_exits; u32 halt_wakeup; u32 request_irq_exits; =2D- 1.5.5 --Boundary-00=_zVBLIXQHX7cT4Kq Content-Type: text/x-diff; charset="utf-8"; name="0002-KVM-VMX-Enable-NMI-with-in-kernel-irqchip.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="0002-KVM-VMX-Enable-NMI-with-in-kernel-irqchip.patch" =46rom 069c50dca077796101af3eb5890e3fd31a72743f Mon Sep 17 00:00:00 2001 =46rom: Sheng Yang Date: Thu, 15 May 2008 18:23:25 +0800 Subject: [PATCH] KVM: VMX: Enable NMI with in-kernel irqchip Signed-off-by: Sheng Yang =2D-- arch/x86/kvm/vmx.c | 125 +++++++++++++++++++++++++++++++++++++---= =2D-- arch/x86/kvm/vmx.h | 12 ++++- arch/x86/kvm/x86.c | 1 + include/asm-x86/kvm_host.h | 1 + 4 files changed, 120 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e94a8c3..134c75e 100644 =2D-- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -264,6 +264,12 @@ static inline int cpu_has_vmx_vpid(void) SECONDARY_EXEC_ENABLE_VPID); } =20 +static inline int cpu_has_virtual_nmis(void) +{ + return (vmcs_config.pin_based_exec_ctrl & + PIN_BASED_VIRTUAL_NMIS); +} + static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) { int i; @@ -1083,7 +1089,7 @@ static __init int setup_vmcs_config(struct vmcs_confi= g *vmcs_conf) u32 _vmentry_control =3D 0; =20 min =3D PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; =2D opt =3D 0; + opt =3D PIN_BASED_VIRTUAL_NMIS; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, &_pin_based_exec_control) < 0) return -EIO; @@ -2125,6 +2131,13 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu, in= t irq) irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); } =20 +static void vmx_inject_nmi(struct kvm_vcpu *vcpu) +{ + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, + INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR); + vcpu->arch.nmi_pending =3D 0; +} + static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) { int word_index =3D __ffs(vcpu->arch.irq_summary); @@ -2648,6 +2661,19 @@ static int handle_ept_violation(struct kvm_vcpu *vcp= u, struct kvm_run *kvm_run) return 1; } =20 +static int handle_nmi_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_ru= n) +{ + u32 cpu_based_vm_exec_control; + + /* clear pending NMI */ + cpu_based_vm_exec_control =3D vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control &=3D ~CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); + ++vcpu->stat.nmi_window_exits; + + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest exec= ution * may resume. Otherwise they set the kvm_run parameter to indicate what = needs @@ -2658,6 +2684,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu= *vcpu, [EXIT_REASON_EXCEPTION_NMI] =3D handle_exception, [EXIT_REASON_EXTERNAL_INTERRUPT] =3D handle_external_interrupt, [EXIT_REASON_TRIPLE_FAULT] =3D handle_triple_fault, + [EXIT_REASON_NMI_WINDOW] =3D handle_nmi_window, [EXIT_REASON_IO_INSTRUCTION] =3D handle_io, [EXIT_REASON_CR_ACCESS] =3D handle_cr, [EXIT_REASON_DR_ACCESS] =3D handle_dr, @@ -2745,17 +2772,52 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); } =20 +static void enable_nmi_window(struct kvm_vcpu *vcpu) +{ + u32 cpu_based_vm_exec_control; + + if (!cpu_has_virtual_nmis()) + return; + + cpu_based_vm_exec_control =3D vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); + cpu_based_vm_exec_control |=3D CPU_BASED_VIRTUAL_NMI_PENDING; + vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); +} + +static int vmx_nmi_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr =3D vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return !(guest_intr & (GUEST_INTR_STATE_NMI | + GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)); +} + +static int vmx_irq_enabled(struct kvm_vcpu *vcpu) +{ + u32 guest_intr =3D vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + return (!(guest_intr & (GUEST_INTR_STATE_MOV_SS | + GUEST_INTR_STATE_STI)) && + (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF)); +} + +static void enable_intr_window(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.nmi_pending) + enable_nmi_window(vcpu); + else if (kvm_cpu_has_interrupt(vcpu)) + enable_irq_window(vcpu); +} + static void vmx_intr_assist(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx =3D to_vmx(vcpu); =2D u32 idtv_info_field, intr_info_field; =2D int has_ext_irq, interrupt_window_open; + u32 idtv_info_field, intr_info_field, exit_intr_info_field; int vector; =20 update_tpr_threshold(vcpu); =20 =2D has_ext_irq =3D kvm_cpu_has_interrupt(vcpu); intr_info_field =3D vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); + exit_intr_info_field =3D vmcs_read32(VM_EXIT_INTR_INFO); idtv_info_field =3D vmx->idt_vectoring_info; if (intr_info_field & INTR_INFO_VALID_MASK) { if (idtv_info_field & INTR_INFO_VALID_MASK) { @@ -2763,8 +2825,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) if (printk_ratelimit()) printk(KERN_ERR "Fault when IDT_Vectoring\n"); } =2D if (has_ext_irq) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { @@ -2774,30 +2835,56 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) u8 vect =3D idtv_info_field & VECTORING_INFO_VECTOR_MASK; =20 vmx_inject_irq(vcpu, vect); =2D if (unlikely(has_ext_irq)) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } =20 KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler); =20 =2D vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); + /* + * SDM 3: 25.7.1.2 + * Clear bit "block by NMI" before VM entry if a NMI delivery + * faulted. + */ + if ((idtv_info_field & VECTORING_INFO_TYPE_MASK) + =3D=3D INTR_TYPE_NMI_INTR && cpu_has_virtual_nmis()) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + ~GUEST_INTR_STATE_NMI); + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field + & ~INTR_INFO_RESVD_BITS_MASK); vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); =20 if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK)) vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, vmcs_read32(IDT_VECTORING_ERROR_CODE)); =2D if (unlikely(has_ext_irq)) =2D enable_irq_window(vcpu); + enable_intr_window(vcpu); return; } =2D if (!has_ext_irq) + if (cpu_has_virtual_nmis()) { + /* + * SDM 3: 25.7.1.2 + * Re-set bit "block by NMI" before VM entry if vmexit caused by + * a guest IRET fault. + */ + if ((exit_intr_info_field & INTR_INFO_UNBLOCK_NMI) && + (exit_intr_info_field & INTR_INFO_VECTOR_MASK) !=3D 8) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, + vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) | + GUEST_INTR_STATE_NMI); + else if (vcpu->arch.nmi_pending) { + if (vmx_nmi_enabled(vcpu)) + vmx_inject_nmi(vcpu); + enable_intr_window(vcpu); + return; + } + + } + if (!kvm_cpu_has_interrupt(vcpu)) return; =2D interrupt_window_open =3D =2D ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && =2D (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) =3D=3D 0); =2D if (interrupt_window_open) { + if (vmx_irq_enabled(vcpu)) { vector =3D kvm_cpu_get_interrupt(vcpu); vmx_inject_irq(vcpu, vector); kvm_timer_intr_post(vcpu, vector); @@ -2958,7 +3045,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struc= t kvm_run *kvm_run) fixup_rmode_irq(vmx); =20 vcpu->arch.interrupt_window_open =3D =2D (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) =3D=3D 0; + (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) =3D=3D 0; =20 asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); vmx->launched =3D 1; @@ -2966,7 +3054,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struc= t kvm_run *kvm_run) intr_info =3D vmcs_read32(VM_EXIT_INTR_INFO); =20 /* We need to handle NMIs before interrupts are enabled */ =2D if ((intr_info & INTR_INFO_INTR_TYPE_MASK) =3D=3D 0x200) { /* nmi */ + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) =3D=3D 0x200 && + (intr_info & INTR_INFO_VALID_MASK)) { KVMTRACE_0D(NMI, vcpu, handler); asm("int $2"); } diff --git a/arch/x86/kvm/vmx.h b/arch/x86/kvm/vmx.h index 79d94c6..425a134 100644 =2D-- a/arch/x86/kvm/vmx.h +++ b/arch/x86/kvm/vmx.h @@ -40,6 +40,7 @@ #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 #define CPU_BASED_CR8_STORE_EXITING 0x00100000 #define CPU_BASED_TPR_SHADOW 0x00200000 +#define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 #define CPU_BASED_MOV_DR_EXITING 0x00800000 #define CPU_BASED_UNCOND_IO_EXITING 0x01000000 #define CPU_BASED_USE_IO_BITMAPS 0x02000000 @@ -216,7 +217,7 @@ enum vmcs_field { #define EXIT_REASON_TRIPLE_FAULT 2 =20 #define EXIT_REASON_PENDING_INTERRUPT 7 =2D +#define EXIT_REASON_NMI_WINDOW 8 #define EXIT_REASON_TASK_SWITCH 9 #define EXIT_REASON_CPUID 10 #define EXIT_REASON_HLT 12 @@ -251,7 +252,9 @@ enum vmcs_field { #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ #define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_UNBLOCK_NMI 0x1000 /* 12 */ #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ +#define INTR_INFO_RESVD_BITS_MASK 0x7ffff000 =20 #define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK #define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK @@ -259,9 +262,16 @@ enum vmcs_field { #define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK =20 #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ +#define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ #define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ =20 +/* GUEST_INTERRUPTIBILITY_INFO flags. */ +#define GUEST_INTR_STATE_STI 0x00000001 +#define GUEST_INTR_STATE_MOV_SS 0x00000002 +#define GUEST_INTR_STATE_SMI 0x00000004 +#define GUEST_INTR_STATE_NMI 0x00000008 + /* * Exit Qualifications for MOV for Control Register Access */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8461da4..e537005 100644 =2D-- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -72,6 +72,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] =3D { { "mmio_exits", VCPU_STAT(mmio_exits) }, { "signal_exits", VCPU_STAT(signal_exits) }, { "irq_window", VCPU_STAT(irq_window_exits) }, + { "nmi_window", VCPU_STAT(nmi_window_exits) }, { "halt_exits", VCPU_STAT(halt_exits) }, { "halt_wakeup", VCPU_STAT(halt_wakeup) }, { "hypercalls", VCPU_STAT(hypercalls) }, diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 567d739..28f2e91 100644 =2D-- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -344,6 +344,7 @@ struct kvm_vcpu_stat { u32 mmio_exits; u32 signal_exits; u32 irq_window_exits; + u32 nmi_window_exits; u32 halt_exits; u32 halt_wakeup; u32 request_irq_exits; =2D-=20 1.5.5 --Boundary-00=_zVBLIXQHX7cT4Kq Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ --Boundary-00=_zVBLIXQHX7cT4Kq Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel --Boundary-00=_zVBLIXQHX7cT4Kq--