Skip to contentSkip to conversation

irqdevice INTR example

PATCH Gregory Haskins 3 participants 13 messages Apr 12, 2007 – Apr 16, 2007 9 messages not in the archive KVM

lore
Share & tools
lore
#0 lore raw

Hi All,
Attached are the first three patches in my queue. The first two you are likely familiar with at this point (though I have made some more of the requested changes to 02-irqdevice.patch). The last item (03-preemptible-cpu.patch) adds an implementation to the previously unused kvm_vcpu_intr() callback. This acts as a functional example of the INTR callback mechanism as Avi requested. Note that the work related to IF/NMI/TPR classification of interrupts happens later in my queue and is not mature enough to share yet, but hopefully soon.

Thoughts?
-Greg

KVM: Adds support for in-kernel mmio handlers

From: <>

---

 drivers/kvm/kvm.h      |   31 ++++++++++++++++++
 drivers/kvm/kvm_main.c |   82 +++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 101 insertions(+), 12 deletions(-)
drivers/kvm/kvm.h +31 -0
index fceeb84..181099f 100644
@@ -236,6 +236,36 @@ struct kvm_pio_request {
 	int rep;
 };
 
+struct kvm_io_device {
+	unsigned long (*read)(struct kvm_io_device *this,
+			      gpa_t addr,
+			      int length);
+	void (*write)(struct kvm_io_device *this,
+		      gpa_t addr,
+		      int length,
+		      unsigned long val);
+	int (*in_range)(struct kvm_io_device *this, gpa_t addr);
+
+	void             *private;
+};
+
+/*
+ * It would be nice to use something smarter than a linear search, TBD...
+ * Thankfully we dont expect many devices to register (famous last words :),
+ * so until then it will suffice.  At least its abstracted so we can change
+ * in one place.
+ */
+struct kvm_io_bus {
+	int                   dev_count;
+#define NR_IOBUS_DEVS 6
+	struct kvm_io_device *devs[NR_IOBUS_DEVS];
+};
+
+void kvm_io_bus_init(struct kvm_io_bus *bus);
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus, 
+			     struct kvm_io_device *dev);
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -345,6 +375,7 @@ struct kvm {
 	unsigned long rmap_overflow;
 	struct list_head vm_list;
 	struct file *filp;
+	struct kvm_io_bus mmio_bus;
 };
 
 struct kvm_stat {
drivers/kvm/kvm_main.c +70 -12

126 lines not on this page · raw message

KVM: Add irqdevice object

From: <>

The current code is geared towards using a user-mode (A)PIC. This patch adds an "irqdevice" abstraction, and implements a "userint" model to handle the duties of the original code. Later, we can develop other irqdevice models to handle objects like LAPIC, IOAPIC, i8259, etc, as appropriate

---

 drivers/kvm/Makefile    |    2 
 drivers/kvm/irqdevice.h |  170 ++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/kvm.h       |    9 +-
 drivers/kvm/kvm_main.c  |   57 ++++++++++---
 drivers/kvm/svm.c       |   33 ++++----
 drivers/kvm/userint.c   |  202 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/vmx.c       |   29 +++----
 7 files changed, 449 insertions(+), 53 deletions(-)
drivers/kvm/Makefile +1 -1
index c0a789f..540afbc 100644
@@ -2,7 +2,7 @@
 # Makefile for Kernel-based Virtual Machine module
 #
 
-kvm-objs := kvm_main.o mmu.o x86_emulate.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o userint.o
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
drivers/kvm/irqdevice.h new file +170 -0

170 lines not on this page · raw message

drivers/kvm/kvm.h +6 -3
index 181099f..58966d9 100644
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 
 #include "vmx.h"
+#include "irqdevice.h"
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
 
@@ -157,6 +158,8 @@ struct vmcs {
 
 struct kvm_vcpu;
 
+int kvm_userint_init(struct kvm_irqdevice *dev);
+
 /*
  * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
  * 32-bit).  The kvm_mmu structure abstracts the details of the current mmu
@@ -266,6 +269,8 @@ struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
 void kvm_io_bus_register_dev(struct kvm_io_bus *bus, 
 			     struct kvm_io_device *dev);
 
+#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -278,9 +283,7 @@ struct kvm_vcpu {
 	u64 host_tsc;
 	struct kvm_run *run;
 	int interrupt_window_open;
-	unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
-	unsigned long irq_pending[NR_IRQ_WORDS];
+	struct kvm_irqdevice irq_dev;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +41 -16

88 lines not on this page · raw message

drivers/kvm/svm.c +16 -17
index b7e1410..e59a548 100644
@@ -108,20 +108,16 @@ static unsigned get_addr_size(struct kvm_vcpu *vcpu)
 
 static inline u8 pop_irq(struct kvm_vcpu *vcpu)
 {
-	int word_index = __ffs(vcpu->irq_summary);
-	int bit_index = __ffs(vcpu->irq_pending[word_index]);
-	int irq = word_index * BITS_PER_LONG + bit_index;
-
-	clear_bit(bit_index, &vcpu->irq_pending[word_index]);
-	if (!vcpu->irq_pending[word_index])
-		clear_bit(word_index, &vcpu->irq_summary);
-	return irq;
+	return kvm_irqdevice_read_vector(&vcpu->irq_dev, 0);
 }
 
 static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
 {
-	set_bit(irq, vcpu->irq_pending);
-	set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+	/* FIXME: We probably want to reserve the "set_pin" verb for
+	 * actual interrupt requests, not for putting back something
+	 * previously pending.  Lets revisit this
+	 */
+	kvm_irqdevice_set_pin(&vcpu->irq_dev, irq, 1);
 }
 
 static inline void clgi(void)
@@ -1092,7 +1088,7 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
 	skip_emulated_instruction(vcpu);
-	if (vcpu->irq_summary)
+	if (kvm_irqdevice_pending(&vcpu->irq_dev, 0))
 		return 1;
 
 	kvm_run->exit_reason = KVM_EXIT_HLT;
@@ -1263,7 +1259,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
 	 * possible
 	 */
 	if (kvm_run->request_interrupt_window &&
-	    !vcpu->irq_summary) {
+	    !kvm_irqdevice_pending(&vcpu->irq_dev, 0)) {
 		++kvm_stat.irq_window_exits;
 		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
 		return 0;
@@ -1399,7 +1395,8 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 		(!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
 		 (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
 
-	if (vcpu->interrupt_window_open && vcpu->irq_summary)
+	if (vcpu->interrupt_window_open && 
+	    kvm_irqdevice_pending(&vcpu->irq_dev, 0))
 		/*
 		 * If interrupts enabled, and not blocked by sti or mov ss. Good.
 		 */
@@ -1409,7 +1406,8 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 	 * Interrupts blocked.  Wait for unblock.
 	 */
 	if (!vcpu->interrupt_window_open &&
-	    (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
+	    (kvm_irqdevice_pending(&vcpu->irq_dev, 0) || 
+	     kvm_run->request_interrupt_window)) {
 		control->intercept |= 1ULL << INTERCEPT_VINTR;
 	} else
 		control->intercept &= ~(1ULL << INTERCEPT_VINTR);
@@ -1418,8 +1416,9 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 static void post_kvm_run_save(struct kvm_vcpu *vcpu,
 			      struct kvm_run *kvm_run)
 {
-	kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
-						  vcpu->irq_summary == 0);
+	kvm_run->ready_for_interrupt_injection = 
+		(vcpu->interrupt_window_open && 
+		 !kvm_irqdevice_pending(&vcpu->irq_dev, 0));
 	kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
 	kvm_run->cr8 = vcpu->cr8;
 	kvm_run->apic_base = vcpu->apic_base;
@@ -1434,7 +1433,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
 					  struct kvm_run *kvm_run)
 {
-	return (!vcpu->irq_summary &&
+	return (!kvm_irqdevice_pending(&vcpu->irq_dev, 0) &&
 		kvm_run->request_interrupt_window &&
 		vcpu->interrupt_window_open &&
 		(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
drivers/kvm/userint.c new file +202 -0

202 lines not on this page · raw message

drivers/kvm/vmx.c +13 -16
index 61a6116..a0fdf02 100644
@@ -1219,13 +1219,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
 
 static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
 {
-	int word_index = __ffs(vcpu->irq_summary);
-	int bit_index = __ffs(vcpu->irq_pending[word_index]);
-	int irq = word_index * BITS_PER_LONG + bit_index;
-
-	clear_bit(bit_index, &vcpu->irq_pending[word_index]);
-	if (!vcpu->irq_pending[word_index])
-		clear_bit(word_index, &vcpu->irq_summary);
+	int irq = kvm_irqdevice_read_vector(&vcpu->irq_dev, 0);
+	BUG_ON(irq < 0);
 
 	if (vcpu->rmode.active) {
 		inject_rmode_irq(vcpu, irq);
@@ -1246,7 +1241,7 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 		 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
 
 	if (vcpu->interrupt_window_open &&
-	    vcpu->irq_summary &&
+	    kvm_irqdevice_pending(&vcpu->irq_dev, 0) &&
 	    !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
 		/*
 		 * If interrupts enabled, and not blocked by sti or mov ss. Good.
@@ -1255,7 +1250,8 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
 
 	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
 	if (!vcpu->interrupt_window_open &&
-	    (vcpu->irq_summary || kvm_run->request_interrupt_window))
+	    (kvm_irqdevice_pending(&vcpu->irq_dev, 0) ||
+	     kvm_run->request_interrupt_window))
 		/*
 		 * Interrupts blocked.  Wait for unblock.
 		 */
@@ -1314,8 +1310,8 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 	if (is_external_interrupt(vect_info)) {
 		int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
-		set_bit(irq, vcpu->irq_pending);
-		set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
+		/* FIXME: Is this right? */
+		kvm_irqdevice_set_pin(&vcpu->irq_dev, irq, 1); 
 	}
 
 	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
@@ -1619,8 +1615,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
 	kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
 	kvm_run->cr8 = vcpu->cr8;
 	kvm_run->apic_base = vcpu->apic_base;
-	kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
-						  vcpu->irq_summary == 0);
+	kvm_run->ready_for_interrupt_injection = 
+		(vcpu->interrupt_window_open && 
+		 !kvm_irqdevice_pending(&vcpu->irq_dev, 0));
 }
 
 static int handle_interrupt_window(struct kvm_vcpu *vcpu,
@@ -1631,7 +1628,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
 	 * possible
 	 */
 	if (kvm_run->request_interrupt_window &&
-	    !vcpu->irq_summary) {
+	    !kvm_irqdevice_pending(&vcpu->irq_dev, 0)) {
 		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
 		++kvm_stat.irq_window_exits;
 		return 0;
@@ -1642,7 +1639,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
 static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
 	skip_emulated_instruction(vcpu);
-	if (vcpu->irq_summary)
+	if (kvm_irqdevice_pending(&vcpu->irq_dev, 0))
 		return 1;
 
 	kvm_run->exit_reason = KVM_EXIT_HLT;
@@ -1713,7 +1710,7 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
 					  struct kvm_run *kvm_run)
 {
-	return (!vcpu->irq_summary &&
+	return (!kvm_irqdevice_pending(&vcpu->irq_dev, 0) &&
 		kvm_run->request_interrupt_window &&
 		vcpu->interrupt_window_open &&
 		(vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

---

 drivers/kvm/Makefile   |    2 -
 drivers/kvm/condvar.c  |  109 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/condvar.h  |   36 ++++++++++++++++
 drivers/kvm/kvm.h      |   12 +++++
 drivers/kvm/kvm_main.c |   47 ++++++++++++++++++---
 drivers/kvm/svm.c      |   35 +++++++++++++++
 drivers/kvm/vmx.c      |   35 +++++++++++++++
 7 files changed, 270 insertions(+), 6 deletions(-)
drivers/kvm/Makefile +1 -1
index 540afbc..b3bef0e 100644
@@ -2,7 +2,7 @@
 # Makefile for Kernel-based Virtual Machine module
 #
 
-kvm-objs := kvm_main.o mmu.o x86_emulate.o userint.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o userint.o condvar.o
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
drivers/kvm/condvar.c new file +109 -0

109 lines not on this page · raw message

drivers/kvm/condvar.h new file +36 -0
new file mode 100644
index 0000000..58ed523
@@ -0,0 +1,36 @@
+/*
+ * Condition Variable
+ *
+ * Copyright (C) 2007, Novell
+ *
+ * Authors:
+ *   Gregory Haskins <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+struct cv_lock_ops {
+	void (*lock)(void *);
+	void (*unlock)(void *);
+};
+
+struct condvar {
+	wait_queue_head_t   queue;
+	struct cv_lock_ops *lock_ops;
+};
+
+void condvar_init(struct condvar *cv);
+int condvar_wait(struct condvar *cv, void *l, long timeout);
+int condvar_signal(struct condvar *cv);
+
+/*
+ *------------------------------------------------------------------------
+ * spinlock_condvar
+ *------------------------------------------------------------------------
+ */
+
+void spinlock_condvar_init(struct condvar *cv);
+
+
drivers/kvm/kvm.h +12 -0
index 58966d9..703ffe0 100644
@@ -14,6 +14,7 @@
 
 #include "vmx.h"
 #include "irqdevice.h"
+#include "condvar.h"
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
 
@@ -271,6 +272,16 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
 
+/*
+ * structure for maintaining info for interrupting an executing VCPU
+ */
+struct kvm_vcpu_irq {
+	spinlock_t          lock;
+	struct condvar      cv;
+	struct task_struct *task;
+	int                 pending;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -284,6 +295,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int interrupt_window_open;
 	struct kvm_irqdevice irq_dev;
+	struct kvm_vcpu_irq irq;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +42 -5

61 lines not on this page · raw message

drivers/kvm/svm.c +35 -0
index e59a548..6bc2fb1 100644
@@ -1463,9 +1463,25 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	int r;
 
 again:
+	spin_lock(&vcpu->irq.lock);
+
+	/*
+	 * Setting vcpu->task signals to outsiders that the VMCS is 
+	 * effectively in GUEST mode, and therefore must be signalled
+	 * to transition the task back to HOST mode if any new interrupts
+	 * arrive.
+	 */
+	vcpu->irq.task = current;
+
+	/*
+	 * We also must inject interrupts (if any) while the irq_lock
+	 * is held
+	 */
 	if (!vcpu->mmio_read_completed)
 		do_interrupt_requests(vcpu, kvm_run);
 
+	spin_unlock(&vcpu->irq.lock);
+
 	clgi();
 
 	pre_svm_run(vcpu);
@@ -1617,6 +1633,25 @@ again:
 	reload_tss(vcpu);
 
 	/*
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.task = NULL;
+	condvar_signal(&vcpu->irq.cv);
+
+	/*
+	 * If irqpending is asserted someone undoubtedly has sent us a SIGSTOP
+	 * signal.  Counter it with a SIGCONT
+	 */
+	if(vcpu->irq.pending) {
+	    send_sig(SIGCONT, current, 0);
+	    vcpu->irq.pending = 0;
+	}
+
+	spin_unlock(&vcpu->irq.lock);
+
+	/*
 	 * Profile KVM exit RIPs:
 	 */
 	if (unlikely(prof_on == KVM_PROFILING))
drivers/kvm/vmx.c +35 -0
index a0fdf02..f7b716b 100644
@@ -1748,9 +1748,25 @@ again:
 	vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
 #endif
 
+	spin_lock(&vcpu->irq.lock);
+
+	/*
+	 * Setting vcpu->task signals to outsiders that the VMCS is 
+	 * effectively in GUEST mode, and therefore must be signalled
+	 * to transition the task back to HOST mode if any new interrupts
+	 * arrive.
+	 */
+	vcpu->irq.task = current;
+
+	/*
+	 * We also must inject interrupts (if any) while the irq_lock
+	 * is held
+	 */
 	if (!vcpu->mmio_read_completed)
 		do_interrupt_requests(vcpu, kvm_run);
 
+	spin_unlock(&vcpu->irq.lock);
+
 	if (vcpu->guest_debug.enabled)
 		kvm_guest_debug_pre(vcpu);
 
@@ -1911,6 +1927,25 @@ again:
 
 	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
+	/*
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.task = NULL;
+	condvar_signal(&vcpu->irq.cv);
+
+	/*
+	 * If irqpending is asserted someone undoubtedly has sent us a SIGSTOP
+	 * signal.  Counter it with a SIGCONT
+	 */
+	if(vcpu->irq.pending) {
+	    send_sig(SIGCONT, current, 0);
+	    vcpu->irq.pending = 0;
+	}
+
+	spin_unlock(&vcpu->irq.lock);
+
 	if (fail) {
 		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		kvm_run->fail_entry.hardware_entry_failure_reason

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 19 lines · Gregory Haskins

Hi All,
Attached are the first three patches in my queue. The first two you are likely familiar with at this point (though I have made some more of the requested changes to 02-irqdevice.patch). The last item (03-preemptible-cpu.patch) adds an implementation to the previously unused kvm_vcpu_intr() callback. This acts as a functional example of the INTR callback mechanism as Avi requested. Note that the work related to IF/NMI/TPR classification of interrupts happens later in my queue and is not mature enough to share yet, but hopefully soon.

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

drivers/kvm/condvar.c new file +2 -0
new file mode 100644
index 0000000..87e464a
@@ -0,0 +1,109 @@
+/*
+ * Condition Variable

drivers/kvm/condvar.c line 12

Quoted 10 lines
drivers/kvm/condvar.c new file +10 -0
+ *
+ * Copyright (C) 2007, Novell
+ *
+ * Authors:
+ *   Gregory Haskins <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */

If you want condition variables, activate your cryogenically-cooled suit and post on it on lkml. This cannot be added to the kernel via kvm.

Quoted 6 lines
drivers/kvm/condvar.c new file +1 -3
+
 	/*
-	 * FIXME: Implement this or the CPU wont notice the interrupt until
-	 * the next natural VMEXIT.  Note that this is how the system
-	 * has always worked, so nothing is broken here.  This is a future

drivers/kvm/condvar.c

Quoted 10 lines
drivers/kvm/condvar.c new file +9 -1
-	 * enhancement
+	 * HACK ALERT!
+	 *
+	 * We want to send a virtual interrupt signal to the task that owns
+	 * the guest.  However, the signal will only force a VMEXIT (via
+	 * a reschedule IPI) if the task is currently in GUEST mode.  There
+	 * is a race condition between the time that we mark the vcpu as
+	 * running and the time the system actually enter guest mode.  Since
+	 * there doesnt appear to be any way to help with this situation from
+	 * the VT hardware, we are forced to wait to make sure the guest 

We support AMD too.

drivers/kvm/condvar.c

Quoted 4 lines
drivers/kvm/condvar.c new file +3 -0
+	 * actually gets interrupted in a reasonable amount of time.  If it
+	 * does not, we assume that the IPI failed because it was too early
+	 * and must try again until it does.

Waiting seems totally broken. I'm not even sure what we are waiting for -- certainly you can't wait for re-entry into guest mode, since there's not guarantee that's coming. Many times the guest will be sleeping on a hlt instruction waiting for an interrupt.

If the guest is in guest mode, an IPI is right. If it is elsewhere, we need to use one of the many (alas) standard wakeup mechanisms to wake up userspace and let it know the vcpu needs service.

Qemu uses signals, but I think that making the vcpu fd writable is more generic. For qemu, we can attach a signal to the fd (using fcntl(2)); that has the benefit of leaving the choice of which signal to use to userspace.

Quoted 7 lines
drivers/kvm/condvar.c new file +5 -0
+	 *
+	 * This condvar/spinlock/timeout/retry eliminate the race in a safe
+	 * manner, at the expense of making the INTR delivery synchronous
 	 */
+	spin_lock(&vcpu->irq.lock);
+	

drivers/kvm/condvar.c

Quoted 10 lines
drivers/kvm/condvar.c new file +10 -0
+	if (vcpu->irq.task) {
+		struct timespec tmo = {
+			.tv_sec  = 0,
+			.tv_nsec = 100000 /* 100us */
+		};
+
+		BUG_ON(vcpu->irq.task == current);
+			
+		while (vcpu->irq.task) {
+			send_sig(SIGSTOP, vcpu->irq.task, 0);

SIGSTOP?! I lost the plot here.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

A message that is not in the archive (sent off-list or not yet received): 461DE791.1040707-atKUWr5tajBWk0Htik3J/[email protected]

#4 lore raw
Quoted 2 lines · Avi Kivity

If you want condition variables, activate your cryogenically-cooled suit and post on it on lkml. This cannot be added to the kernel via kvm.

Better just rip it out. The code would be a lot simpler with opencoded waitqueue use, and faster aswell due to getting rid of the indirect calls.

e.g. this:

+ if (vcpu->irq.task) {
+ struct timespec tmo = {
+ .tv_sec = 0,
+ .tv_nsec = 100000 /* 100us */
+ };
+
+ BUG_ON(vcpu->irq.task == current);
+
+ while (vcpu->irq.task) {
+ send_sig(SIGSTOP, vcpu->irq.task, 0);
+ condvar_wait(&vcpu->irq.cv, &vcpu->irq.lock,
+ timespec_to_jiffies(&tmo));
+ }
+
+ vcpu->irq.pending = 1;
+ }
+

would simply become

	if (vcpu->irq.task) {
		struct timespec tmo = {
			.tv_sec  = 0,
			.tv_nsec = 100000 /* 100us */
		};

		BUG_ON(vcpu->irq.task == current);
	
		for (;;) {
			send_sig(SIGSTOP, vcpu->irq.task, 0);
			prepare_to_wait(&vcpu->irq.wq, &wait,
					TASK_UNINTERRUPTIBLE);
			if (!vcpu->irq.task)
				break;
			spin_unlock(&vcpu->irq.lock);
			schedule_timeout(timespec_to_jiffies(&tmo));
			spin_lock(&vcpu->irq.lock);
		}
		finish_wait(&vcpu->irq.wq, &wait, TASK_UNINTERRUPTIBLE);

		vcpu->irq.pending = 1;
	}

with equal behaviour. although the send_sig in the loop and the very short sleep time still look rather odd to me.

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

#5 lore raw
In reply to a message not in the archive
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Thu, Apr 12, 2007 at 4:02 AM, in message <461DE791.1040707-atKUWr5tajBWk0Htik3J/[email protected]>,

Quoted 32 lines · Avi Kivity
Quoted 2 lines · Gregory Haskins

Hi All,
Attached are the first three patches in my queue. The first two you are

likely familiar with at this point (though I have made some more of the requested changes to 02- irqdevice.patch). The last item
(03- preemptible- cpu.patch) adds an implementation to the previously unused kvm_vcpu_intr() callback. This acts as a functional example of the INTR callback mechanism as Avi requested. Note that the work related to IF/NMI/TPR classification of interrupts happens later in my queue and is not mature enough to share yet, but hopefully soon.

Quoted 22 lines

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

diff -- git a/drivers/kvm/condvar.c b/drivers/kvm/condvar.c new file mode 100644
index 0000000..87e464a

drivers/kvm/condvar.c renamed from dev/null +0 -0

@@ - 0,0 +1,109 @@
+/*
+ * Condition Variable
+ *
+ * Copyright (C) 2007, Novell
+ *
+ * Authors:
+ * Gregory Haskins <[email protected]>
+ *

Quoted 8 lines
Quoted 5 lines

+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top- level directory.
+ *
+ */

If you want condition variables, activate your cryogenically- cooled suit and post on it on lkml. This cannot be added to the kernel via kvm.

Hehe. I wasn't aware of the contention surrounding them but that does explain why they are notably missing. I will rip it out this code in favor of a pure waitqueue as Christof suggested to avoid more controversy.

Quoted 13 lines
Quoted 13 lines
drivers/kvm/condvar.c renamed from dev/null +5 -4
+
 	/*
-	 * FIXME: Implement this or the CPU wont notice the interrupt until
-	 * the next natural VMEXIT.  Note that this is how the system
-	 * has always worked, so nothing is broken here.  This is a future
-	 * enhancement
+	 * HACK ALERT!
+	 *
+	 * We want to send a virtual interrupt signal to the task that owns
+	 * the guest.  However, the signal will only force a VMEXIT (via
Quoted 8 lines

drivers/kvm/condvar.c

Quoted 6 lines
drivers/kvm/condvar.c renamed from dev/null +5 -0
+	 * a reschedule IPI) if the task is currently in GUEST mode.  There
+	 * is a race condition between the time that we mark the vcpu as
+	 * running and the time the system actually enter guest mode.  Since
+	 * there doesnt appear to be any way to help with this situation from
+	 * the VT hardware, we are forced to wait to make sure the guest 

We support AMD too.

My patch actually supports both, and I didn't mean to infer that AMD was skipped. I was speaking generally when I said "VT". Is there a better term to refer to the concept of VMX/SVN?

Quoted 9 lines

drivers/kvm/condvar.c

Quoted 5 lines
drivers/kvm/condvar.c renamed from dev/null +3 -0
+	 * actually gets interrupted in a reasonable amount of time.  If it
+	 * does not, we assume that the IPI failed because it was too early
+	 * and must try again until it does.

Waiting seems totally broken. I'm not even sure what we are waiting for -- certainly you can't wait for re- entry into guest mode, since there's not guarantee that's coming.

Actually, there is ;) (unless I missed something) If you look at the other side of this implementation in vcpu_XXX_run(), I only set the vcpu->irq.task when the vcpu is just about to enter guest mode. And I clear it when it leaves. In other words, the kvn_vcpu_intr() function is a no-op if the vcpu is not in guest mode (or close to it).

Quoted 2 lines

If it is elsewhere, we need to use one of the many (alas) standard wakeup mechanisms to wake up userspace and let it know the vcpu needs service.

My code assumes we only need to kick the vcpu if its in guest mode because it figures it will just pick up the interrupt on the next run cycle otherwise. I haven't studied QEMU deep enough to know that it can suspend the execution of the run-cycle...i just thought it looped indefinitely. This makes sense now that I think about it because something like hlt should cause a suspension of CPU activity until further notice. If we need to be able to signal the vcpu *anytime* I will have to go back and refactor some things.

Quoted 5 lines

Qemu uses signals, but I think that making the vcpu fd writable is more generic. For qemu, we can attach a signal to the fd (using fcntl(2)); that has the benefit of leaving the choice of which signal to use to userspace.

Ack, I will look into this design.

Quoted 12 lines
Quoted 12 lines
drivers/kvm/condvar.c renamed from dev/null +10 -0
+	 *
+	 * This condvar/spinlock/timeout/retry eliminate the race in a safe
+	 * manner, at the expense of making the INTR delivery synchronous
 	 */
+	spin_lock(&vcpu- >irq.lock);
+	
+	if (vcpu- >irq.task) {
+		struct timespec tmo = {
+			.tv_sec  = 0,
+			.tv_nsec = 100000 /* 100us */
+		};
Quoted 8 lines

drivers/kvm/condvar.c

Quoted 6 lines
drivers/kvm/condvar.c renamed from dev/null +5 -0
+
+		BUG_ON(vcpu- >irq.task == current);
+			
+		while (vcpu- >irq.task) {
+			send_sig(SIGSTOP, vcpu- >irq.task, 0);

SIGSTOP?! I lost the plot here.

Well, I needed a signal to send that would reliably IPI the guest. I originally wrote the code to send RT signal 33 (which I defined as KVM_SIGNAL_VIRTUAL_INTERRUPT). In both cases, the design calls for sending a signal (purely for the IPI function of the kernel) and then to remove the signal before userspace sees it. I had some trouble with the code that used dequeue_signal() to strip out the RT signal. So I then changed to sending SIGSTOP to IPI, and SIGCONT to effectively strip out the pending SIGSTOP.

Keep in mind that this is really just proof-of-concept code. The general idea of this POC is to demonstrate how I envisioned the irqdevice API to be used to deliver interrupts even once concurrent access is possible (e.g., SMP/PV). The details of which signal are used, etc, are incidental for now until we agree that the irqdevice API approach is acceptable.

Regards,
-Greg

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw
Quoted 9 lines · Gregory Haskins
Quoted 5 lines
Quoted 2 lines

If you want condition variables, activate your cryogenically- cooled suit and post on it on lkml. This cannot be added to the kernel via kvm.

Hehe. I wasn't aware of the contention surrounding them but that does explain why they are notably missing. I will rip it out this code in favor of a pure waitqueue as Christof suggested to avoid more controversy.

Actually, I am in favor of having well-defined synchronization primitives. The only issues I see with condition variables are:

- there are many variants of mutexes in the kernel (mutex, spinlock, spinlock with irqs disabled, ...), so many condvar variants are needed.
- they're very close to waitqueues, so perhaps there's not much justification

I'm no synchronization primitive expert, though. My comment had nothing to do with my opinion on condition variables or your implementation thereof. kvm is simply not the place to introduce them.

Quoted 22 lines
Quoted 12 lines
Quoted 12 lines
drivers/kvm/kvm_main.c +5 -4
+
 	/*
-	 * FIXME: Implement this or the CPU wont notice the interrupt until
-	 * the next natural VMEXIT.  Note that this is how the system
-	 * has always worked, so nothing is broken here.  This is a future
-	 * enhancement
+	 * HACK ALERT!
+	 *
+	 * We want to send a virtual interrupt signal to the task that owns
+	 * the guest.  However, the signal will only force a VMEXIT (via
Quoted 9 lines

drivers/kvm/kvm_main.c static void kvm_vcpu_intr(struct kvm_irqsink *this, · line 2339

Quoted 7 lines
drivers/kvm/kvm_main.c +5 -0
+	 * a reschedule IPI) if the task is currently in GUEST mode.  There
+	 * is a race condition between the time that we mark the vcpu as
+	 * running and the time the system actually enter guest mode.  Since
+	 * there doesnt appear to be any way to help with this situation from
+	 * the VT hardware, we are forced to wait to make sure the guest 

We support AMD too.

Quoted 2 lines

My patch actually supports both, and I didn't mean to infer that AMD was skipped. I was speaking generally when I said "VT". Is there a better term to refer to the concept of VMX/SVN?

I referred to the comment. Maybe just "the hardware"?

Quoted 11 lines
Quoted 10 lines

drivers/kvm/kvm_main.c static void kvm_vcpu_intr(struct kvm_irqsink *this, · line 2342

Quoted 6 lines
drivers/kvm/kvm_main.c +3 -0
+	 * actually gets interrupted in a reasonable amount of time.  If it
+	 * does not, we assume that the IPI failed because it was too early
+	 * and must try again until it does.

Waiting seems totally broken. I'm not even sure what we are waiting for -- certainly you can't wait for re- entry into guest mode, since there's not guarantee that's coming.

Quoted 3 lines

Actually, there is ;) (unless I missed something) If you look at the other side of this implementation in vcpu_XXX_run(), I only set the vcpu->irq.task when the vcpu is just about to enter guest mode. And I clear it when it leaves. In other words, the kvn_vcpu_intr() function is a no-op if the vcpu is not in guest mode (or close to it).

Ah, ok -- I misunderstood the whole thing. The way to avoid the race is to disable interrupts before entering the guest. This way the IPI is delayed until you enter guest mode:

    irq_disable();

    spin_lock();
    vcpu->guest_mode = 1;
    check_whether_an_irq_is_pending_and_if_so_inject_it();
    spin_unlock();

    asm ("vm_entry_sequence");

    vcpu->guest_mode = 0;
   
    irq_enable(); // currently in the vm entry sequence

    // recheck here?

If the interrupt happens before the spin_lock(), we'll get a non-ipi wakeup and then see it in check_whether(). If it happens after it we'll get an IPI which will be ignored until we're snugly in guest mode.

Quoted 5 lines
Quoted 3 lines

If it is elsewhere, we need to use one of the many (alas) standard wakeup mechanisms to wake up userspace and let it know the vcpu needs service.

My code assumes we only need to kick the vcpu if its in guest mode because it figures it will just pick up the interrupt on the next run cycle otherwise. I haven't studied QEMU deep enough to know that it can suspend the execution of the run-cycle...i just thought it looped indefinitely.

In general I find it useful to pretend there are many userspaces being written for kvm, otherwise we get locked into qemu's current mode of operation.

Quoted 1 line

This makes sense now that I think about it because something like hlt should cause a suspension of CPU activity until further notice.

An alternative is to handle hlt in the kernel in a place where we're ready for the IPI wakeup. The downside to that is that we have to be prepared for external wakeup sources as well (signal, poll, aio... messy).

Quoted 22 lines
Quoted 12 lines
Quoted 12 lines
drivers/kvm/kvm_main.c +10 -0
+	 *
+	 * This condvar/spinlock/timeout/retry eliminate the race in a safe
+	 * manner, at the expense of making the INTR delivery synchronous
 	 */
+	spin_lock(&vcpu- >irq.lock);
+	
+	if (vcpu- >irq.task) {
+		struct timespec tmo = {
+			.tv_sec  = 0,
+			.tv_nsec = 100000 /* 100us */
+		};
Quoted 9 lines

Review

Quoted 7 lines
(quoted diff) +5 -0
+
+		BUG_ON(vcpu- >irq.task == current);
+			
+		while (vcpu- >irq.task) {
+			send_sig(SIGSTOP, vcpu- >irq.task, 0);

SIGSTOP?! I lost the plot here.

Quoted 3 lines

Well, I needed a signal to send that would reliably IPI the guest. I originally wrote the code to send RT signal 33 (which I defined as KVM_SIGNAL_VIRTUAL_INTERRUPT). In both cases, the design calls for sending a signal (purely for the IPI function of the kernel) and then to remove the signal before userspace sees it. I had some trouble with the code that used dequeue_signal() to strip out the RT signal. So I then changed to sending SIGSTOP to IPI, and SIGCONT to effectively strip out the pending SIGSTOP.

It's best not to use signals internally. Qemu relies on them and we have to support them, but in kernel we should use existing kernel mechanisms.

Quoted 2 lines

Keep in mind that this is really just proof-of-concept code. The general idea of this POC is to demonstrate how I envisioned the irqdevice API to be used to deliver interrupts even once concurrent access is possible (e.g., SMP/PV). The details of which signal are used, etc, are incidental for now until we agree that the irqdevice API approach is acceptable.

I was interested in how ->pending() and ->read_vector() and the raise callback interact, but got distracted by the, err, uniqueness of the signal thing.

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

A message that is not in the archive (sent off-list or not yet received): 461E2AD5.7070905-atKUWr5tajBWk0Htik3J/[email protected]

#9 lore raw

I have attached a new version of the patch which eliminates the condition variable (if only by name, anyway ;)

Quoted 1 line
Quoted 1 line
Quoted 1 line

On Thu, Apr 12, 2007 at 8:49 AM, in message <461E2AD5.7070905-atKUWr5tajBWk0Htik3J/[email protected]>,

Quoted 7 lines · Avi Kivity

Actually, I am in favor of having well- defined synchronization primitives. The only issues I see with condition variables are:

- there are many variants of mutexes in the kernel (mutex, spinlock, spinlock with irqs disabled, ...), so many condvar variants are needed.

Yeah, I tried to address that with lock_ops, but I agree.

Quoted 2 lines

- they're very close to waitqueues, so perhaps there's not much justification

Agreed they are very close. I won't go into my opinion of waitqueues vs cond-vars in this forum ;)

Quoted 4 lines

I'm no synchronization primitive expert, though. My comment had nothing to do with my opinion on condition variables or your implementation thereof. kvm is simply not the place to introduce them.

No problem. I think your argument is a good one.

Quoted 2 lines

I referred to the comment. Maybe just "the hardware"?

Done

Quoted 20 lines

Ah, ok -- I misunderstood the whole thing. The way to avoid the race is to disable interrupts before entering the guest. This way the IPI is delayed until you enter guest mode:

    irq_disable();

    spin_lock();
    vcpu- >guest_mode = 1;
    check_whether_an_irq_is_pending_and_if_so_inject_it();
    spin_unlock();

    asm ("vm_entry_sequence");

    vcpu- >guest_mode = 0;
   
    irq_enable(); // currently in the vm entry sequence

    // recheck here?
Quoted 3 lines

If the interrupt happens before the spin_lock(), we'll get a non- ipi wakeup and then see it in check_whether(). If it happens after it we'll get an IPI which will be ignored until we're snugly in guest mode.

When I first read this I thought "whoa! you want to disable interrupts during the whole time we are in GUEST mode?" But then it dawned on me what you are suggesting: Interrupts would be re-enabled after the context switch because we re-load the processor state? Cool! The thing I can't wrap my head around is what happens when the guest has IF=0 and and external interrupt comes in? Would we still exit?

But that aside, a problem that I see is that (IIUC) IPIs use NMIs not EXT-INTs. Assuming that is right, I suppose we might be able to do a similar trick except we also disable NMIs first (is this possible/recommended/forbidden?).

Quoted 4 lines

In general I find it useful to pretend there are many userspaces being written for kvm, otherwise we get locked into qemu's current mode of operation.

Sounds reasonable. I will start to do the same.

Quoted 7 lines
Quoted 2 lines

This makes sense now that I think about it because something like hlt should

cause a suspension of CPU activity until further notice.

An alternative is to handle hlt in the kernel in a place where we're ready for the IPI wakeup. The downside to that is that we have to be prepared for external wakeup sources as well (signal, poll, aio... messy).

Hmmm...interesting. I wonder if there are advantages that make this worth exploring. Oh well, I will back burner these thoughts until the SMP/PV/APIC stuff is sorted out.

Quoted 4 lines

It's best not to use signals internally. Qemu relies on them and we have to support them, but in kernel we should use existing kernel mechanisms.

But Avi, this was *your* idea to use signals ;) But in all seriousness, I don't know if I have a choice. I have two requirements which constrain me:

1) I need an IPI to cause a VMEXIT
2) I need to support 2.6.16, strongly preferable as a loadable module.

According to my research (which is undoubtedly not 100% definitive), 2.6.16 or even the newer kernels do not export most of the IPI facilities. send_sig() happens to be exported and it happens to invoke a reschedule_IPI under the hood, so its convenient. If there is another way to get access to the IPI facility without playing games with signals, I am all ears. But until then I don't know what else to do. If I had the luxury of modifying the kernel source, we could just export what we needed and be done with it.

Quoted 4 lines

I was interested in how - >pending() and - >read_vector() and the raise callback interact, but got distracted by the, err, uniqueness of the signal thing.

You still haven't weighed in here ;) Hopefully you have a clearer picture of what I was trying to do now at least. Whether you agree or not is another matter.

Regards,
-Greg

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

---

 drivers/kvm/kvm.h      |   11 ++++++++++
 drivers/kvm/kvm_main.c |   54 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/kvm/svm.c      |   35 +++++++++++++++++++++++++++++++
 drivers/kvm/vmx.c      |   35 +++++++++++++++++++++++++++++++
 4 files changed, 130 insertions(+), 5 deletions(-)
drivers/kvm/kvm.h +11 -0
index 58966d9..70d1bb9 100644
@@ -271,6 +271,16 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
 
+/*
+ * structure for maintaining info for interrupting an executing VCPU
+ */
+struct kvm_vcpu_irq {
+	spinlock_t          lock;
+	wait_queue_head_t   wq;
+	struct task_struct *task;
+	int                 pending;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -284,6 +294,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int interrupt_window_open;
 	struct kvm_irqdevice irq_dev;
+	struct kvm_vcpu_irq irq;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +49 -5

68 lines not on this page · raw message

drivers/kvm/svm.c +35 -0
index e59a548..41765bd 100644
@@ -1463,9 +1463,25 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	int r;
 
 again:
+	spin_lock(&vcpu->irq.lock);
+
+	/*
+	 * Setting vcpu->task signals to outsiders that the VMCS is 
+	 * effectively in GUEST mode, and therefore must be signalled
+	 * to transition the task back to HOST mode if any new interrupts
+	 * arrive.
+	 */
+	vcpu->irq.task = current;
+
+	/*
+	 * We also must inject interrupts (if any) while the irq_lock
+	 * is held
+	 */
 	if (!vcpu->mmio_read_completed)
 		do_interrupt_requests(vcpu, kvm_run);
 
+	spin_unlock(&vcpu->irq.lock);
+
 	clgi();
 
 	pre_svm_run(vcpu);
@@ -1617,6 +1633,25 @@ again:
 	reload_tss(vcpu);
 
 	/*
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.task = NULL;
+	wake_up(&vcpu->irq.wq);
+
+	/*
+	 * If irqpending is asserted someone undoubtedly has sent us a SIGSTOP
+	 * signal.  Counter it with a SIGCONT
+	 */
+	if(vcpu->irq.pending) {
+	    send_sig(SIGCONT, current, 0);
+	    vcpu->irq.pending = 0;
+	}
+
+	spin_unlock(&vcpu->irq.lock);
+
+	/*
 	 * Profile KVM exit RIPs:
 	 */
 	if (unlikely(prof_on == KVM_PROFILING))
drivers/kvm/vmx.c +35 -0
index a0fdf02..1d5ce85 100644
@@ -1748,9 +1748,25 @@ again:
 	vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
 #endif
 
+	spin_lock(&vcpu->irq.lock);
+
+	/*
+	 * Setting vcpu->task signals to outsiders that the VMCS is 
+	 * effectively in GUEST mode, and therefore must be signalled
+	 * to transition the task back to HOST mode if any new interrupts
+	 * arrive.
+	 */
+	vcpu->irq.task = current;
+
+	/*
+	 * We also must inject interrupts (if any) while the irq_lock
+	 * is held
+	 */
 	if (!vcpu->mmio_read_completed)
 		do_interrupt_requests(vcpu, kvm_run);
 
+	spin_unlock(&vcpu->irq.lock);
+
 	if (vcpu->guest_debug.enabled)
 		kvm_guest_debug_pre(vcpu);
 
@@ -1911,6 +1927,25 @@ again:
 
 	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
+	/*
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.task = NULL;
+	wake_up(&vcpu->irq.wq);
+
+	/*
+	 * If irqpending is asserted someone undoubtedly has sent us a SIGSTOP
+	 * signal.  Counter it with a SIGCONT
+	 */
+	if(vcpu->irq.pending) {
+	    send_sig(SIGCONT, current, 0);
+	    vcpu->irq.pending = 0;
+	}
+
+	spin_unlock(&vcpu->irq.lock);
+
 	if (fail) {
 		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		kvm_run->fail_entry.hardware_entry_failure_reason

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#11 lore raw
Quoted 18 lines · Gregory Haskins
Quoted 18 lines

Ah, ok -- I misunderstood the whole thing. The way to avoid the race is to disable interrupts before entering the guest. This way the IPI is delayed until you enter guest mode:

    irq_disable();

    spin_lock();
    vcpu- >guest_mode = 1;
    check_whether_an_irq_is_pending_and_if_so_inject_it();
    spin_unlock();

    asm ("vm_entry_sequence");

    vcpu- >guest_mode = 0;
   
    irq_enable(); // currently in the vm entry sequence
Quoted 9 lines
Quoted 6 lines
    // recheck here?

If the interrupt happens before the spin_lock(), we'll get a non- ipi wakeup and then see it in check_whether(). If it happens after it we'll get an IPI which will be ignored until we're snugly in guest mode.

When I first read this I thought "whoa! you want to disable interrupts during the whole time we are in GUEST mode?" But then it dawned on me what you are suggesting: Interrupts would be re-enabled after the context switch because we re-load the processor state? Cool! The thing I can't wrap my head around is what happens when the guest has IF=0 and and external interrupt comes in? Would we still exit?

It's really subtle.

With respect to interrupts, VT^H^Hthe hardware provides an override over IF. If an interrupt happens while this override is enabled, we exit guest mode regardless of the state of IF. In effect interrupts are enabled but _delivery_ is disabled. Once we exit guest mode, interrupts become disabled again until we set IF explicitly.

Quoted 3 lines

But that aside, a problem that I see is that (IIUC) IPIs use NMIs not EXT-INTs. Assuming that is right, I suppose we might be able to do a similar trick except we also disable NMIs first (is this possible/recommended/forbidden?).

IPIs are maskable, but are not exactly EXT-INT, I think.

Quoted 9 lines
Quoted 4 lines

It's best not to use signals internally. Qemu relies on them and we have to support them, but in kernel we should use existing kernel mechanisms.

But Avi, this was *your* idea to use signals ;) But in all seriousness, I don't know if I have a choice. I have two requirements which constrain me:

1) I need an IPI to cause a VMEXIT

kick_process() can do that in guest mode. Or even smp_call_function_single(). Outside guest mode, we do need a signal, but having it requested via fcntl() seems more flexible to me.

Starting out with a hardcoded signal (and no special treatment for guest mode) is okay to get things rolling.

Quoted 5 lines

2) I need to support 2.6.16, strongly preferable as a loadable module.

According to my research (which is undoubtedly not 100% definitive), 2.6.16 or even the newer kernels do not export most of the IPI facilities. send_sig() happens to be exported and it happens to invoke a reschedule_IPI under the hood, so its convenient. If there is another way to get access to the IPI facility without playing games with signals, I am all ears. But until then I don't know what else to do. If I had the luxury of modifying the kernel source, we could just export what we needed and be done with it.

Look at the magic that is kernel/external-module-compat.h and the 'sync' target of kernel/Makefile.

The idea is that mainline kernel code is as clear and as use-the-bleedingest-edge-apis as we want, with the external module code brutally hacked into something that will compile on older kernels. We go as far back as 2.6.9 IIRC.

Quoted 7 lines
Quoted 4 lines

I was interested in how - >pending() and - >read_vector() and the raise callback interact, but got distracted by the, err, uniqueness of the signal thing.

You still haven't weighed in here ;) Hopefully you have a clearer picture of what I was trying to do now at least. Whether you agree or not is another matter.

My eyes were clouded by the signal thing :)

Signature · 8 lines
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

A message that is not in the archive (sent off-list or not yet received): 461E3EDB.3080002-atKUWr5tajBWk0Htik3J/[email protected]

#13 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Thu, Apr 12, 2007 at 10:14 AM, in message <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/[email protected]>,

Quoted 8 lines · Avi Kivity

It's really subtle.

With respect to interrupts, VT^H^Hthe hardware provides an override over IF. If an interrupt happens while this override is enabled, we exit guest mode regardless of the state of IF. In effect interrupts are enabled but _delivery_ is disabled. Once we exit guest mode, interrupts become disabled again until we set IF explicitly.

Heres a version that implements that idea. Note that its still a POC, as the kick_process still needs to be exported and handled in extern-module-compat (or whatever its called)

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

---

 drivers/kvm/kvm.h      |   14 +++++++++++++
 drivers/kvm/kvm_main.c |   50 ++++++++++++++++++++++++++++++++++++++++++------
 drivers/kvm/svm.c      |   43 +++++++++++++++++++++++++++++++++++++++++
 drivers/kvm/vmx.c      |   47 +++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 146 insertions(+), 8 deletions(-)
drivers/kvm/kvm.h +14 -0
index 58966d9..56a3d58 100644
@@ -271,6 +271,19 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
 
+#define KVM_SIGNAL_VIRTUAL_INTERRUPT 33 /* Hardcoded for now */
+
+/*
+ * structure for maintaining info for interrupting an executing VCPU
+ */
+struct kvm_vcpu_irq {
+	spinlock_t          lock;
+	struct task_struct *task;
+	int                 signo;
+	int                 guest_mode;
+	int                 pending;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -284,6 +297,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int interrupt_window_open;
 	struct kvm_irqdevice irq_dev;
+	struct kvm_vcpu_irq irq;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +44 -6

69 lines not on this page · raw message

drivers/kvm/svm.c +43 -0

66 lines not on this page · raw message

drivers/kvm/vmx.c +45 -2

74 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

#14 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Thu, Apr 12, 2007 at 12:01 PM, in message <[email protected]>,

Quoted 11 lines · Gregory Haskins
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Thu, Apr 12, 2007 at 10:14 AM, in message <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/[email protected]>,

Quoted 8 lines · Avi Kivity

It's really subtle.

With respect to interrupts, VT^H^Hthe hardware provides an override over IF. If an interrupt happens while this override is enabled, we exit guest mode regardless of the state of IF. In effect interrupts are enabled but _delivery_ is disabled. Once we exit guest mode, interrupts become disabled again until we set IF explicitly.

Quoted 3 lines

Heres a version that implements that idea. Note that its still a POC, as the kick_process still needs to be exported and handled in extern-module-compat (or whatever its called)

Here are more refinements to this logic which make it actually usable. It turns out that smp_call_function_single() is exported under at least 2.6.16 (perhaps even earlier, not sure) so I refactored the code to use that instead of kick_process() (thanks for the hint, Avi).

I also added checks so that the current task doesn't unnecessarily signal itself (this covers the case we would hit today with the interrupt controller still in QEMU). Also, we check to see if there are any signals pending before VMENTER as an optimization.

Comments please.

Regards,
-Greg

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

---

 drivers/kvm/kvm.h      |   14 +++++++++
 drivers/kvm/kvm_main.c |   77 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/kvm/svm.c      |   54 ++++++++++++++++++++++++++++++++++
 drivers/kvm/vmx.c      |   58 +++++++++++++++++++++++++++++++++++-
 4 files changed, 195 insertions(+), 8 deletions(-)
drivers/kvm/kvm.h +14 -0
index 58966d9..56a3d58 100644
@@ -271,6 +271,19 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
 
+#define KVM_SIGNAL_VIRTUAL_INTERRUPT 33 /* Hardcoded for now */
+
+/*
+ * structure for maintaining info for interrupting an executing VCPU
+ */
+struct kvm_vcpu_irq {
+	spinlock_t          lock;
+	struct task_struct *task;
+	int                 signo;
+	int                 guest_mode;
+	int                 pending;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -284,6 +297,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int interrupt_window_open;
 	struct kvm_irqdevice irq_dev;
+	struct kvm_vcpu_irq irq;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +71 -6

102 lines not on this page · raw message

drivers/kvm/svm.c +54 -0

77 lines not on this page · raw message

drivers/kvm/vmx.c +56 -2

85 lines not on this page · raw message

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#16 lore raw
Quoted 11 lines · Gregory Haskins
Quoted 8 lines

It's really subtle.

With respect to interrupts, VT^H^Hthe hardware provides an override over IF. If an interrupt happens while this override is enabled, we exit guest mode regardless of the state of IF. In effect interrupts are enabled but _delivery_ is disabled. Once we exit guest mode, interrupts become disabled again until we set IF explicitly.

Heres a version that implements that idea. Note that its still a POC, as the kick_process still needs to be exported and handled in extern-module-compat (or whatever its called)

Hopefully Ingo will ack such a patch, as he suggested kick_process() originally.

Quoted 8 lines
drivers/kvm/kvm_main.c +4 -0
@@ -1866,6 +1874,19 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		kvm_arch_ops->decache_regs(vcpu);
 	}
 
+	/*
+	 * Make sure the current task is accurately recorded.  Most of the 
+	 * time, it will be so we first check if its necessary without taking
+	 * the lock.  If there is a mismatch, we must aquire the lock and 

drivers/kvm/kvm_main.c static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) · line 1890

Quoted 10 lines
drivers/kvm/kvm_main.c +9 -0
+	 * check again to eliminate races
+	 */
+	if (unlikely(vcpu->irq.task != current)) {
+		spin_lock(&vcpu->irq.lock);
+		if (vcpu->irq.task != current)
+			vcpu->irq.task = current;
+		spin_unlock(&vcpu->irq.lock);
+	}
+
 

Isn't this equivalent to

    vcpu->irq.task = current

?

btw, these double-check things are broken, see
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.
It will usually work on x86, and can be made to work elsewhere with memory barriers, but it's less simple than it appears.

Review static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) · line 1892

Quoted 2 lines
(quoted diff) +1 -0
+	 * FIXME: Do we need to do anything additional to mask IPI/NMIs? 
 

I'm fairly certain you don't. I keep hearing about the deadlockability of sending ipis with interrupts disabled.

Quoted 12 lines
drivers/kvm/svm.c +11 -0
+	 */
+	local_irq_save(irq_flags);
+
+	spin_lock(&vcpu->irq.lock);
+
+	/*
+	 * There are optimizations we can make when signaling interrupts
+	 * if we know the VCPU is in GUEST mode, so mark that here
+	 */
+	vcpu->irq.guest_mode = 1;
+

drivers/kvm/svm.c static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) · line 1495

Quoted 10 lines
drivers/kvm/svm.c +6 -0
+	/*
+	 * We also must inject interrupts (if any) while the irq_lock
+	 * is held
+	 */
 	if (!vcpu->mmio_read_completed)
 		do_interrupt_requests(vcpu, kvm_run);
 
+	spin_unlock(&vcpu->irq.lock);
+
 	clgi();

stgi() / clgi() is what implements interrupt handling under svm. I think you got this right, but please tell me you read the relevant sections in the manual a few times.

Quoted 4 lines
drivers/kvm/svm.c +0 -0
@@ -1617,6 +1650,16 @@ again:
 	reload_tss(vcpu);
 
 	/*

drivers/kvm/svm.c again: · line 1662

Quoted 10 lines
drivers/kvm/svm.c +9 -0
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.guest_mode = 0;
+	vcpu->irq.pending = 0;
+	
+	spin_unlock(&vcpu->irq.lock);
+
 

If an interrupt happened just before here, then we need to check it, otherwise it's lost. Also an opportunity to see ->read_vector in action, which was the purpose of the exercise IIRC.

Quoted 7 lines
drivers/kvm/vmx.c +3 -0
 	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
+	/*
+	 * Signal that we have transitioned back to host mode 
+	 */

drivers/kvm/vmx.c again: · line 1959

Quoted 10 lines
drivers/kvm/vmx.c +7 -0
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.guest_mode = 0;
+	vcpu->irq.pending = 0;
+
+	spin_unlock(&vcpu->irq.lock);
+
 	if (fail) {
 		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		kvm_run->fail_entry.hardware_entry_failure_reason

Ditto.

You also want spin_lock_irq() when interrupts are enabled, since some callers will lock it in interrupt context.

Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic.


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

A message that is not in the archive (sent off-list or not yet received): 4620E56A.7040207-atKUWr5tajBWk0Htik3J/[email protected]

#18 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Sat, Apr 14, 2007 at 10:30 AM, in message <4620E56A.7040207-atKUWr5tajBWk0Htik3J/[email protected]>,

Quoted 10 lines · Avi Kivity
Quoted 9 lines · Gregory Haskins
Quoted 8 lines

It's really subtle.

With respect to interrupts, VT^H^Hthe hardware provides an override over IF. If an interrupt happens while this override is enabled, we exit guest mode regardless of the state of IF. In effect interrupts are enabled but _delivery_ is disabled. Once we exit guest mode, interrupts become disabled again until we set IF explicitly.

Quoted 7 lines
Quoted 1 line

Heres a version that implements that idea. Note that its still a POC, as

the kick_process still needs to be exported and handled in extern-module-compat (or whatever its called)

Quoted 1 line

Hopefully Ingo will ack such a patch, as he suggested kick_process() originally.

Out of curiosity, did you review my kick_process() version or the newer smp_call_function_single() based version of the patch?

Quoted 24 lines

Review static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu,

Quoted 3 lines
(quoted diff) +0 -0
@@ -1866,6 +1874,19 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, 

struct kvm_run *kvm_run)

Quoted 7 lines
drivers/kvm/kvm_main.c +4 -0
 		kvm_arch_ops->decache_regs(vcpu);
 	}
 
+	/*
+	 * Make sure the current task is accurately recorded.  Most of the 
+	 * time, it will be so we first check if its necessary without taking
+	 * the lock.  If there is a mismatch, we must aquire the lock and 

drivers/kvm/kvm_main.c static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) · line 1891

Quoted 10 lines
drivers/kvm/kvm_main.c +9 -0
+	 * check again to eliminate races
+	 */
+	if (unlikely(vcpu->irq.task != current)) {
+		spin_lock(&vcpu->irq.lock);
+		if (vcpu->irq.task != current)
+			vcpu->irq.task = current;
+		spin_unlock(&vcpu->irq.lock);
+	}
+
 

Isn't this equivalent to

Quoted 1 line
    vcpu->irq.task = current

Yeah, good point. I originally had a printk in there to report when it changes, thus the conditional. I didn't collapse it when I took the printk out. I suppose you could argue that updating the variable indiscriminately will unnecessarily dirty a cache-line, but I doubt it would matter in the grand scheme of things.

Quoted 7 lines

?

btw, these double-check things are broken, see
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.
It will usually work on x86, and can be made to work elsewhere with memory barriers, but it's less simple than it appears.

Interesting. Thanks for the link!

Quoted 3 lines

stgi() / clgi() is what implements interrupt handling under svm. I think you got this right, but please tell me you read the relevant sections in the manual a few times.

Actually, no. I have read the VMX doc pretty thoroughly but I haven't looked at the SVN doc at all yet. I'm still drinking from a fire hose between VMX, KVM, QEMU etc. ;) I will certainly rectify this situation before I submit the patch for actual inclusion. If I do anything particularly egregious in SVN, pointers are more than welcome.

Quoted 5 lines
Quoted 5 lines
drivers/kvm/svm.c +0 -0
@@ -1617,6 +1650,16 @@ again:
 	reload_tss(vcpu);
 
Quoted 15 lines

drivers/kvm/svm.c again:

Quoted 11 lines
drivers/kvm/svm.c +9 -0
 	/*
+	 * Signal that we have transitioned back to host mode 
+	 */
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.guest_mode = 0;
+	vcpu->irq.pending = 0;
+	
+	spin_unlock(&vcpu->irq.lock);
+
 

If an interrupt happened just before here, then we need to check it, otherwise it's lost. Also an opportunity to see ->read_vector in action, which was the purpose of the exercise IIRC.

I'm not sure if you noticed this, but the read_vector() call already happened as part of the do_interrupt_requests() call before the VMENTRY (assuming you have applied the previous patch in the series, of course ;). You would never "lose" the interrupt even if the interrupt came in before the critical section because it would be safely queued in the irqdevice model for the next pass through the run() loop. However, you do highlight a bug in this code that could cause the interrupt to be deferred indefinitely until a second interrupt came in if the processor happens to halt after this VMEXIT. I.e., since a signal isn't being delivered while in irq.guest_mode = 1, we do need to handle this at this layer by looping back into the CPU. I will fix this. Good find!

Quoted 21 lines
Quoted 8 lines
drivers/kvm/vmx.c +3 -0
 	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 
+	/*
+	 * Signal that we have transitioned back to host mode 
+	 */

drivers/kvm/vmx.c again: · line 1959

Quoted 10 lines
drivers/kvm/vmx.c +7 -0
+	spin_lock(&vcpu->irq.lock);
+
+	vcpu->irq.guest_mode = 0;
+	vcpu->irq.pending = 0;
+
+	spin_unlock(&vcpu->irq.lock);
+
 	if (fail) {
 		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
 		kvm_run->fail_entry.hardware_entry_failure_reason

Ditto.

Quoted 3 lines

You also want spin_lock_irq() when interrupts are enabled, since some callers will lock it in interrupt context.

Good catch. I forgot to update the locks after the changeover to disabling IRQs.

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

#19 lore raw
Quoted 1 line
Quoted 1 line
Quoted 1 line

On Sun, Apr 15, 2007 at 6:32 PM, in message <[email protected]>,

Quoted 5 lines · Gregory Haskins

However, you do highlight a bug in this code that could cause the interrupt to be deferred indefinitely until a second interrupt came in if the processor happens to halt after this VMEXIT. I.e., since a signal isn't being delivered while in irq.guest_mode = 1, we do need to handle this at this layer by looping back into the CPU.

I think I misspoke. I inspected the code after writing this and realized that I think it was fine the way it was. The point of confusion I think was the irq.pending flag, which really wasn't doing anything useful in this context. But other than the superfluous variable, I think the design would work as it was written. Basically, the calls to pending/read_vector would indicate the appropriate vector to inject...so all we really need is a "kick" via the IPI to knock the task out of GUEST mode (if applicable). Once that happens, the normal processing will pick up on the posted vector, even if a HLT were in progress.

I removed the irq.pending flag for clarity. If I truly need it downstream in my patch series I will add it there.

Attached is an updated patch incorporating the latest feedback.

Regards,
-Greg

KVM: Preemptible VCPU

From: <>

This adds support for interrupting an executing CPU

---

 drivers/kvm/kvm.h      |   13 +++++++++
 drivers/kvm/kvm_main.c |   68 ++++++++++++++++++++++++++++++++++++++++++++----
 drivers/kvm/svm.c      |   51 ++++++++++++++++++++++++++++++++++++
 drivers/kvm/vmx.c      |   55 +++++++++++++++++++++++++++++++++++++--
 4 files changed, 179 insertions(+), 8 deletions(-)
drivers/kvm/kvm.h +13 -0
index 58966d9..87357cc 100644
@@ -271,6 +271,18 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
 
 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
 
+#define KVM_SIGNAL_VIRTUAL_INTERRUPT 33 /* Hardcoded for now */
+
+/*
+ * structure for maintaining info for interrupting an executing VCPU
+ */
+struct kvm_vcpu_irq {
+	spinlock_t          lock;
+	struct task_struct *task;
+	int                 signo;
+	int                 guest_mode;
+};
+
 struct kvm_vcpu {
 	struct kvm *kvm;
 	union {
@@ -284,6 +296,7 @@ struct kvm_vcpu {
 	struct kvm_run *run;
 	int interrupt_window_open;
 	struct kvm_irqdevice irq_dev;
+	struct kvm_vcpu_irq irq;
 	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
 	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
 
drivers/kvm/kvm_main.c +62 -6

99 lines not on this page · raw message

drivers/kvm/svm.c +51 -0

74 lines not on this page · raw message

drivers/kvm/vmx.c +53 -2

82 lines not on this page · raw message

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

_______________________________________________
kvm-devel mailing list [email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#21 lore raw
Quoted 3 lines · Gregory Haskins

Out of curiosity, did you review my kick_process() version or the newer smp_call_function_single() based version of the patch?

The former.

Quoted 25 lines
Quoted 25 lines

Review static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, · line 1874

Quoted 3 lines
(quoted diff) +0 -0
@@ -1866,6 +1874,19 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, 
 

struct kvm_run *kvm_run)

Quoted 8 lines
drivers/kvm/kvm_main.c +5 -0
 		kvm_arch_ops->decache_regs(vcpu);
 	}
 
+	/*
+	 * Make sure the current task is accurately recorded.  Most of the 
+	 * time, it will be so we first check if its necessary without taking
+	 * the lock.  If there is a mismatch, we must aquire the lock and 
+	 * check again to eliminate races

drivers/kvm/kvm_main.c static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)

Quoted 10 lines
drivers/kvm/kvm_main.c +8 -0
+	 */
+	if (unlikely(vcpu->irq.task != current)) {
+		spin_lock(&vcpu->irq.lock);
+		if (vcpu->irq.task != current)
+			vcpu->irq.task = current;
+		spin_unlock(&vcpu->irq.lock);
+	}
+
 
 

Isn't this equivalent to

Quoted 6 lines
Quoted 2 lines
    vcpu->irq.task = current

Yeah, good point. I originally had a printk in there to report when it changes, thus the conditional. I didn't collapse it when I took the printk out. I suppose you could argue that updating the variable indiscriminately will unnecessarily dirty a cache-line, but I doubt it would matter in the grand scheme of things.

The vcpu cachelines are already dirty.

Please repost the patchset (one patch per message) so I can see it together. Thanks.

Signature · 8 lines
Do not meddle in the internals of kernels, for they are subtle and quick to panic.


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/