VMShm, a mechanism for accessing POSIX shared memory from QEMU/kvm guests

VMShm is a mechanism that enables qemu virtual machines to access to POSIX shared memory objects created on the host OS.

VMShm make it possible to an user space application running in a virtual machine to map up to 1M of a POSIX shared memory object from the host OS.

It can be used as a base to build up an high performance communication channel between host and guest(s) OSes.

Installation

VMShm is distributed as a patch for QEMU 0.13.0, so in order to install vmshm it is needed to build qemu with the vmshm patch applied.
It is needed to build and load the linux-vshm driver (as a kernel module) in guest os to use the VMShm device.

Qemu

To have a VMShm enabled qemu it is needed to rebuild it with the vmshm patch, so the first thing to do is to obtain the qemu sources (from qemu website), then apply the patch obtained from the gVirtusS Download Page, configure, build and install the new qemu:

wget http://downloads.sourceforge.net/project/kvm/qemu-kvm/0.13.0/qemu-kvm-0.13.0.tar.gz
tar xfz qemu-kvm-0.13.0.tar.gz
cd qemu-kvm-0.13.0
wget http://osl.uniparthenope.it/pub/projects/gvirtus/qemu-0.13.0-vmshm-0.1.diff
patch -p1 < qemu-0.13.0-vmshm-0.1.diff
./configure
make
make install

Then to use vmshm add the “-device vmshm” option to the common arguments used for qemu.

linux driver

The linux driver is distributed as an “out-of-tree” linux module. To build and use it, it is needed to obtain the sources, build, install and load the module:

wget http://osl.uniparthenope.it/pub/projects/gvirtus/linux-vmshm-0.1.tar.gz
cd linux-vmshm-0.1
make
make install
modprobe vmshm

Note: it is needed to load the vmshm module everytime that the guest os boots.

Device implentation

VMShm is implemented as virtual PCI device that exposes three BAR:

  • the mmio, containing the registers used for requesting the operations of opening, mapping and releasing of the shared memory;
  • a buffer of 1M, where will be mapped the shared memory;
  • a buffer (called name) of 1K, where is stored the name of the shared memory object to open.

There are just two read-only registers:

  • open, mapped at 0x0. Reading from this register will ensure that the device (VMShm) will open (shm_open) the shared memory object, whose name is stored in the “name” buffer, and will map the memory just opened to the buffer region. The value will be 0 (zero) if everything worked right and the memory is ready;
  • close, mapped at 0x20. Reading from this register will make the device unmap and release the memory.

Driver implementation

The driver, after performing common pci intialization and region mapping, to open and access to a POSIX shared memory object already created in the host OS, has to do the following operations:

  • write the name of the memory object to open in the “name” buffer;
  • read the content of the “open” register, and check that the content is 0 (zero), meaning that everything worked;
  • make the desidered operation to the “buffer” (the second region of the pci device), probably the common operation is to expose this buffer to the userspace;
  • read from the “close” register to release the shared memory when is not needed anymore.

Linux driver

With VMShm is provided also the driver for linux. It is a linux kernel module, that can be built outside the kernel source.

The linux driver exposes the usage of VMShm to the user space applications through a character device, “/dev/vmshm0”.

On the /dev/vmshm0 it is possible to perform 4 operation:

  • open, for acquiring the device;
  • ioctl, with the name of the shared memory as argument, for requesting the opening and mapping of the host OS POSIX shared memory;
  • mmap, for mapping the device buffer to the user space;
  • release (close), for unmapping the shared memory and releasing the usage of the device.

The following example will show better the usage from an userspace application:

int fd = open("/dev/vshm0", O_RDWR);
if(fd < 0) {
    fprintf(stderr, "Cannot open device\n");
    exit(0);
}

if(ioctl(fd, 0, "/shared-with-qemu") != 0) {
    fprintf(stderr, "Cannot map host's shared memory object.n");
    exit(0);
}

char *shm = mmap(NULL, 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

if(shm == MAP_FAILED) {
    fprintf(stderr, "Cannot mmap device buffer\n");
    exit(0);
}

/* do everything that you need on the shm buffer */
/* for example write the pid of the process */
sprintf(shm, "I was here: %d", getpid());

/* ... */

munmap(shm, 1024 * 1024);
close(fd);

Leave a comment