qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Amit Shah <amit.shah@qumranet.com>
To: kvm-devel@lists.sourceforge.net
Cc: Amit Shah <amit.shah@qumranet.com>, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 2/2] KVM Userspace: IRQ injection into guest
Date: Wed,  7 Nov 2007 21:45:13 +0200	[thread overview]
Message-ID: <11944647134113-git-send-email-amit.shah@qumranet.com> (raw)
Message-ID: <95597be41c7ffbb889a0e53cb8294203ac6b5519.1194464687.git.amit.shah@qumranet.com> (raw)
In-Reply-To: <11944647133010-git-send-email-amit.shah@qumranet.com>
In-Reply-To: <cc1a3d4ee5e648e13b3c75fc62d9c6c00405c322.1194464687.git.amit.shah@qumranet.com>

This kernel module injects IRQs specified on the command line
via the passthrough parameter

This doesn't handle shared interrupts.

These patches don't yet work with the in-kernel apic, so you have
to use -no-kvm-irqchip.

These will soon be overridden by a new mechanism that utilises
the in-kernel apic.

Signed-off-by: Amit Shah <amit.shah@qumranet.com>
---
 Makefile               |   10 ++-
 irqhook/Kbuild         |    3 +
 irqhook/Makefile       |   25 ++++++
 irqhook/irqhook_main.c |  217 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 251 insertions(+), 4 deletions(-)
 create mode 100644 irqhook/Kbuild
 create mode 100644 irqhook/Makefile
 create mode 100644 irqhook/irqhook_main.c

diff --git a/Makefile b/Makefile
index 776ff01..4ba6221 100644
--- a/Makefile
+++ b/Makefile
@@ -5,13 +5,13 @@ DESTDIR=
 
 rpmrelease = devel
 
-.PHONY: kernel user libkvm qemu bios clean
+.PHONY: kernel irqhook user libkvm qemu bios clean
 
