All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Evensky <evensky@sandia.gov>
To: penberg@kernel.org
Cc: Sasha Levin <levinsasha928@gmail.com>, kvm@vger.kernel.org
Subject: [PATCH] kvm tools: adds a PCI device that exports a host shared segment as a PCI BAR in the guest
Date: Wed, 24 Aug 2011 15:25:11 -0700	[thread overview]
Message-ID: <20110824222510.GC14835@dancer.ca.sandia.gov> (raw)



This patch adds a PCI device that provides PCI device memory to the
guest. This memory in the guest exists as a shared memory segment in
the host. This is similar memory sharing capability of Nahanni
(ivshmem) available in QEMU. In this case, the shared memory segment
is exposed as a PCI BAR only.

A new command line argument is added as:
    --shmem pci:0xc8000000:16MB:handle=/newmem:create

which will set the PCI BAR at 0xc8000000, the shared memory segment
and the region pointed to by the BAR will be 16MB. On the host side
the shm_open handle will be '/newmem', and the kvm tool will create
the shared segment, set its size, and initialize it. If the size,
handle, or create flag are absent, they will default to 16MB,
handle=/kvm_shmem, and create will be false. The address family,
'pci:' is also optional as it is the only address family currently
supported. Only a single --shmem is supported at this time.

Signed-off-by: David Evensky <evensky@sandia.gov>

diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/builtin-run.c linux-kvm_pci_shmem/tools/kvm/builtin-run.c
--- linux-kvm/tools/kvm/builtin-run.c	2011-08-24 10:21:22.342077674 -0700
+++ linux-kvm_pci_shmem/tools/kvm/builtin-run.c	2011-08-24 14:17:33.190451297 -0700
@@ -28,6 +28,8 @@
 #include "kvm/sdl.h"
 #include "kvm/vnc.h"
 #include "kvm/guest_compat.h"
+#include "shmem-util.h"
+#include "kvm/pci-shmem.h"
 
 #include <linux/types.h>
 
@@ -52,6 +54,8 @@
 #define DEFAULT_SCRIPT		"none"
 
 #define MB_SHIFT		(20)
+#define KB_SHIFT		(10)
+#define GB_SHIFT		(30)
 #define MIN_RAM_SIZE_MB		(64ULL)
 #define MIN_RAM_SIZE_BYTE	(MIN_RAM_SIZE_MB << MB_SHIFT)
 
@@ -151,6 +155,130 @@ static int virtio_9p_rootdir_parser(cons
 	return 0;
 }
 
