Commit 5cb470e4 authored by Alexandru Elisei's avatar Alexandru Elisei
Browse files

Remove pci-shmem device

The pci-shmem emulated device ("ivshmem") was created by QEMU for
cross-VM data sharing. The only Linux driver that uses this device is
the Android Virtual System on a Chip staging driver, which also mentions
a character device driver implemented on top of shmem, which was removed
from Linux.

On the kvmtool side, the only commits touching the pci-shmem device
since it was introduced in 2012 were made when refactoring various
kvmtool subsystems. Let's remove the maintenance burden on the kvmtool
maintainers and remove this unused device.
parent 49f1e01f
......@@ -99,7 +99,6 @@ OBJS += util/read-write.o
OBJS += util/util.o
OBJS += virtio/9p.o
OBJS += virtio/9p-pdu.o
OBJS += hw/pci-shmem.o
OBJS += kvm-ipc.o
OBJS += builtin-sandbox.o
OBJS += virtio/mmio.o
......
......@@ -31,7 +31,6 @@
#include "kvm/sdl.h"
#include "kvm/vnc.h"
#include "kvm/guest_compat.h"
#include "kvm/pci-shmem.h"
#include "kvm/kvm-ipc.h"
#include "kvm/builtin-debug.h"
......@@ -99,10 +98,6 @@ void kvm_run_set_wrapper_sandbox(void)
OPT_INTEGER('c', "cpus", &(cfg)->nrcpus, "Number of CPUs"), \
OPT_U64('m', "mem", &(cfg)->ram_size, "Virtual machine memory" \
" size in MiB."), \
OPT_CALLBACK('\0', "shmem", NULL, \
"[pci:]<addr>:<size>[:handle=<handle>][:create]", \
"Share host shmem with guest via pci device", \
shmem_parser, NULL), \
OPT_CALLBACK('d', "disk", kvm, "image or rootfs_dir", "Disk " \
" image or rootfs directory", img_name_parser, \
kvm), \
......
#include "kvm/devices.h"
#include "kvm/pci-shmem.h"
#include "kvm/virtio-pci-dev.h"
#include "kvm/irq.h"
#include "kvm/kvm.h"
#include "kvm/pci.h"
#include "kvm/util.h"
#include "kvm/ioport.h"
#include "kvm/ioeventfd.h"
#include <linux/kvm.h>
#include <linux/byteorder.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#define MB_SHIFT (20)
#define KB_SHIFT (10)
#define GB_SHIFT (30)
static struct pci_device_header pci_shmem_pci_device = {
.vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
.device_id = cpu_to_le16(0x1110),
.header_type = PCI_HEADER_TYPE_NORMAL,
.class[2] = 0xFF, /* misc pci device */
.status = cpu_to_le16(PCI_STATUS_CAP_LIST),
.capabilities = (void *)&pci_shmem_pci_device.msix - (void *)&pci_shmem_pci_device,
.msix.cap = PCI_CAP_ID_MSIX,
.msix.ctrl = cpu_to_le16(1),
.msix.table_offset = cpu_to_le32(1), /* Use BAR 1 */
.msix.pba_offset = cpu_to_le32(0x1001), /* Use BAR 1 */
};
static struct device_header pci_shmem_device = {
.bus_type = DEVICE_BUS_PCI,
.data = &pci_shmem_pci_device,
};
/* registers for the Inter-VM shared memory device */
enum ivshmem_registers {
INTRMASK = 0,
INTRSTATUS = 4,
IVPOSITION = 8,
DOORBELL = 12,
};
static struct shmem_info *shmem_region;
static u16 ivshmem_registers;
static int local_fd;
static u32 local_id;
static u64 msix_block;
static u64 msix_pba;
static struct msix_table msix_table[2];
int pci_shmem__register_mem(struct shmem_info *si)
{
if (!shmem_region) {
shmem_region = si;
} else {
pr_warning("only single shmem currently avail. ignoring.\n");
free(si);
}
return 0;
}
static bool shmem_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u16 offset = port - ivshmem_registers;
switch (offset) {
case INTRMASK:
break;
case INTRSTATUS:
break;
case IVPOSITION:
ioport__write32(data, local_id);
break;
case DOORBELL:
break;
};
return true;
}
static bool shmem_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u16 offset = port - ivshmem_registers;
switch (offset) {
case INTRMASK:
break;
case INTRSTATUS:
break;
case IVPOSITION:
break;
case DOORBELL:
break;
};
return true;
}
static struct ioport_operations shmem_pci__io_ops = {
.io_in = shmem_pci__io_in,
.io_out = shmem_pci__io_out,
};
static void callback_mmio_msix(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
{
void *mem;
if (addr - msix_block < 0x1000)
mem = &msix_table;
else
mem = &msix_pba;
if (is_write)
memcpy(mem + addr - msix_block, data, len);
else
memcpy(data, mem + addr - msix_block, len);
}
/*
* Return an irqfd which can be used by other guests to signal this guest
* whenever they need to poke it
*/
int pci_shmem__get_local_irqfd(struct kvm *kvm)
{
int fd, gsi, r;
if (local_fd == 0) {
fd = eventfd(0, 0);
if (fd < 0)
return fd;
if (pci_shmem_pci_device.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE)) {
gsi = irq__add_msix_route(kvm, &msix_table[0].msg,
pci_shmem_device.dev_num << 3);
if (gsi < 0)
return gsi;
} else {
gsi = pci_shmem_pci_device.irq_line;
}
r = irq__add_irqfd(kvm, gsi, fd, -1);
if (r < 0)
return r;
local_fd = fd;
}
return local_fd;
}
/*
* Connect a new client to ivshmem by adding the appropriate datamatch
* to the DOORBELL
*/
int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd)
{
struct kvm_ioeventfd ioevent;
ioevent = (struct kvm_ioeventfd) {
.addr = ivshmem_registers + DOORBELL,
.len = sizeof(u32),
.datamatch = id,
.fd = fd,
.flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH,
};
return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
}
/*
* Remove a client connected to ivshmem by removing the appropriate datamatch
* from the DOORBELL
*/
int pci_shmem__remove_client(struct kvm *kvm, u32 id)
{
struct kvm_ioeventfd ioevent;
ioevent = (struct kvm_ioeventfd) {
.addr = ivshmem_registers + DOORBELL,
.len = sizeof(u32),
.datamatch = id,
.flags = KVM_IOEVENTFD_FLAG_PIO
| KVM_IOEVENTFD_FLAG_DATAMATCH
| KVM_IOEVENTFD_FLAG_DEASSIGN,
};
return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
}
static void *setup_shmem(const char *key, size_t len, int creating)
{
int fd;
int rtn;
void *mem;
int flag = O_RDWR;
if (creating)
flag |= O_CREAT;
fd = shm_open(key, flag, S_IRUSR | S_IWUSR);
if (fd < 0) {
pr_warning("Failed to open shared memory file %s\n", key);
return NULL;
}
if (creating) {
rtn = ftruncate(fd, (off_t) len);
if (rtn < 0)
pr_warning("Can't ftruncate(fd,%zu)\n", len);
}
mem = mmap(NULL, len,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
if (mem == MAP_FAILED) {
pr_warning("Failed to mmap shared memory file");
mem = NULL;
}
close(fd);
return mem;
}
int shmem_parser(const struct option *opt, const char *arg, int unset)
{
const u64 default_size = SHMEM_DEFAULT_SIZE;
const u64 default_phys_addr = SHMEM_DEFAULT_ADDR;
const char *default_handle = SHMEM_DEFAULT_HANDLE;
struct shmem_info *si = malloc(sizeof(struct shmem_info));
u64 phys_addr;
u64 size;
char *handle = NULL;
int create = 0;
const char *p = arg;
char *next;
int base = 10;
int verbose = 0;
const int skip_pci = strlen("pci:");
if (verbose)
pr_info("shmem_parser(%p,%s,%d)", opt, arg, unset);
/* parse out optional addr family */
if (strcasestr(p, "pci:")) {
p += skip_pci;
} else if (strcasestr(p, "mem:")) {
die("I can't add to E820 map yet.\n");
}
/* parse out physical addr */
base = 10;
if (strcasestr(p, "0x"))
base = 16;
phys_addr = strtoll(p, &next, base);
if (next == p && phys_addr == 0) {
pr_info("shmem: no physical addr specified, using default.");
phys_addr = default_phys_addr;
}
if (*next != ':' && *next != '\0')
die("shmem: unexpected chars after phys addr.\n");
if (*next == '\0')
p = next;
else
p = next + 1;
/* parse out size */
base = 10;
if (strcasestr(p, "0x"))
base = 16;
size = strtoll(p, &next, base);
if (next == p && size == 0) {
pr_info("shmem: no size specified, using default.");
size = default_size;
}
/* look for [KMGkmg][Bb]* uses base 2. */
int skip_B = 0;
if (strspn(next, "KMGkmg")) { /* might have a prefix */
if (*(next + 1) == 'B' || *(next + 1) == 'b')
skip_B = 1;
switch (*next) {
case 'K':
case 'k':
size = size << KB_SHIFT;
break;
case 'M':
case 'm':
size = size << MB_SHIFT;
break;
case 'G':
case 'g':
size = size << GB_SHIFT;
break;
default:
die("shmem: bug in detecting size prefix.");
break;
}
next += 1 + skip_B;
}
if (*next != ':' && *next != '\0') {
die("shmem: unexpected chars after phys size. <%c><%c>\n",
*next, *p);
}
if (*next == '\0')
p = next;
else
p = next + 1;
/* parse out optional shmem handle */
const int skip_handle = strlen("handle=");
next = strcasestr(p, "handle=");
if (*p && next) {
if (p != next)
die("unexpected chars before handle\n");
p += skip_handle;
next = strchrnul(p, ':');
if (next - p) {
handle = malloc(next - p + 1);
strncpy(handle, p, next - p);
handle[next - p] = '\0'; /* just in case. */
}
if (*next == '\0')
p = next;
else
p = next + 1;
}
/* parse optional create flag to see if we should create shm seg. */
if (*p && strcasestr(p, "create")) {
create = 1;
p += strlen("create");
}
if (*p != '\0')
die("shmem: unexpected trailing chars\n");
if (handle == NULL) {
handle = malloc(strlen(default_handle) + 1);
strcpy(handle, default_handle);
}
if (verbose) {
pr_info("shmem: phys_addr = %llx",
(unsigned long long)phys_addr);
pr_info("shmem: size = %llx", (unsigned long long)size);
pr_info("shmem: handle = %s", handle);
pr_info("shmem: create = %d", create);
}
si->phys_addr = phys_addr;
si->size = size;
si->handle = handle;
si->create = create;
pci_shmem__register_mem(si); /* ownership of si, etc. passed on. */
return 0;
}
int pci_shmem__init(struct kvm *kvm)
{
char *mem;
int r;
if (shmem_region == NULL)
return 0;
/* Register MMIO space for MSI-X */
r = ioport__register(kvm, IOPORT_EMPTY, &shmem_pci__io_ops, IOPORT_SIZE, NULL);
if (r < 0)
return r;
ivshmem_registers = (u16)r;
msix_block = pci_get_io_space_block(0x1010);
kvm__register_mmio(kvm, msix_block, 0x1010, false, callback_mmio_msix, NULL);
/*
* This registers 3 BARs:
*
* 0 - ivshmem registers
* 1 - MSI-X MMIO space
* 2 - Shared memory block
*/
pci_shmem_pci_device.bar[0] = cpu_to_le32(ivshmem_registers | PCI_BASE_ADDRESS_SPACE_IO);
pci_shmem_pci_device.bar_size[0] = shmem_region->size;
pci_shmem_pci_device.bar[1] = cpu_to_le32(msix_block | PCI_BASE_ADDRESS_SPACE_MEMORY);
pci_shmem_pci_device.bar_size[1] = 0x1010;
pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY);
pci_shmem_pci_device.bar_size[2] = shmem_region->size;
device__register(&pci_shmem_device);
/* Open shared memory and plug it into the guest */
mem = setup_shmem(shmem_region->handle, shmem_region->size,
shmem_region->create);
if (mem == NULL)
return -EINVAL;
kvm__register_dev_mem(kvm, shmem_region->phys_addr, shmem_region->size,
mem);
return 0;
}
dev_init(pci_shmem__init);
int pci_shmem__exit(struct kvm *kvm)
{
return 0;
}
dev_exit(pci_shmem__exit);
#ifndef KVM__PCI_SHMEM_H
#define KVM__PCI_SHMEM_H
#include <linux/types.h>
#include <linux/list.h>
#include "kvm/parse-options.h"
#define SHMEM_DEFAULT_SIZE (16 << MB_SHIFT)
#define SHMEM_DEFAULT_ADDR (0xc8000000)
#define SHMEM_DEFAULT_HANDLE "/kvm_shmem"
struct kvm;
struct shmem_info;
struct shmem_info {
u64 phys_addr;
u64 size;
char *handle;
int create;
};
int pci_shmem__init(struct kvm *kvm);
int pci_shmem__exit(struct kvm *kvm);
int pci_shmem__register_mem(struct shmem_info *si);
int shmem_parser(const struct option *opt, const char *arg, int unset);
int pci_shmem__get_local_irqfd(struct kvm *kvm);
int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd);
int pci_shmem__remove_client(struct kvm *kvm, u32 id);
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment