From: "Gregory Haskins" <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
To: "Avi Kivity" <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: Re: irqdevice INTR example
Date: Thu, 12 Apr 2007 12:01:09 -0400 [thread overview]
Message-ID: <461E1F73.BA47.005A.0@novell.com> (raw)
In-Reply-To: <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 729 bytes --]
>>> On Thu, Apr 12, 2007 at 10:14 AM, in message <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/w@public.gmane.org>,
Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org> wrote:
>
> 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)
[-- Attachment #2: preemptible-cpu-3.patch --]
[-- Type: text/plain, Size: 8176 bytes --]
KVM: Preemptible VCPU
From: <>
This adds support for interrupting an executing CPU
Signed-off-by: Gregory Haskins <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
---
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(-)
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 58966d9..56a3d58 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -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() */
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 7e00412..d2a9025 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -299,6 +299,14 @@ static struct kvm *kvm_create_vm(void)
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
mutex_init(&vcpu->mutex);
+
+ memset(&vcpu->irq, 0, sizeof(vcpu->irq));
+ spin_lock_init(&vcpu->irq.lock);
+ /*
+ * This should be settable by userspace someday
+ */
+ vcpu->irq.signo = KVM_SIGNAL_VIRTUAL_INTERRUPT;
+
vcpu->cpu = -1;
vcpu->kvm = kvm;
vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -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
+ * 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);
+ }
+
r = kvm_arch_ops->run(vcpu, kvm_run);
out:
@@ -2320,13 +2341,30 @@ static void kvm_vcpu_intr(struct kvm_irqsink *this,
* Our irq device is requesting to interrupt the vcpu. If it is
* currently running, we should inject a host IPI to force a VMEXIT
*/
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu*)this->private;
+
+ spin_lock(&vcpu->irq.lock);
- /*
- * 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
- */
+ if (vcpu->irq.task) {
+ if (vcpu->irq.guest_mode)
+ /*
+ * If we are in guest mode, we can optimize the IPI
+ * by only waking the vcpu.
+ */
+ kick_process(vcpu->irq.task);
+ else
+ /*
+ * If we are not in guest mode, we must assume that
+ * we could be blocked anywhere, including userspace.
+ * Send a signal to give everyone a chance to get
+ * notification
+ */
+ send_sig(vcpu->irq.signo, vcpu->irq.task, 0);
+
+ vcpu->irq.pending = 1;
+ }
+
+ spin_unlock(&vcpu->irq.lock);
}
static void kvm_vcpu_irqsink_init(struct kvm_vcpu *vcpu)
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index e59a548..641e8e4 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1461,11 +1461,37 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
u16 gs_selector;
u16 ldt_selector;
int r;
+ unsigned long irq_flags;
again:
+ /*
+ * We disable interrupts until the next VMEXIT to eliminate a race
+ * condition for delivery of virtual interrutps. Note that this is
+ * probably not as bad as it sounds, as interrupts will invoke a
+ * VMEXIT once transitioned to GUEST mode (and thus exit this lock
+ * scope) even if they are disabled.
+ *
+ * FIXME: Do we need to do anything additional to mask IPI/NMIs?
+ */
+ 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;
+
+ /*
+ * 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);
@@ -1597,6 +1623,13 @@ again:
#endif
: "cc", "memory" );
+ /*
+ * FIXME: We'd like to turn on interrupts ASAP, but is this so early
+ * that we will mess up the state of the CPU before we fully
+ * transition from guest to host?
+ */
+ local_irq_restore(irq_flags);
+
fx_save(vcpu->guest_fx_image);
fx_restore(vcpu->host_fx_image);
@@ -1617,6 +1650,16 @@ again:
reload_tss(vcpu);
/*
+ * 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);
+
+ /*
* Profile KVM exit RIPs:
*/
if (unlikely(prof_on == KVM_PROFILING))
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index a0fdf02..b67ad9e 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1722,6 +1722,7 @@ static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
u16 fs_sel, gs_sel, ldt_sel;
int fs_gs_ldt_reload_needed;
int r;
+ unsigned long irq_flags;
again:
/*
@@ -1748,11 +1749,36 @@ again:
vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
#endif
+ if (vcpu->guest_debug.enabled)
+ kvm_guest_debug_pre(vcpu);
+
+ /*
+ * We disable interrupts until the next VMEXIT to eliminate a race
+ * condition for delivery of virtual interrutps. Note that this is
+ * probably not as bad as it sounds, as interrupts will invoke a
+ * VMEXIT once transitioned to GUEST mode (and thus exit this lock
+ * scope) even if they are disabled.
+ *
+ * FIXME: Do we need to do anything additional to mask IPI/NMIs?
+ */
+ 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;
+
+ /*
+ * We also must inject interrupts (if any) while the irq.lock
+ * is held
+ */
if (!vcpu->mmio_read_completed)
do_interrupt_requests(vcpu, kvm_run);
- if (vcpu->guest_debug.enabled)
- kvm_guest_debug_pre(vcpu);
+ spin_unlock(&vcpu->irq.lock);
fx_save(vcpu->host_fx_image);
fx_restore(vcpu->guest_fx_image);
@@ -1880,6 +1906,13 @@ again:
: "cc", "memory" );
/*
+ * FIXME: We'd like to turn on interrupts ASAP, but is this so early
+ * that we will mess up the state of the CPU before we fully
+ * transition from guest to host?
+ */
+ local_irq_restore(irq_flags);
+
+ /*
* Reload segment selectors ASAP. (it's needed for a functional
* kernel: x86 relies on having __KERNEL_PDA in %fs and x86_64
* relies on having 0 in %gs for the CPU PDA to work.)
@@ -1911,6 +1944,16 @@ 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.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
[-- Attachment #3: Type: text/plain, Size: 345 bytes --]
-------------------------------------------------------------------------
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
[-- Attachment #4: Type: text/plain, Size: 186 bytes --]
_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel
next prev parent reply other threads:[~2007-04-12 16:01 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-12 4:02 irqdevice INTR example Gregory Haskins
[not found] ` <461D7702.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-04-12 8:02 ` Avi Kivity
[not found] ` <461DE791.1040707-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-04-12 8:18 ` Christoph Hellwig
2007-04-12 11:55 ` Gregory Haskins
[not found] ` <461DE5C9.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-04-12 12:49 ` Avi Kivity
[not found] ` <461E2AD5.7070905-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-04-12 13:43 ` Gregory Haskins
[not found] ` <461DFF1C.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-04-12 14:14 ` Avi Kivity
[not found] ` <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-04-12 16:01 ` Gregory Haskins [this message]
2007-04-13 13:05 ` Fwd: " Gregory Haskins
[not found] ` <461E1F73.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-04-14 14:30 ` Avi Kivity
[not found] ` <4620E56A.7040207-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-04-15 22:32 ` Gregory Haskins
2007-04-15 23:32 ` Gregory Haskins
[not found] ` <46226FBC.BA47.005A.0-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
2007-04-16 5:46 ` Avi Kivity
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=461E1F73.BA47.005A.0@novell.com \
--to=ghaskins-et1tbqhtxzrqt0dzr+alfa@public.gmane.org \
--cc=avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org \
--cc=kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox