summaryrefslogtreecommitdiff
path: root/libkvm
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2008-09-26 09:30:58 +0200
committerAvi Kivity <avi@redhat.com>2008-10-01 00:45:19 +0300
commit60898cb8dbabd587842bdc3ff655cc18493856a1 (patch)
tree17e638236f474a81dd0bcb5817bc47114522148d /libkvm
parent42621e776ac3a12930c3fec19c60e68e563df4cc (diff)
kvm: qemu: Enable NMI support for user space irqchip
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. In order to use the 'nmi' monitor command which asynchroniously injects NMIs for the given CPU, a new service called kvm_inject_interrupt is required. This will invoke cpu_interrupt on the target VCPU, working around the fact that the QEMU service is not thread-safe. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'libkvm')
-rw-r--r--libkvm/libkvm.c31
-rw-r--r--libkvm/libkvm.h23
2 files changed, 54 insertions, 0 deletions
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index dfa63bb8..4f23eaee 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -766,6 +766,11 @@ int try_push_interrupts(kvm_context_t kvm)
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);
@@ -790,6 +795,17 @@ int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu)
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;
@@ -797,6 +813,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);
@@ -872,6 +891,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);
@@ -956,6 +978,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;
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
index 14ea93bb..60d6d08c 100644
--- 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 kvm, int vcpu);
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
@@ -578,6 +590,17 @@ int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
#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
/*!