From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Gregory Haskins" Subject: Re: irqdevice INTR example Date: Thu, 12 Apr 2007 12:01:09 -0400 Message-ID: <461E1F73.BA47.005A.0@novell.com> References: <461D7702.BA47.005A.0@novell.com> <461DE791.1040707@qumranet.com> <461DE5C9.BA47.005A.0@novell.com> <461E2AD5.7070905@qumranet.com> <461DFF1C.BA47.005A.0@novell.com> <461E3EDB.3080002@qumranet.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__PartB295E7D5.0__=" Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org To: "Avi Kivity" Return-path: In-Reply-To: <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/w@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org Errors-To: kvm-devel-bounces-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org List-Id: kvm.vger.kernel.org --=__PartB295E7D5.0__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline >>> On Thu, Apr 12, 2007 at 10:14 AM, in message <461E3EDB.3080002-atKUWr5tajBWk0Htik3J/w@public.gmane.org>, Avi Kivity 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) --=__PartB295E7D5.0__= Content-Type: text/plain; name="preemptible-cpu-3.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="preemptible-cpu-3.patch" KVM: Preemptible VCPU From: <> This adds support for interrupting an executing CPU Signed-off-by: Gregory Haskins --- 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, =20 #define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long) =20 +#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() */ =20 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 =3D &kvm->vcpus[i]; =20 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 =3D KVM_SIGNAL_VIRTUAL_INTERRUPT; + vcpu->cpu =3D -1; vcpu->kvm =3D kvm; vcpu->mmu.root_hpa =3D 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); } =20 + /* + * Make sure the current task is accurately recorded. Most of = the=20 + * 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=20 + * check again to eliminate races + */ + if (unlikely(vcpu->irq.task !=3D current)) { + spin_lock(&vcpu->irq.lock); + if (vcpu->irq.task !=3D current) + vcpu->irq.task =3D current; + spin_unlock(&vcpu->irq.lock); + } + r =3D kvm_arch_ops->run(vcpu, kvm_run); =20 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=20 */ + struct kvm_vcpu *vcpu =3D (struct kvm_vcpu*)this->private; + + spin_lock(&vcpu->irq.lock); =09 - /* - * 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 =3D 1; + } +=09 + spin_unlock(&vcpu->irq.lock); } =20 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; =20 again: + /* + * We disable interrupts until the next VMEXIT to eliminate a = race=20 + * 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=20 + * scope) even if they are disabled. + * + * FIXME: Do we need to do anything additional to mask IPI/NMIs?=20= + */ + 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 =3D 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); =20 + spin_unlock(&vcpu->irq.lock); + clgi(); =20 pre_svm_run(vcpu); @@ -1597,6 +1623,13 @@ again: #endif : "cc", "memory" ); =20 + /* + * 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=20 + * transition from guest to host? + */ + local_irq_restore(irq_flags); + fx_save(vcpu->guest_fx_image); fx_restore(vcpu->host_fx_image); =20 @@ -1617,6 +1650,16 @@ again: reload_tss(vcpu); =20 /* + * Signal that we have transitioned back to host mode=20 + */ + spin_lock(&vcpu->irq.lock); + + vcpu->irq.guest_mode =3D 0; + vcpu->irq.pending =3D 0; +=09 + spin_unlock(&vcpu->irq.lock); + + /* * Profile KVM exit RIPs: */ if (unlikely(prof_on =3D=3D 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; =20 again: /* @@ -1748,11 +1749,36 @@ again: vmcs_writel(HOST_GS_BASE, segment_base(gs_sel)); #endif =20 + if (vcpu->guest_debug.enabled) + kvm_guest_debug_pre(vcpu); + + /* + * We disable interrupts until the next VMEXIT to eliminate a = race=20 + * 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=20 + * scope) even if they are disabled. + * + * FIXME: Do we need to do anything additional to mask IPI/NMIs?=20= + */ + 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 =3D 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); =20 - if (vcpu->guest_debug.enabled) - kvm_guest_debug_pre(vcpu); + spin_unlock(&vcpu->irq.lock); =20 fx_save(vcpu->host_fx_image); fx_restore(vcpu->guest_fx_image); @@ -1880,6 +1906,13 @@ again: : "cc", "memory" ); =20 /* + * 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=20 + * 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: =20 asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); =20 + /* + * Signal that we have transitioned back to host mode=20 + */ + spin_lock(&vcpu->irq.lock); + + vcpu->irq.guest_mode =3D 0; + vcpu->irq.pending =3D 0; + + spin_unlock(&vcpu->irq.lock); + if (fail) { kvm_run->exit_reason =3D KVM_EXIT_FAIL_ENTRY; kvm_run->fail_entry.hardware_entry_failure_reason --=__PartB295E7D5.0__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- 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 --=__PartB295E7D5.0__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kvm-devel mailing list kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/kvm-devel --=__PartB295E7D5.0__=--