-all: $(if $(WANT_MODULE), kernel) user libkvm qemu
+all: $(if $(WANT_MODULE), kernel irqhook) user libkvm qemu
 
 kcmd = $(if $(WANT_MODULE),,@\#)
 
-qemu kernel user libkvm:
+qemu kernel user irqhook libkvm:
 	$(MAKE) -C $@
 
 qemu: libkvm
@@ -42,6 +42,7 @@ install-rpm:
 
 install:
 	$(kcmd)make -C kernel DESTDIR="$(DESTDIR)" install
+	$(kcmd)make -C irqhook DESTDIR="$(DESTDIR)" install
 	make -C libkvm DESTDIR="$(DESTDIR)" install
 	make -C qemu DESTDIR="$(DESTDIR)" install
 
@@ -62,13 +63,14 @@ srpm:
 	tar czf SOURCES/user.tar.gz user
 	tar czf SOURCES/libkvm.tar.gz libkvm
 	tar czf SOURCES/kernel.tar.gz kernel
+	tar czf SOURCES/irqhook.tar.gz irqhook
 	tar czf SOURCES/scripts.tar.gz scripts
 	cp Makefile configure kvm_stat SOURCES
 	rpmbuild  --define="_topdir $$(pwd)" -bs $(tmpspec)
 	$(RM) $(tmpspec)
 
 clean:
-	for i in $(if $(WANT_MODULE), kernel) user libkvm qemu; do \
+	for i in $(if $(WANT_MODULE), kernel irqhook) user libkvm qemu; do \
 		make -C $$i clean; \
 	done
 	rm -f config.mak user/config.mak
diff --git a/irqhook/Kbuild b/irqhook/Kbuild
new file mode 100644
index 0000000..9af75a4
--- /dev/null
+++ b/irqhook/Kbuild
@@ -0,0 +1,3 @@
+EXTRA_CFLAGS := -I$(src)/include
+obj-m := irqhook.o
+irqhook-objs := irqhook_main.o
diff --git a/irqhook/Makefile b/irqhook/Makefile
new file mode 100644
index 0000000..3b1d851
--- /dev/null
+++ b/irqhook/Makefile
@@ -0,0 +1,25 @@
+include ../config.mak
+
+KVERREL = $(patsubst /lib/modules/%/build,%,$(KERNELDIR))
+
+DESTDIR=
+
+INSTALLDIR = $(patsubst %/build,%/extra,$(KERNELDIR))
+
+rpmrelease = devel
+
+LINUX = ../linux-2.6
+
+all::
+	$(MAKE) -C $(KERNELDIR) M=`pwd` "$$@"
+
+#sync:
+#	rsync --exclude='*.mod.c' "$(LINUX)"/drivers/irqhook/*.[ch] .
+
+install:
+	mkdir -p $(DESTDIR)/$(INSTALLDIR)
+	cp *.ko $(DESTDIR)/$(INSTALLDIR)
+	/sbin/depmod -a
+
+clean:
+	$(MAKE) -C $(KERNELDIR) M=`pwd` $@
diff --git a/irqhook/irqhook_main.c b/irqhook/irqhook_main.c
new file mode 100644
index 0000000..812b714
--- /dev/null
+++ b/irqhook/irqhook_main.c
@@ -0,0 +1,217 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/bitmap.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+
+#include <asm/uaccess.h>
+
+#define irqh_VERSION "0.0.1"
+#define irqh_MODULE_NAME "irqhook"
+#define irqh_DRIVER_NAME   irqh_MODULE_NAME " HW IRQ hook " irqh_VERSION
+
+// based on earlier proprietary Tutis code; this modified version goes under GPL
+MODULE_AUTHOR("Nir Peleg - Tutis");
+MODULE_DESCRIPTION("IRQ hook driver");
+MODULE_LICENSE("GPL");
+
+//#define irqh_DEBUG /* define to enable copious debugging info */
+
+#ifdef irqh_DEBUG
+#define DPRINTK(fmt, args...) printk("<1>" "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define ERROR(fmt, args...) printk("<1>" "%s: " fmt, __FUNCTION__ , ## args)
+
+static spinlock_t irqh_lock;
+static wait_queue_head_t irqh_proc_list;
+
+enum {NINTR = 256};
+
+static DECLARE_BITMAP(pending, NINTR);
+static DECLARE_BITMAP(handled, NINTR);
+
+#define irqh_on(which, bit)	test_bit(bit, which)
+#define irqh_set(which, bit)	set_bit(bit, which)
+#define irqh_clear(which, bit)	clear_bit(bit, which)
+#define irqh_ffs(which)		find_first_bit(which, NINTR)
+
+static irqreturn_t
+irqh_interrupt(int irq, void *p)
+{
+	unsigned long flags;
+
+	DPRINTK("interrupt: %d\n", irq);
+	if (!irqh_on(handled, irq))
+		return IRQ_HANDLED;
+	spin_lock_irqsave(&irqh_lock, flags);
+	irqh_set(pending, irq);
+	wake_up_interruptible(&irqh_proc_list);
+	spin_unlock_irqrestore(&irqh_lock, flags);
+	disable_irq_nosync(irq);
+	return IRQ_HANDLED;
+}
+
+static ssize_t
+irqh_dev_write(struct file *fp, const char *buf, size_t size, loff_t *offp)
+{
+	int n, device, func, devfn;
+	char arg[32], *cp, *cp1;
+	struct pci_dev *pdp = 0;
+
+	DPRINTK("ENTER\n");
+	if ((fp->f_mode & FMODE_WRITE) == 0 || size > sizeof arg)
+		return -EINVAL;
+
+	if (size >= sizeof arg || copy_from_user(arg, buf, size))
+		return -EFAULT;
+	arg[size] = 0;
+	cp = arg + (arg[0] == '+' || arg[0] == '-');
+	n = simple_strtol(cp, &cp1, 0);
+	if (*cp1 == ':') {
+		device = simple_strtol(cp1+1, &cp1, 0);
+		func = simple_strtol(cp1+1, NULL, 0);
+		DPRINTK("PCI dev %d:%d.%d\n", n, device, func);
+		devfn = PCI_DEVFN(device, func);
+		for_each_pci_dev(pdp) {
+			if (pdp->bus->number == n && pdp->devfn == devfn) {
+				n = pdp->irq;
+				goto found;
+			}
+		}
+		ERROR("PCI device not found\n");
+		return -ENOENT;
+	}
+    found:
+	DPRINTK("IRQ %d\n", n);
+	if (arg[0] == '+') {
+		if (pdp) {
+			if (pci_enable_device(pdp))
+				ERROR("device not enabled\n");
+			if ((unsigned)(n = pdp->irq) >= NINTR) {
+				ERROR("device has invalid IRQ set\n");
+				return -EINVAL;
+			}
+		}
+		if (irqh_on(handled, n))
+			return -EBUSY;
+		if (request_irq(n, irqh_interrupt, IRQF_SHARED, irqh_MODULE_NAME, (void *)irqh_interrupt)) {
+			ERROR("request_irq failed\n");
+			return -EIO;
+		}
+		printk("Bound machine irq %d\n", n);
+		irqh_set(handled, n);
+		goto done;
+	}
+	if ((unsigned)n >= NINTR)
+		return -EINVAL;
+	if (arg[0] == '-') {
+		if (pdp)
+			pci_disable_device(pdp);
+		free_irq(n, (void *)irqh_interrupt);
+		irqh_clear(handled, n);
+	} else
+		enable_irq(n);
+
+    done:
+	DPRINTK("DONE\n");
+	return size;
+}
+
+static ssize_t
+irqh_dev_read(struct file *fp, char *buf, size_t size, loff_t *offp)
+{
+	char b[20];
+	int m = -ERESTARTSYS, n;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	DPRINTK("ENTER\n");
+	if ((fp->f_mode & FMODE_READ) == 0)
+		return -EINVAL;
+	spin_lock_irq(&irqh_lock);
+	while (!signal_pending(current)) {
+		if ((n = irqh_ffs(pending)) < NINTR) {
+			if ((m = sprintf(b, "%d", n) + 1) > size)
+				m = size;
+			if (copy_to_user(buf, b, m))
+				m = -EFAULT;
+			else
+				irqh_clear(pending, n);
+			break;
+		}
+		if (fp->f_flags & O_NONBLOCK) {
+			m = -EWOULDBLOCK;
+			break;
+		}
+		add_wait_queue(&irqh_proc_list, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irq(&irqh_lock);
+		schedule();
+		spin_lock_irq(&irqh_lock);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&irqh_proc_list, &wait);
+	}
+	spin_unlock_irq(&irqh_lock);
+	return m;
+}
+
+static struct file_operations irqh_chrdev_ops = {
+	owner:		THIS_MODULE,
+	read:		irqh_dev_read,
+	write:		irqh_dev_write,
+};
+
+#define	irqh_MISCDEV_MINOR	MISC_DYNAMIC_MINOR
+
+static struct miscdevice irqh_miscdev = {
+	irqh_MISCDEV_MINOR,
+	irqh_MODULE_NAME,
+	&irqh_chrdev_ops,
+};
+
+static int __init
+irqh_init(void)
+{
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	if (rc = misc_register(&irqh_miscdev)) {
+		printk(KERN_ERR irqh_MODULE_NAME ": " "cannot register misc device\n");
+		DPRINTK("EXIT, returning %d\n", rc);
+		return rc;
+	}
+
+	printk(KERN_INFO irqh_DRIVER_NAME " loaded\n");
+
+	init_waitqueue_head(&irqh_proc_list);
+	spin_lock_init(&irqh_lock);
+
+	DPRINTK("EXIT, returning 0\n");
+	return 0;
+}
+
+static void __exit
+irqh_cleanup(void)
+{
+	int n;
+
+	DPRINTK("ENTER\n");
+	
+	while ((n = irqh_ffs(handled)) < NINTR) {
+		irqh_clear(handled, n);
+		free_irq(n, (void *)irqh_interrupt);
+	}
+	misc_deregister (&irqh_miscdev);
+
+	DPRINTK("EXIT\n");
+}
+
+module_init (irqh_init);
+module_exit (irqh_cleanup);
-- 
1.5.3

  parent reply	other threads:[~2007-11-07 19:44 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cc1a3d4ee5e648e13b3c75fc62d9c6c00405c322.1194464687.git.amit.shah@qumranet.com>
2007-11-07 19:45 ` [Qemu-devel] [PATCH 1/2] KVM userspace: Add PCI device passthrough support Amit Shah
2007-11-08  6:28   ` [Qemu-devel] Re: [kvm-devel] " Avi Kivity
2007-11-08  9:19   ` [Qemu-devel] " Fabrice Bellard
2007-11-08 10:00     ` [kvm-devel] " Dor Laor
     [not found] ` <95597be41c7ffbb889a0e53cb8294203ac6b5519.1194464687.git.amit.shah@qumranet.com>
2007-11-07 19:45   ` Amit Shah [this message]
2007-11-07 20:01 ` [Qemu-devel] Re: [kvm-devel] " Hollis Blanchard
2007-11-08  6:12   ` Amit Shah

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=11944647134113-git-send-email-amit.shah@qumranet.com \
    --to=amit.shah@qumranet.com \
    --cc=kvm-devel@lists.sourceforge.net \
    --cc=qemu-devel@nongnu.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;
as well as URLs for NNTP newsgroup(s).