+static int shmem_parser(const struct option *opt, const char *arg, int unset)
+{
+	const uint64_t default_size = SHMEM_DEFAULT_SIZE;
+	const uint64_t default_phys_addr = SHMEM_DEFAULT_ADDR;
+	const char *default_handle = SHMEM_DEFAULT_HANDLE;
+	enum { PCI, UNK } addr_type = PCI;
+	uint64_t phys_addr;
+	uint64_t 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;
+		addr_type = 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 = %lx", phys_addr);
+		pr_info("shmem: size      = %lx", size);
+		pr_info("shmem: handle    = %s", handle);
+		pr_info("shmem: create    = %d", create);
+	}
+	struct shmem_info *si = malloc(sizeof(struct shmem_info));
+	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;
+}
 
 static const struct option options[] = {
 	OPT_GROUP("Basic options:"),
@@ -158,6 +286,10 @@ static const struct option options[] = {
 			"A name for the guest"),
 	OPT_INTEGER('c', "cpus", &nrcpus, "Number of CPUs"),
 	OPT_U64('m', "mem", &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),
 	OPT_CALLBACK('d', "disk", NULL, "image or rootfs_dir", "Disk image or rootfs directory", img_name_parser),
 	OPT_BOOLEAN('\0', "balloon", &balloon, "Enable virtio balloon"),
 	OPT_BOOLEAN('\0', "vnc", &vnc, "Enable VNC framebuffer"),
@@ -695,6 +827,8 @@ int kvm_cmd_run(int argc, const char **a
 
 	kbd__init(kvm);
 
+	pci_shmem__init(kvm);
+
 	if (vnc || sdl)
 		fb = vesa__init(kvm);
 
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/hw/pci-shmem.c linux-kvm_pci_shmem/tools/kvm/hw/pci-shmem.c
--- linux-kvm/tools/kvm/hw/pci-shmem.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-kvm_pci_shmem/tools/kvm/hw/pci-shmem.c	2011-08-24 14:18:09.227234167 -0700
@@ -0,0 +1,59 @@
+#include "shmem-util.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"
+
+static struct pci_device_header pci_shmem_pci_device = {
+	.vendor_id = PCI_VENDOR_ID_PCI_SHMEM,
+	.device_id = PCI_DEVICE_ID_PCI_SHMEM,
+	.header_type = PCI_HEADER_TYPE_NORMAL,
+	.class = 0xFF0000,	/* misc pci device */
+};
+
+static struct shmem_info *shmem_region;
+
+int pci_shmem__register_mem(struct shmem_info *si)
+{
+	if (shmem_region == NULL) {
+		shmem_region = si;
+	} else {
+		pr_warning("only single shmem currently avail. ignoring.\n");
+		free(si);
+	}
+	return 0;
+}
+
+int pci_shmem__init(struct kvm *kvm)
+{
+	u8 dev, line, pin;
+	char *mem;
+	int verbose = 0;
+	if (irq__register_device(PCI_DEVICE_ID_PCI_SHMEM, &dev, &pin, &line)
+	    < 0)
+		return 0;
+	/* ignore irq stuff, just want bus info for now. */
+	/* pci_shmem_pci_device.irq_pin          = pin; */
+	/* pci_shmem_pci_device.irq_line         = line; */
+	if (shmem_region == 0) {
+		if (verbose == 1)
+			pr_warning
+			    ("pci_shmem_init: memory region not registered\n");
+		return 0;
+	}
+	pci_shmem_pci_device.bar[0] =
+	    shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY;
+	pci_shmem_pci_device.bar_size[0] = shmem_region->size;
+	pci__register(&pci_shmem_pci_device, dev);
+
+	mem =
+	    setup_shmem(shmem_region->handle, shmem_region->size,
+			shmem_region->create, verbose);
+	if (mem == NULL)
+		return 0;
+	kvm__register_mem(kvm, shmem_region->phys_addr, shmem_region->size,
+			  mem);
+	return 1;
+}
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/include/kvm/pci-shmem.h linux-kvm_pci_shmem/tools/kvm/include/kvm/pci-shmem.h
--- linux-kvm/tools/kvm/include/kvm/pci-shmem.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-kvm_pci_shmem/tools/kvm/include/kvm/pci-shmem.h	2011-08-13 15:43:01.067953711 -0700
@@ -0,0 +1,13 @@
+#ifndef KVM__PCI_SHMEM_H
+#define KVM__PCI_SHMEM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct kvm;
+struct shmem_info;
+
+int pci_shmem__init(struct kvm *self);
+int pci_shmem__register_mem(struct shmem_info *si);
+
+#endif
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/include/kvm/virtio-pci-dev.h linux-kvm_pci_shmem/tools/kvm/include/kvm/virtio-pci-dev.h
--- linux-kvm/tools/kvm/include/kvm/virtio-pci-dev.h	2011-08-09 15:38:48.760120973 -0700
+++ linux-kvm_pci_shmem/tools/kvm/include/kvm/virtio-pci-dev.h	2011-08-18 10:06:12.171539230 -0700
@@ -15,10 +15,13 @@
 #define PCI_DEVICE_ID_VIRTIO_BLN		0x1005
 #define PCI_DEVICE_ID_VIRTIO_P9			0x1009
 #define PCI_DEVICE_ID_VESA			0x2000
+#define PCI_DEVICE_ID_PCI_SHMEM			0x0001
 
 #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
+#define PCI_VENDOR_ID_PCI_SHMEM			0x0001
 #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
 
 #define PCI_SUBSYSTEM_ID_VESA			0x0004
+#define PCI_SUBSYSTEM_ID_PCI_SHMEM		0x0001
 
 #endif /* VIRTIO_PCI_DEV_H_ */
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/include/shmem-util.h linux-kvm_pci_shmem/tools/kvm/include/shmem-util.h
--- linux-kvm/tools/kvm/include/shmem-util.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-kvm_pci_shmem/tools/kvm/include/shmem-util.h	2011-08-24 14:15:30.271780710 -0700
@@ -0,0 +1,27 @@
+#ifndef SHMEM_UTIL_H
+#define SHMEM_UTIL_H
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define SHMEM_DEFAULT_SIZE (16 << MB_SHIFT)
+#define SHMEM_DEFAULT_ADDR (0xc8000000)
+#define SHMEM_DEFAULT_HANDLE "/kvm_shmem"
+struct shmem_info {
+	uint64_t phys_addr;
+	uint64_t size;
+	char *handle;
+	int create;
+};
+
+inline void *setup_shmem(const char *key, size_t len, int creating,
+			 int verbose);
+inline void fill_mem(void *buf, size_t buf_size, char *fill, size_t fill_len);
+
+#endif				/* SHMEM_UTIL_H */
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/Makefile linux-kvm_pci_shmem/tools/kvm/Makefile
--- linux-kvm/tools/kvm/Makefile	2011-08-24 10:21:22.342077676 -0700
+++ linux-kvm_pci_shmem/tools/kvm/Makefile	2011-08-24 13:55:37.442003451 -0700
@@ -77,10 +77,12 @@ OBJS	+= threadpool.o
 OBJS	+= util/parse-options.o
 OBJS	+= util/rbtree-interval.o
 OBJS	+= util/strbuf.o
+OBJS	+= util/shmem-util.o
 OBJS	+= virtio/9p.o
 OBJS	+= virtio/9p-pdu.o
 OBJS	+= hw/vesa.o
 OBJS	+= hw/i8042.o
+OBJS	+= hw/pci-shmem.o
 
 FLAGS_BFD := $(CFLAGS) -lbfd
 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
diff -uprN -X linux-kvm/Documentation/dontdiff linux-kvm/tools/kvm/util/shmem-util.c linux-kvm_pci_shmem/tools/kvm/util/shmem-util.c
--- linux-kvm/tools/kvm/util/shmem-util.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-kvm_pci_shmem/tools/kvm/util/shmem-util.c	2011-08-24 14:19:31.801027897 -0700
@@ -0,0 +1,64 @@
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include "shmem-util.h"
+
+inline void *setup_shmem(const char *key, size_t len, int creating, int verbose)
+{
+	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 == -1) {
+		fprintf(stderr, "Failed to open shared memory file %s\n", key);
+		fflush(stderr);
+		return NULL;
+	}
+	if (creating) {
+		if (verbose)
+			fprintf(stderr, "Truncating file.\n");
+		rtn = ftruncate(fd, (off_t) len);
+		if (rtn == -1) {
+			fprintf(stderr, "Can't ftruncate(fd,%ld)\n", len);
+			fflush(stderr);
+		}
+	}
+	mem = mmap(NULL, len,
+		   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
+	close(fd);
+	if (mem == NULL) {
+		fprintf(stderr, "Failed to mmap shared memory file\n");
+		fflush(stderr);
+		return NULL;
+	}
+	if (creating) {
+		int fill_bytes = 0xae0dae0d;
+		if (verbose)
+			fprintf(stderr, "Filling buffer\n");
+		fill_mem(mem, len, (char *)&fill_bytes, 4);
+	}
+	return mem;
+}
+
+inline void fill_mem(void *buf, size_t buf_size, char *fill, size_t fill_len)
+{
+	size_t i;
+
+	if (fill_len == 1) {
+		memset(buf, fill[0], buf_size);
+	} else {
+		if (buf_size > fill_len) {
+			for (i = 0; i < buf_size - fill_len; i += fill_len)
+				memcpy(((char *)buf) + i, fill, fill_len);
+			memcpy(buf + i, fill, buf_size - i);
+		} else {
+			memcpy(buf, fill, buf_size);
+		}
+	}
+}

             reply	other threads:[~2011-08-24 22:25 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-24 22:25 David Evensky [this message]
2011-08-25  3:27 ` [PATCH] kvm tools: adds a PCI device that exports a host shared segment as a PCI BAR in the guest Alexander Graf
2011-08-25  4:49   ` David Evensky
2011-08-25  4:52     ` Alexander Graf
2011-08-25  5:11       ` Pekka Enberg
     [not found]         ` <A16CB574-D2F7-440B-BD26-12EB4DEAD917@suse.de>
2011-08-25  5:37           ` Pekka Enberg
2011-08-25  5:38             ` Alexander Graf
2011-08-25  5:06     ` Pekka Enberg
2011-08-25  5:49       ` David Evensky
2011-08-25 10:31       ` Stefan Hajnoczi
2011-08-25 10:37         ` Pekka Enberg
2011-08-25 10:59           ` Stefan Hajnoczi
2011-08-25 11:15             ` Pekka Enberg
2011-08-25 11:30               ` Avi Kivity
2011-08-25 11:38                 ` Pekka Enberg
2011-08-25 11:51                   ` Avi Kivity
2011-08-25 12:01                     ` Pekka Enberg
2011-08-25 11:51                 ` Sasha Levin
2011-08-25 11:25             ` Sasha Levin
2011-08-25 15:08               ` David Evensky
2011-08-25 22:08                 ` Eric Northup
2011-08-25 22:27                   ` David Evensky
2011-08-26  6:33                 ` Sasha Levin
2011-08-26 15:05                   ` David Evensky
     [not found]               ` <30669_1314285268_p7PFESZN013126_20110825150806.GF24996@dancer.ca.sandia.gov>
2011-08-25 21:00                 ` David Evensky
2011-08-25 21:11                   ` Avi Kivity
2011-08-25 22:03                     ` David Evensky
2011-08-28  7:34                       ` Avi Kivity
2011-08-29  4:55                         ` David Evensky
2011-08-25  5:41 ` Avi Kivity
2011-08-25  6:01   ` David Evensky
2011-08-25  6:02 ` Pekka Enberg
2011-08-25  6:11   ` David Evensky
     [not found] ` <CAFO3S41WOutTEmMGAeor6w=OZ_cax_AHB7Wo24jfUioynv3DFg@mail.gmail.com>
     [not found]   ` <4E55E378.4060904@kernel.org>
2011-08-25  6:30     ` Asias He
2011-08-25  7:02       ` Pekka Enberg
2011-08-25  7:20         ` Asias He
2011-08-25  7:24           ` Pekka Enberg
2011-08-25 21:35 ` Anthony Liguori
2011-08-25 21:50   ` David Evensky
2011-08-26  6:11   ` Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110824222510.GC14835@dancer.ca.sandia.gov \
    --to=evensky@sandia.gov \
    --cc=kvm@vger.kernel.org \
    --cc=levinsasha928@gmail.com \
    --cc=penberg@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.