* [PATCH 2/3] VMX: Provide support for user space injected NMIs
2008-09-15 16:28 [PATCH 0/3] x86: User space NMI injection Jan Kiszka
@ 2008-09-15 16:38 ` Jan Kiszka
2008-09-15 16:55 ` [PATCH 1/3] kvm-x86: Support " Jan Kiszka
2008-09-15 16:59 ` [PATCH 3/3] kvm-userspace: Enable user space injected NMI support Jan Kiszka
2 siblings, 0 replies; 4+ messages in thread
From: Jan Kiszka @ 2008-09-15 16:38 UTC (permalink / raw)
To: kvm-devel; +Cc: Yang, Sheng, Avi Kivity
This patch adds the required bits to the VMX side for user space
injected NMIs. As with the preexisting in-kernel irqchip support, the
CPU must provide the "virtual NMI" feature for proper tracking of the
NMI blocking state. Workarounds for older CPUs are still under
consideration.
Based on the original patch by Sheng Yang.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
arch/x86/kvm/vmx.c | 111 ++++++++++++++++++++++++++++++++++-------------------
1 file changed, 72 insertions(+), 39 deletions(-)
Index: b/arch/x86/kvm/vmx.c
===================================================================
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2358,6 +2358,7 @@ static void vmx_inject_irq(struct kvm_vc
static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
{
+ ++vcpu->stat.nmi_injections;
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR);
}
@@ -2374,24 +2375,76 @@ static void kvm_do_inject_irq(struct kvm
kvm_queue_interrupt(vcpu, irq);
}
+static void enable_irq_window(struct kvm_vcpu *vcpu)
+{
+ u32 cpu_based_vm_exec_control;
+
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+ 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 = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
+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 do_interrupt_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
+ u32 guest_intr = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
u32 cpu_based_vm_exec_control;
- vcpu->arch.interrupt_window_open =
- ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
- (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-
- if (vcpu->arch.interrupt_window_open &&
- vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending)
- kvm_do_inject_irq(vcpu);
+ vcpu->arch.nmi_window_open =
+ !(guest_intr & (GUEST_INTR_STATE_NMI |
+ GUEST_INTR_STATE_MOV_SS |
+ GUEST_INTR_STATE_STI));
+
+ if (cpu_has_virtual_nmis() &&
+ vcpu->arch.nmi_window_open && vcpu->arch.nmi_pending) {
+ vcpu->arch.nmi_pending = false;
+ vcpu->arch.nmi_injected = true;
+ vmx_inject_nmi(vcpu);
- if (vcpu->arch.interrupt_window_open && vcpu->arch.interrupt.pending)
- vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
+ vcpu->arch.interrupt_window_open = 0;
+ } else {
+ vcpu->arch.interrupt_window_open =
+ ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ !(guest_intr & (GUEST_INTR_STATE_MOV_SS |
+ GUEST_INTR_STATE_STI)));
+
+ if (vcpu->arch.interrupt_window_open &&
+ vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending)
+ kvm_do_inject_irq(vcpu);
+
+ if (vcpu->arch.interrupt_window_open &&
+ vcpu->arch.interrupt.pending)
+ vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
+ }
cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+
+ if (cpu_has_virtual_nmis() && !vcpu->arch.nmi_window_open &&
+ (vcpu->arch.nmi_pending || kvm_run->request_nmi_window))
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_NMI_PENDING;
+ else
+ cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
+
if (!vcpu->arch.interrupt_window_open &&
(vcpu->arch.irq_summary || kvm_run->request_interrupt_window))
/*
@@ -2400,6 +2453,7 @@ static void do_interrupt_requests(struct
cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
else
cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
}
@@ -2903,6 +2957,14 @@ static int handle_nmi_window(struct kvm_
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
++vcpu->stat.nmi_window_exits;
+ /*
+ * If the user space waits to inject a NNI, exit as soon as possible
+ */
+ if (kvm_run->request_nmi_window && !vcpu->arch.nmi_pending) {
+ kvm_run->exit_reason = KVM_EXIT_NMI_WINDOW_OPEN;
+ return 0;
+ }
+
return 1;
}
@@ -3032,27 +3094,6 @@ static void update_tpr_threshold(struct
vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
}
-static void enable_irq_window(struct kvm_vcpu *vcpu)
-{
- u32 cpu_based_vm_exec_control;
-
- cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
- cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
- 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 = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
- cpu_based_vm_exec_control |= 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 = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
@@ -3069,14 +3110,6 @@ static int vmx_irq_enabled(struct kvm_vc
(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_complete_interrupts(struct vcpu_vmx *vmx)
{
u32 exit_intr_info;
@@ -3315,7 +3348,7 @@ static void vmx_vcpu_run(struct kvm_vcpu
if (vmx->rmode.irq.pending)
fixup_rmode_irq(vmx);
- vcpu->arch.interrupt_window_open =
+ vcpu->arch.interrupt_window_open = vcpu->arch.nmi_window_open =
(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) == 0;
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 1/3] kvm-x86: Support for user space injected NMIs
2008-09-15 16:28 [PATCH 0/3] x86: User space NMI injection Jan Kiszka
2008-09-15 16:38 ` [PATCH 2/3] VMX: Provide support for user space injected NMIs Jan Kiszka
@ 2008-09-15 16:55 ` Jan Kiszka
2008-09-15 16:59 ` [PATCH 3/3] kvm-userspace: Enable user space injected NMI support Jan Kiszka
2 siblings, 0 replies; 4+ messages in thread
From: Jan Kiszka @ 2008-09-15 16:55 UTC (permalink / raw)
To: kvm-devel; +Cc: Yang, Sheng, Avi Kivity
Introduces the KVM_NMI IOCTL to the generic x86 part of KVM for
injecting NMIs from user space and also extends the statistic report
accordingly.
Based on the original patch by Sheng Yang.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
arch/x86/kvm/x86.c | 46 +++++++++++++++++++++++++++++++++++++++++++--
include/asm-x86/kvm_host.h | 3 ++
include/linux/kvm.h | 11 ++++++++--
3 files changed, 56 insertions(+), 4 deletions(-)
Index: b/arch/x86/kvm/x86.c
===================================================================
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_en
{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
{ "hypercalls", VCPU_STAT(hypercalls) },
{ "request_irq", VCPU_STAT(request_irq_exits) },
+ { "request_nmi", VCPU_STAT(request_nmi_exits) },
{ "irq_exits", VCPU_STAT(irq_exits) },
{ "host_state_reload", VCPU_STAT(host_state_reload) },
{ "efer_reload", VCPU_STAT(efer_reload) },
@@ -93,6 +94,7 @@ struct kvm_stats_debugfs_item debugfs_en
{ "insn_emulation", VCPU_STAT(insn_emulation) },
{ "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) },
{ "irq_injections", VCPU_STAT(irq_injections) },
+ { "nmi_injections", VCPU_STAT(nmi_injections) },
{ "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) },
{ "mmu_pte_write", VM_STAT(mmu_pte_write) },
{ "mmu_pte_updated", VM_STAT(mmu_pte_updated) },
@@ -1534,6 +1536,15 @@ static int kvm_vcpu_ioctl_interrupt(stru
return 0;
}
+static int kvm_vcpu_ioctl_nmi(struct kvm_vcpu *vcpu)
+{
+ vcpu_load(vcpu);
+ kvm_inject_nmi(vcpu);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
static int vcpu_ioctl_tpr_access_reporting(struct kvm_vcpu *vcpu,
struct kvm_tpr_access_ctl *tac)
{
@@ -1593,6 +1604,13 @@ long kvm_arch_vcpu_ioctl(struct file *fi
r = 0;
break;
}
+ case KVM_NMI: {
+ r = kvm_vcpu_ioctl_nmi(vcpu);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
case KVM_SET_CPUID: {
struct kvm_cpuid __user *cpuid_arg = argp;
struct kvm_cpuid cpuid;
@@ -3050,18 +3068,37 @@ static int dm_request_for_irq_injection(
(kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
}
+/*
+ * Check if userspace requested a NMI window, and that the NMI window
+ * is open.
+ *
+ * No need to exit to userspace if we already have a NMI queued.
+ */
+static int dm_request_for_nmi_injection(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return (!vcpu->arch.nmi_pending &&
+ kvm_run->request_nmi_window &&
+ vcpu->arch.nmi_window_open);
+}
+
static void post_kvm_run_save(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
- if (irqchip_in_kernel(vcpu->kvm))
+ if (irqchip_in_kernel(vcpu->kvm)) {
kvm_run->ready_for_interrupt_injection = 1;
- else
+ kvm_run->ready_for_nmi_injection = 1;
+ } else {
kvm_run->ready_for_interrupt_injection =
(vcpu->arch.interrupt_window_open &&
vcpu->arch.irq_summary == 0);
+ kvm_run->ready_for_nmi_injection =
+ (vcpu->arch.nmi_window_open &&
+ vcpu->arch.nmi_pending == 0);
+ }
}
static void vapic_enter(struct kvm_vcpu *vcpu)
@@ -3237,6 +3274,11 @@ static int __vcpu_run(struct kvm_vcpu *v
}
if (r > 0) {
+ if (dm_request_for_nmi_injection(vcpu, kvm_run)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_NMI;
+ ++vcpu->stat.request_nmi_exits;
+ }
if (dm_request_for_irq_injection(vcpu, kvm_run)) {
r = -EINTR;
kvm_run->exit_reason = KVM_EXIT_INTR;
Index: b/include/asm-x86/kvm_host.h
===================================================================
--- a/include/asm-x86/kvm_host.h
+++ b/include/asm-x86/kvm_host.h
@@ -321,6 +321,7 @@ struct kvm_vcpu_arch {
bool nmi_pending;
bool nmi_injected;
+ bool nmi_window_open;
u64 mtrr[0x100];
};
@@ -406,6 +407,7 @@ struct kvm_vcpu_stat {
u32 halt_exits;
u32 halt_wakeup;
u32 request_irq_exits;
+ u32 request_nmi_exits;
u32 irq_exits;
u32 host_state_reload;
u32 efer_reload;
@@ -414,6 +416,7 @@ struct kvm_vcpu_stat {
u32 insn_emulation_fail;
u32 hypercalls;
u32 irq_injections;
+ u32 nmi_injections;
};
struct descriptor_table {
Index: b/include/linux/kvm.h
===================================================================
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -83,18 +83,22 @@ struct kvm_irqchip {
#define KVM_EXIT_S390_SIEIC 13
#define KVM_EXIT_S390_RESET 14
#define KVM_EXIT_DCR 15
+#define KVM_EXIT_NMI 16
+#define KVM_EXIT_NMI_WINDOW_OPEN 17
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
__u8 request_interrupt_window;
- __u8 padding1[7];
+ __u8 request_nmi_window;
+ __u8 padding1[6];
/* out */
__u32 exit_reason;
__u8 ready_for_interrupt_injection;
__u8 if_flag;
- __u8 padding2[2];
+ __u8 ready_for_nmi_injection;
+ __u8 padding2;
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;
@@ -384,6 +388,7 @@ struct kvm_trace_rec {
#define KVM_CAP_COALESCED_MMIO 15
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
#define KVM_CAP_DEVICE_ASSIGNMENT 17
+#define KVM_CAP_NMI 18
/*
* ioctls for VM fds
@@ -455,6 +460,8 @@ struct kvm_trace_rec {
#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
+/* Available with KVM_CAP_NMI */
+#define KVM_NMI _IO(KVMIO, 0x9a)
#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 3/3] kvm-userspace: Enable user space injected NMI support
2008-09-15 16:28 [PATCH 0/3] x86: User space NMI injection Jan Kiszka
2008-09-15 16:38 ` [PATCH 2/3] VMX: Provide support for user space injected NMIs Jan Kiszka
2008-09-15 16:55 ` [PATCH 1/3] kvm-x86: Support " Jan Kiszka
@ 2008-09-15 16:59 ` Jan Kiszka
2 siblings, 0 replies; 4+ messages in thread
From: Jan Kiszka @ 2008-09-15 16:59 UTC (permalink / raw)
To: kvm-devel; +Cc: Yang, Sheng, Avi Kivity
Make use of the new KVM_NMI IOCTL to push NMIs into the KVM guest if the
user space APIC emulation or some other source raised them.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
libkvm/libkvm.c | 31 +++++++++++++++++++++++++++++++
libkvm/libkvm.h | 23 +++++++++++++++++++++++
qemu/qemu-kvm-x86.c | 26 +++++++++++++++++++++++---
qemu/qemu-kvm.c | 8 +++++++-
qemu/qemu-kvm.h | 1 +
5 files changed, 85 insertions(+), 4 deletions(-)
Index: b/libkvm/libkvm.c
===================================================================
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -811,6 +811,11 @@ int try_push_interrupts(kvm_context_t kv
return kvm->callbacks->try_push_interrupts(kvm->opaque);
}
+int try_push_nmi(kvm_context_t kvm)
+{
+ return kvm->callbacks->try_push_nmi(kvm->opaque);
+}
+
void post_kvm_run(kvm_context_t kvm, int vcpu)
{
kvm->callbacks->post_kvm_run(kvm->opaque, vcpu);
@@ -835,6 +840,17 @@ int kvm_is_ready_for_interrupt_injection
return run->ready_for_interrupt_injection;
}
+int kvm_is_ready_for_nmi_injection(kvm_context_t kvm, int vcpu)
+{
+#ifdef KVM_CAP_NMI
+ struct kvm_run *run = kvm->run[vcpu];
+
+ return run->ready_for_nmi_injection;
+#else
+ return 0;
+#endif
+}
+
int kvm_run(kvm_context_t kvm, int vcpu)
{
int r;
@@ -842,6 +858,9 @@ int kvm_run(kvm_context_t kvm, int vcpu)
struct kvm_run *run = kvm->run[vcpu];
again:
+#ifdef KVM_CAP_NMI
+ run->request_nmi_window = try_push_nmi(kvm);
+#endif
#if !defined(__s390__)
if (!kvm->irqchip_in_kernel)
run->request_interrupt_window = try_push_interrupts(kvm);
@@ -917,6 +936,9 @@ again:
r = handle_halt(kvm, vcpu);
break;
case KVM_EXIT_IRQ_WINDOW_OPEN:
+#ifdef KVM_CAP_NMI
+ case KVM_EXIT_NMI_WINDOW_OPEN:
+#endif
break;
case KVM_EXIT_SHUTDOWN:
r = handle_shutdown(kvm, vcpu);
@@ -1001,6 +1023,15 @@ int kvm_has_sync_mmu(kvm_context_t kvm)
return r;
}
+int kvm_inject_nmi(kvm_context_t kvm, int vcpu)
+{
+#ifdef KVM_CAP_NMI
+ return ioctl(kvm->vcpu_fd[vcpu], KVM_NMI);
+#else
+ return -ENOSYS;
+#endif
+}
+
int kvm_init_coalesced_mmio(kvm_context_t kvm)
{
int r = 0;
Index: b/libkvm/libkvm.h
===================================================================
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -66,6 +66,7 @@ struct kvm_callbacks {
int (*shutdown)(void *opaque, int vcpu);
int (*io_window)(void *opaque);
int (*try_push_interrupts)(void *opaque);
+ int (*try_push_nmi)(void *opaque);
void (*post_kvm_run)(void *opaque, int vcpu);
int (*pre_kvm_run)(void *opaque, int vcpu);
int (*tpr_access)(void *opaque, int vcpu, uint64_t rip, int is_write);
@@ -216,6 +217,17 @@ uint64_t kvm_get_apic_base(kvm_context_t
int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu);
/*!
+ * \brief Check if a vcpu is ready for NMI injection
+ *
+ * This checks if vcpu is not already running in NMI context.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return boolean indicating NMI injection readiness
+ */
+int kvm_is_ready_for_nmi_injection(kvm_context_t kvm, int vcpu);
+
+/*!
* \brief Read VCPU registers
*
* This gets the GP registers from the VCPU and outputs them
@@ -579,6 +591,17 @@ int kvm_set_lapic(kvm_context_t kvm, int
#endif
+/*!
+ * \brief Simulate an NMI
+ *
+ * This allows you to simulate a non-maskable interrupt.
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param vcpu Which virtual CPU should get dumped
+ * \return 0 on success
+ */
+int kvm_inject_nmi(kvm_context_t kvm, int vcpu);
+
#endif
/*!
Index: b/qemu/qemu-kvm-x86.c
===================================================================
--- a/qemu/qemu-kvm-x86.c
+++ b/qemu/qemu-kvm-x86.c
@@ -598,7 +598,8 @@ int kvm_arch_halt(void *opaque, int vcpu
CPUState *env = cpu_single_env;
if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->eflags & IF_MASK))) {
+ (env->eflags & IF_MASK)) &&
+ !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
env->halted = 1;
env->exception_index = EXCP_HLT;
}
@@ -627,8 +628,9 @@ void kvm_arch_post_kvm_run(void *opaque,
int kvm_arch_has_work(CPUState *env)
{
- if ((env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT)) &&
- (env->eflags & IF_MASK))
+ if (((env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT)) &&
+ (env->eflags & IF_MASK)) ||
+ (env->interrupt_request & CPU_INTERRUPT_NMI))
return 1;
return 0;
}
@@ -653,6 +655,24 @@ int kvm_arch_try_push_interrupts(void *o
return (env->interrupt_request & CPU_INTERRUPT_HARD) != 0;
}
+int kvm_arch_try_push_nmi(void *opaque)
+{
+ CPUState *env = cpu_single_env;
+ int r;
+
+ if (likely(!(env->interrupt_request & CPU_INTERRUPT_NMI)))
+ return 0;
+
+ if (kvm_is_ready_for_nmi_injection(kvm_context, env->cpu_index)) {
+ env->interrupt_request &= ~CPU_INTERRUPT_NMI;
+ r = kvm_inject_nmi(kvm_context, env->cpu_index);
+ if (r < 0)
+ printf("cpu %d fail inject NMI\n", env->cpu_index);
+ }
+
+ return (env->interrupt_request & CPU_INTERRUPT_NMI) != 0;
+}
+
void kvm_arch_update_regs_for_sipi(CPUState *env)
{
SegmentCache cs = env->segs[R_CS];
Index: b/qemu/qemu-kvm.c
===================================================================
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -167,6 +167,11 @@ static int try_push_interrupts(void *opa
return kvm_arch_try_push_interrupts(opaque);
}
+static int try_push_nmi(void *opaque)
+{
+ return kvm_arch_try_push_nmi(opaque);
+}
+
static void post_kvm_run(void *opaque, int vcpu)
{
@@ -398,7 +403,7 @@ static int kvm_main_loop_cpu(CPUState *e
while (1) {
while (!has_work(env))
kvm_main_loop_wait(env, 1000);
- if (env->interrupt_request & CPU_INTERRUPT_HARD)
+ if (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI))
env->halted = 0;
if (!kvm_irqchip_in_kernel(kvm_context) && info->sipi_needed)
update_regs_for_sipi(env);
@@ -724,6 +729,7 @@ static struct kvm_callbacks qemu_kvm_ops
.shutdown = kvm_shutdown,
.io_window = kvm_io_window,
.try_push_interrupts = try_push_interrupts,
+ .try_push_nmi = try_push_nmi,
.post_kvm_run = post_kvm_run,
.pre_kvm_run = pre_kvm_run,
#ifdef TARGET_I386
Index: b/qemu/qemu-kvm.h
===================================================================
--- a/qemu/qemu-kvm.h
+++ b/qemu/qemu-kvm.h
@@ -57,6 +57,7 @@ void kvm_arch_pre_kvm_run(void *opaque,
void kvm_arch_post_kvm_run(void *opaque, int vcpu);
int kvm_arch_has_work(CPUState *env);
int kvm_arch_try_push_interrupts(void *opaque);
+int kvm_arch_try_push_nmi(void *opaque);
void kvm_arch_update_regs_for_sipi(CPUState *env);
void kvm_arch_cpu_reset(CPUState *env);
^ permalink raw reply [flat|nested] 4+ messages in thread