[module] added kvmfr kernel module for VM->VM shared memory

This commit is contained in:
Geoffrey McRae 2018-05-15 20:50:52 +10:00
parent d0756cf00c
commit 7f81d21aaa
4 changed files with 176 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
module/*.ko
module/*.o
module/*.mod.c
module/.*
module/Module.symvers
module/modules.order

7
module/Makefile Normal file
View file

@ -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

47
module/README Normal file
View file

@ -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.

116
module/kvmfr.c Normal file
View file

@ -0,0 +1,116 @@
/*
UIO KVMFR Driver
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
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 <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/uio_driver.h>
#include <asm/io.h>
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");