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 <[EMAIL PROTECTED]> --- 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 ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel