diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ad0ae435 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +module/*.ko +module/*.o +module/*.mod.c +module/.* +module/Module.symvers +module/modules.order diff --git a/module/Makefile b/module/Makefile new file mode 100644 index 00000000..9a81ed3c --- /dev/null +++ b/module/Makefile @@ -0,0 +1,7 @@ +obj-m += kvmfr.o + +all: + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean diff --git a/module/README b/module/README new file mode 100644 index 00000000..7923c573 --- /dev/null +++ b/module/README @@ -0,0 +1,47 @@ +This kernel module implements a basic interface to the IVSHMEM device for +LookingGlass when using LookingGlass in VM->VM mode. + +== Compiling == + +Make sure you have your kernel headers installed first, on Debian/Ubuntu use +the following command. + + apt-get install linux-headers-$(uname -r) + +Then simply run `make` and you're done. + +== Usage == + +This module requires the `uio` module to be loaded first, loading it is as +simple as: + + modprobe uio + insmod kvmfr.ko + +This will create the `/dev/uio0` node that represents the KVMFR interface. +To use the interface you need permission to access it by either creating a +udev rule to ensure your user can read and write to it, or simply change it's +ownership manually, ie: + + sudo chown user:user /dev/uid0 + +Usage with looking glass is simple, but you do need to speecify both the path +and the size as LookingGlass can not determine the size by itself at this time. + + ./looking-glass-client -f /dev/uio0 -L 16 + +== Note == + +This module is not strictly required, it is possible to access the device +via the /sys interface directly, for example: + + ./looking-glass-client -f /sys/devices/pci0000:00/0000:00:03.0/resource2_wc + +Obviously adjusting the PCI device IDs as required. However while this is +possible it is not recommended as access to the shared memory may be slower. + +== Issues == + +At this time VM->VM access atleast in this authors configurtion is slow, barely +exceeding 15fps at 1200p, it is still yet to be determined if this is an +architecture problem with this authors AMD ThreadRipper platform. diff --git a/module/kvmfr.c b/module/kvmfr.c new file mode 100644 index 00000000..f7e23d81 --- /dev/null +++ b/module/kvmfr.c @@ -0,0 +1,116 @@ +/* +UIO KVMFR Driver +Copyright (C) 2017 Geoffrey McRae +https://looking-glass.hostfission.com + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define PCI_LG_VENDOR_ID 0x1af4 //Red Hat Inc, +#define PCI_LG_DEVICE_ID 0x1110 //Inter-VM shared memory + +#include +#include +#include +#include +#include + +#include + +static int kvmfr_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct uio_info *info; + + info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (pci_enable_device(dev)) + goto out_free; + + if (pci_request_regions(dev, "kvmfr")) + goto out_disable; + + info->mem[0].addr = pci_resource_start(dev, 2); + if (!info->mem[0].addr) + goto out_release; + + info->mem[0].internal_addr = pci_iomap(dev, 2, 0); + if (!info->mem[0].internal_addr) + goto out_release; + + info->mem[0].size = pci_resource_len(dev, 2); + info->mem[0].memtype = UIO_MEM_PHYS; + info->name = "KVMFR"; + info->version = "0.0.1"; + info->irq = 0; + info->irq_flags = 0; + info->handler = NULL; + + if (uio_register_device(&dev->dev, info)) + goto out_unmap; + + pci_set_drvdata(dev, info); + return 0; + +out_unmap: + printk("unmap\n"); + iounmap(info->mem[0].internal_addr); +out_release: + printk("release\n"); + pci_release_regions(dev); +out_disable: + printk("disable\n"); + pci_disable_device(dev); +out_free: + printk("free\n"); + kfree(info); + return -ENODEV; +} + +static void kvmfr_pci_remove(struct pci_dev *dev) +{ + struct uio_info *info = pci_get_drvdata(dev); + + uio_unregister_device(info); + pci_release_regions(dev); + pci_disable_device(dev); + iounmap(info->mem[0].internal_addr); + + kfree(info); +} + +static struct pci_device_id kvmfr_pci_ids[] = +{ + { + .vendor = PCI_LG_VENDOR_ID, + .device = PCI_LG_DEVICE_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID + }, + { 0, } +}; + +static struct pci_driver kvmfr_pci_driver = +{ + .name = "kvmfr", + .id_table = kvmfr_pci_ids, + .probe = kvmfr_pci_probe, + .remove = kvmfr_pci_remove +}; + +module_pci_driver(kvmfr_pci_driver); +MODULE_DEVICE_TABLE(pci, kvmfr_pci_ids); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Geoffrey McRae"); \ No newline at end of file