Samuel Thibault
2008-Jul-02 12:50 UTC
[Xen-devel] [PATCH] stubdom: PCI passthrough support via PV-PCI
stubdom: PCI passthrough support via PV-PCI Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com> diff -r 0361bcf5d310 extras/mini-os/include/pcifront.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/pcifront.h Wed Jul 02 13:43:01 2008 +0100 @@ -0,0 +1,15 @@ +#include <types.h> +#include <xen/io/pciif.h> +struct pcifront_dev; +struct pcifront_dev *init_pcifront(char *nodename); +void pcifront_scan(struct pcifront_dev *dev, void (*fun)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun)); +void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op); +void shutdown_pcifront(struct pcifront_dev *dev); +int pcifront_conf_read(struct pcifront_dev *dev, + unsigned int dom, + unsigned int bus, unsigned int slot, unsigned long fun, + unsigned int off, unsigned int size, unsigned int *val); +int pcifront_conf_write(struct pcifront_dev *dev, + unsigned int dom, + unsigned int bus, unsigned int slot, unsigned long fun, + unsigned int off, unsigned int size, unsigned int val); diff -r 0361bcf5d310 extras/mini-os/include/posix/sys/mman.h --- a/extras/mini-os/include/posix/sys/mman.h Tue Jul 01 14:48:29 2008 +0100 +++ b/extras/mini-os/include/posix/sys/mman.h Wed Jul 02 13:43:01 2008 +0100 @@ -9,6 +9,9 @@ #define MAP_PRIVATE 0x02 #define MAP_ANON 0x20 +/* Pages are always resident anyway */ +#define MAP_LOCKED 0x0 + #define MAP_FAILED ((void*)0) void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); diff -r 0361bcf5d310 extras/mini-os/kernel.c --- a/extras/mini-os/kernel.c Tue Jul 01 14:48:29 2008 +0100 +++ b/extras/mini-os/kernel.c Wed Jul 02 13:43:01 2008 +0100 @@ -40,6 +40,7 @@ #include <netfront.h> #include <blkfront.h> #include <fbfront.h> +#include <pcifront.h> #include <fs.h> #include <xmalloc.h> #include <fcntl.h> @@ -431,6 +432,27 @@ } } +static struct pcifront_dev *pci_dev; + +static void pcifront_thread(void *p) +{ + void print(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) + { + unsigned int vendor, device, rev, class; + + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev); + pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class); + + printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev); + } + + pci_dev = init_pcifront(NULL); + printk("PCI devices:\n"); + pcifront_scan(pci_dev, print); +} + static void fs_thread(void *p) { init_fs_frontend(); @@ -446,6 +468,7 @@ create_thread("blkfront", blkfront_thread, si); create_thread("fbfront", fbfront_thread, si); create_thread("kbdfront", kbdfront_thread, si); + create_thread("pcifront", pcifront_thread, si); create_thread("fs-frontend", fs_thread, si); return 0; } @@ -524,6 +547,9 @@ if (kbd_dev) shutdown_kbdfront(kbd_dev); + if (pci_dev) + shutdown_pcifront(pci_dev); + /* TODO: fs import */ local_irq_disable(); diff -r 0361bcf5d310 extras/mini-os/pcifront.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/pcifront.c Wed Jul 02 13:43:01 2008 +0100 @@ -0,0 +1,278 @@ +/* Minimal PCI driver for Mini-OS. + * Copyright (c) 2007-2008 Samuel Thibault. + * Based on blkfront.c. + */ + +#include <os.h> +#include <xenbus.h> +#include <events.h> +#include <errno.h> +#include <gnttab.h> +#include <xmalloc.h> +#include <wait.h> +#include <pcifront.h> + +#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) + +DECLARE_WAIT_QUEUE_HEAD(pcifront_queue); + +struct pcifront_dev { + domid_t dom; + + struct xen_pci_sharedinfo *info; + grant_ref_t info_ref; + evtchn_port_t evtchn; + + char *nodename; + char *backend; + + xenbus_event_queue events; +}; + +void pcifront_handler(evtchn_port_t port, struct pt_regs *regs, void *data) +{ + wake_up(&pcifront_queue); +} + +static void free_pcifront(struct pcifront_dev *dev) +{ + mask_evtchn(dev->evtchn); + + free(dev->backend); + + gnttab_end_access(dev->info_ref); + free_page(dev->info); + + unbind_evtchn(dev->evtchn); + + free(dev->nodename); + free(dev); +} + +struct pcifront_dev *init_pcifront(char *nodename) +{ + xenbus_transaction_t xbt; + char* err; + char* message=NULL; + int retry=0; + char* msg; + + struct pcifront_dev *dev; + + if (!nodename) + nodename = "device/pci/0"; + + char path[strlen(nodename) + 1 + 10 + 1]; + + printk("******************* PCIFRONT for %s **********\n\n\n", nodename); + + dev = malloc(sizeof(*dev)); + memset(dev, 0, sizeof(*dev)); + dev->nodename = strdup(nodename); + + snprintf(path, sizeof(path), "%s/backend-id", nodename); + dev->dom = xenbus_read_integer(path); + evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn); + + dev->info = (struct xen_pci_sharedinfo*) alloc_page(); + memset(dev->info,0,PAGE_SIZE); + + dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0); + + dev->events = NULL; + +again: + err = xenbus_transaction_start(&xbt); + if (err) { + printk("starting transaction\n"); + } + + err = xenbus_printf(xbt, nodename, "pci-op-ref","%u", + dev->info_ref); + if (err) { + message = "writing pci-op-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, + "event-channel", "%u", dev->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + err = xenbus_printf(xbt, nodename, + "magic", XEN_PCI_MAGIC); + if (err) { + message = "writing magic"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, nodename, "state", "%u", + 3); /* initialised */ + + + err = xenbus_transaction_end(xbt, 0, &retry); + if (retry) { + goto again; + printk("completing transaction\n"); + } + + goto done; + +abort_transaction: + xenbus_transaction_end(xbt, 1, &retry); + goto error; + +done: + + snprintf(path, sizeof(path), "%s/backend", nodename); + msg = xenbus_read(XBT_NIL, path, &dev->backend); + if (msg) { + printk("Error %s when reading the backend path %s\n", msg, path); + goto error; + } + + printk("backend at %s\n", dev->backend); + + { + char path[strlen(dev->backend) + 1 + 5 + 1]; + snprintf(path, sizeof(path), "%s/state", dev->backend); + + xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); + + xenbus_wait_for_value(path, "4", &dev->events); + + xenbus_printf(xbt, nodename, "state", "%u", 4); /* connected */ + } + unmask_evtchn(dev->evtchn); + + printk("**************************\n"); + + return dev; + +error: + free_pcifront(dev); + return NULL; +} + +void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun)) +{ + char path[strlen(dev->backend) + 1 + 5 + 10 + 1]; + int i, n; + char *s, *msg; + unsigned int domain, bus, slot, fun; + + snprintf(path, sizeof(path), "%s/num_devs", dev->backend); + n = xenbus_read_integer(path); + + for (i = 0; i < n; i++) { + snprintf(path, sizeof(path), "%s/vdev-%d", dev->backend, i); + msg = xenbus_read(XBT_NIL, path, &s); + if (msg) { + printk("Error %s when reading the PCI root name at %s\n", path); + continue; + } + + if (sscanf(s, "%x:%x:%x.%x", &domain, &bus, &slot, &fun) != 4) { + printk("\"%s\" does not look like a PCI device address\n", s); + free(s); + continue; + } + free(s); + + func(domain, bus, slot, fun); + } +} + +void shutdown_pcifront(struct pcifront_dev *dev) +{ + char* err; + char *nodename = dev->nodename; + + char path[strlen(dev->backend) + 1 + 5 + 1]; + + printk("close pci: backend at %s\n",dev->backend); + + snprintf(path, sizeof(path), "%s/state", dev->backend); + err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */ + xenbus_wait_for_value(path, "5", &dev->events); + + err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6); + xenbus_wait_for_value(path, "6", &dev->events); + + err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1); + xenbus_wait_for_value(path, "2", &dev->events); + + xenbus_unwatch_path(XBT_NIL, path); + + snprintf(path, sizeof(path), "%s/info-ref", nodename); + xenbus_rm(XBT_NIL, path); + snprintf(path, sizeof(path), "%s/event-channel", nodename); + xenbus_rm(XBT_NIL, path); + + free_pcifront(dev); +} + + +void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op) +{ + dev->info->op = *op; + /* Make sure info is written before the flag */ + wmb(); + set_bit(_XEN_PCIF_active, &dev->info->flags); + notify_remote_via_evtchn(dev->evtchn); + + wait_event(pcifront_queue, !test_bit(_XEN_PCIF_active, &dev->info->flags)); + + /* Make sure flag is read before info */ + rmb(); + *op = dev->info->op; +} + +int pcifront_conf_read(struct pcifront_dev *dev, + unsigned int dom, + unsigned int bus, unsigned int slot, unsigned long fun, + unsigned int off, unsigned int size, unsigned int *val) +{ + struct xen_pci_op op; + + memset(&op, 0, sizeof(op)); + + op.cmd = XEN_PCI_OP_conf_read; + op.domain = dom; + op.bus = bus; + op.devfn = PCI_DEVFN(slot, fun); + op.offset = off; + op.size = size; + + pcifront_op(dev, &op); + + if (op.err) + return op.err; + + *val = op.value; + + return 0; +} + +int pcifront_conf_write(struct pcifront_dev *dev, + unsigned int dom, + unsigned int bus, unsigned int slot, unsigned long fun, + unsigned int off, unsigned int size, unsigned int val) +{ + struct xen_pci_op op; + + memset(&op, 0, sizeof(op)); + + op.cmd = XEN_PCI_OP_conf_write; + op.domain = dom; + op.bus = bus; + op.devfn = PCI_DEVFN(slot, fun); + op.offset = off; + op.size = size; + + op.value = val; + + pcifront_op(dev, &op); + + return op.err; +} diff -r 0361bcf5d310 stubdom/Makefile --- a/stubdom/Makefile Tue Jul 01 14:48:29 2008 +0100 +++ b/stubdom/Makefile Wed Jul 02 13:43:01 2008 +0100 @@ -132,16 +132,20 @@ pciutils-$(LIBPCI_VERSION).tar.bz2: $(WGET) http://www.kernel.org/pub/software/utils/pciutils/pciutils-$(LIBPCI_VERSION).tar.bz2 +pciutils-$(LIBPCI_VERSION): pciutils-$(LIBPCI_VERSION).tar.bz2 + tar xjf $< + patch -d $@ -p1 < pciutils.patch + touch $@ + LIBPCI_STAMPFILE=$(CROSS_ROOT)/$(GNU_TARGET_ARCH)-xen-elf/lib/libpci.a .PHONY: cross-libpci cross-libpci: $(LIBPCI_STAMPFILE) -$(LIBPCI_STAMPFILE): pciutils-$(LIBPCI_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) $(ZLIB_STAMPFILE) - tar xjf $< +$(LIBPCI_STAMPFILE): pciutils-$(LIBPCI_VERSION) $(NEWLIB_STAMPFILE) $(ZLIB_STAMPFILE) ( cd pciutils-$(LIBPCI_VERSION) && \ cp ../libpci.config.h lib/config.h && \ echo ''#define PCILIB_VERSION "$(LIBPCI_VERSION)"'' >> lib/config.h && \ cp ../libpci.config.mak lib/config.mk && \ - $(MAKE) CC="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS)" lib/libpci.a && \ + $(MAKE) CC="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS) -I$(realpath $(MINI_OS)/include)" lib/libpci.a && \ $(INSTALL_DATA) lib/libpci.a $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/lib/ && \ $(INSTALL_DIR) $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci && \ $(INSTALL_DATA) lib/{config,header,pci,types}.h $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci/ \ diff -r 0361bcf5d310 stubdom/libpci.config.h --- a/stubdom/libpci.config.h Tue Jul 01 14:48:29 2008 +0100 +++ b/stubdom/libpci.config.h Wed Jul 02 13:43:01 2008 +0100 @@ -1,4 +1,4 @@ -#define PCI_OS_STUBDOM +#define PCI_OS_MINIOS #define PCI_HAVE_STDINT_H #define PCI_PATH_IDS_DIR "." #define PCI_COMPRESSED_IDS diff -r 0361bcf5d310 stubdom/libpci.config.mak --- a/stubdom/libpci.config.mak Tue Jul 01 14:48:29 2008 +0100 +++ b/stubdom/libpci.config.mak Wed Jul 02 13:43:01 2008 +0100 @@ -1,2 +1,7 @@ LIBZ=-lz LDLIBS+=$(LIBZ) +PCI_OS_MINIOS=1 +PCI_HAVE_STDINT_H=1 +PCI_PATH_IDS_DIR=. +PCI_COMPRESSED_IDS=1 +PCI_IDS=pci.ids.gz diff -r 0361bcf5d310 stubdom/pciutils.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stubdom/pciutils.patch Wed Jul 02 13:43:01 2008 +0100 @@ -0,0 +1,299 @@ +diff -urN pciutils-2.2.9.orig/lib/access.c pciutils-2.2.9/lib/access.c +--- pciutils-2.2.9.orig/lib/access.c 2007-02-06 11:59:43.000000000 +0000 ++++ pciutils-2.2.9/lib/access.c 2008-06-30 19:07:09.713187000 +0100 +@@ -57,6 +57,11 @@ + #else + NULL, + #endif ++#ifdef PCI_OS_MINIOS ++ &pm_minios, ++#else ++ NULL, ++#endif + }; + + struct pci_access * +--- pciutils-2.2.9.orig/lib/pci.h 2006-09-09 13:46:06.000000000 +0100 ++++ pciutils-2.2.9/lib/pci.h 2008-06-30 18:56:15.350111000 +0100 +@@ -33,6 +33,7 @@ + PCI_ACCESS_NBSD_LIBPCI, /* NetBSD libpci */ + PCI_ACCESS_OBSD_DEVICE, /* OpenBSD /dev/pci */ + PCI_ACCESS_DUMP, /* Dump file (params: filename) */ ++ PCI_ACCESS_MINIOS, /* MiniOS */ + PCI_ACCESS_MAX + }; + +@@ -63,6 +64,7 @@ + int fd_rw; /* proc: fd opened read-write */ + struct pci_dev *cached_dev; /* proc: device the fd is for */ + int fd_pos; /* proc: current position */ ++ void *minios; + }; + + /* Initialize PCI access */ +--- pciutils-2.2.9.orig/lib/internal.h 2006-09-09 11:52:47.000000000 +0100 ++++ pciutils-2.2.9/lib/internal.h 2008-07-01 10:46:24.968202000 +0100 +@@ -37,4 +37,4 @@ + + extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc, + pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device, +- pm_dump, pm_linux_sysfs; ++ pm_dump, pm_linux_sysfs, pm_minios; +--- pciutils-2.2.9.orig/lib/Makefile 2007-10-19 13:41:34.000000000 +0100 ++++ pciutils-2.2.9/lib/Makefile 2008-07-01 12:13:14.400525000 +0100 +@@ -46,6 +46,12 @@ + PCILIB=libpciutils.a + endif + ++ifdef PCI_OS_MINIOS ++XEN_ROOT=../../.. ++include $(XEN_ROOT)/Config.mk ++OBJS += minios.o ++endif ++ + all: $(PCILIB) $(PCILIBPC) + + $(PCILIB): $(OBJS) +--- pciutils-2.2.9.orig/lib/types.h 2007-09-03 09:44:15.000000000 +0100 ++++ pciutils-2.2.9/lib/types.h 2008-07-01 12:17:08.396156000 +0100 +@@ -17,9 +17,13 @@ + typedef DWORD u32; + #elif defined(PCI_HAVE_STDINT_H) + #include <stdint.h> ++#ifdef PCI_OS_MINIOS ++#include <types.h> ++#else + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; ++#endif + #else + typedef u_int8_t u8; + typedef u_int16_t u16; +--- pciutils-2.2.9.orig/lib/minios.c 1970-01-01 01:00:00.000000000 +0100 ++++ pciutils-2.2.9/lib/minios.c 2008-07-01 12:31:40.554260000 +0100 +@@ -0,0 +1,113 @@ ++/* ++ * The PCI Library -- MiniOS PCI frontend access ++ * ++ * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008 ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++ */ ++ ++#include <os.h> ++#include <pcifront.h> ++#include <xenbus.h> ++#include "internal.h" ++ ++static int ++minios_detect(struct pci_access *a) ++{ ++ return 1; ++} ++ ++static void ++minios_init(struct pci_access *a) ++{ ++ a->minios = init_pcifront(NULL); ++ if (!a->minios) ++ a->warning("minios_init open failed"); ++} ++ ++static void ++minios_cleanup(struct pci_access *a) ++{ ++ if (a->minios) ++ shutdown_pcifront(a->minios); ++} ++ ++static void ++minios_scan(struct pci_access *a) ++{ ++ if (!a->minios) ++ return; ++ ++ void func(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun) ++ { ++ struct pci_dev *d = pci_alloc_dev(a); ++ ++ d->domain = domain; ++ d->bus = bus; ++ d->dev = slot; ++ d->func = fun; ++ ++ pci_link_dev(a, d); ++ } ++ ++ pcifront_scan(a->minios, func); ++} ++ ++static int ++minios_read(struct pci_dev *d, int pos, byte *buf, int len) ++{ ++ unsigned int val; ++ switch (len) { ++ case 1: ++ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ return 0; ++ * buf = val; ++ return 1; ++ case 2: ++ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ return 0; ++ *(u16 *) buf = cpu_to_le16((u16) val); ++ return 1; ++ case 4: ++ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val)) ++ return 0; ++ *(u32 *) buf = cpu_to_le32((u32) val); ++ return 1; ++ default: ++ return pci_generic_block_read(d, pos, buf, len); ++ } ++} ++ ++static int ++minios_write(struct pci_dev *d, int pos, byte *buf, int len) ++{ ++ unsigned int val; ++ switch (len) { ++ case 1: ++ val = * buf; ++ break; ++ case 2: ++ val = le16_to_cpu(*(u16 *) buf); ++ break; ++ case 4: ++ val = le32_to_cpu(*(u32 *) buf); ++ break; ++ default: ++ return pci_generic_block_write(d, pos, buf, len); ++ } ++ return !pcifront_conf_write(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, val); ++} ++ ++struct pci_methods pm_minios = { ++ "MiniOS-device", ++ NULL, /* config */ ++ minios_detect, ++ minios_init, ++ minios_cleanup, ++ minios_scan, ++ pci_generic_fill_info, ++ minios_read, ++ minios_write, ++ NULL, /* dev_init */ ++ NULL /* dev_cleanup */ ++}; +--- pciutils-2.2.9/lib/generic.c 2007-02-06 12:00:05.000000000 +0000 ++++ pciutils-2.2.9-mine/lib/generic.c 2008-07-01 19:13:52.289949000 +0100 +@@ -74,6 +74,19 @@ + pci_generic_scan_bus(a, busmap, 0); + } + ++static u32 pci_size(u32 base, u32 maxbase, u32 mask) ++{ ++ u32 size = mask & maxbase; ++ if (!size) ++ return 0; ++ size = (size & ~(size-1)) - 1; ++ ++ if (base == maxbase && ((base | size) & mask) != mask) ++ return 0; ++ ++ return size + 1; ++} ++ + int + pci_generic_fill_info(struct pci_dev *d, int flags) + { +@@ -114,23 +127,61 @@ + if (!x || x == (u32) ~0) + continue; + if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +- d->base_addr[i] = x; +- else ++ { ++ d->base_addr[i] = x & PCI_BASE_ADDRESS_IO_MASK; ++ if (flags & PCI_FILL_SIZES) ++ { ++ u32 size; ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0); ++ d->size[i] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), PCI_BASE_ADDRESS_IO_MASK); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, x); ++ } ++ } ++ else + { + if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64) +- d->base_addr[i] = x; ++ { ++ d->base_addr[i] = x & PCI_BASE_ADDRESS_MEM_MASK; ++ if (flags & PCI_FILL_SIZES) ++ { ++ u32 size; ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0); ++ d->size[i] = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4); ++ d->size[i] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), PCI_BASE_ADDRESS_MEM_MASK); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, x); ++ } ++ } + else if (i >= cnt-1) + a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i); + else + { + u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4); + #ifdef PCI_HAVE_64BIT_ADDRESS +- d->base_addr[i-1] = x | (((pciaddr_t) y) << 32); ++ d->base_addr[i-1] = (x | (((pciaddr_t) y) << 32)) & PCI_BASE_ADDRESS_MEM_MASK; ++ if (flags & PCI_FILL_SIZES) ++ { ++ u32 size; ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, ~0); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0); ++ d->size[i-1] = pci_size(y, pci_read_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4) | ++ pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), 0xffffffff ); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, x); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, y); ++ } + #else + if (y) + a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func); + else +- d->base_addr[i-1] = x; ++ { ++ d->base_addr[i-1] = x & PCI_BASE_ADDRESS_MEM_MASK; ++ if (flags & PCI_FILL_SIZES) ++ { ++ u32 size; ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, ~0); ++ d->size[i-1] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4), PCI_BASE_ADDRESS_MEM_MASK); ++ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, x); ++ } ++ } + #endif + } + } +@@ -154,10 +205,19 @@ + { + u32 u = pci_read_long(d, reg); + if (u != 0xffffffff) +- d->rom_base_addr = u; ++ { ++ d->rom_base_addr = u; ++ if (flags & PCI_FILL_SIZES) ++ { ++ u32 size; ++ pci_write_long(d, reg, ~0); ++ d->rom_size = pci_read_long(d, reg); ++ pci_write_long(d, reg, u); ++ } ++ } + } + } +- return flags & ~PCI_FILL_SIZES; ++ return flags; + } + + static int diff -r 0361bcf5d310 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Tue Jul 01 14:48:29 2008 +0100 +++ b/tools/ioemu/Makefile.target Wed Jul 02 13:43:01 2008 +0100 @@ -358,7 +358,7 @@ endif ifdef CONFIG_STUBDOM -#CONFIG_PASSTHROUGH=1 +CONFIG_PASSTHROUGH=1 else ifeq (,$(wildcard /usr/include/pci)) $(warning *** pciutils-devl package not found - missing /usr/include/pci) diff -r 0361bcf5d310 tools/ioemu/hw/pass-through.c --- a/tools/ioemu/hw/pass-through.c Tue Jul 01 14:48:29 2008 +0100 +++ b/tools/ioemu/hw/pass-through.c Wed Jul 02 13:43:01 2008 +0100 @@ -515,6 +515,7 @@ PT_LOG("Error: couldn''t locate device in libpci structures\n"); return NULL; } + pci_fill_info(pci_dev, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); if ( e_devfn == PT_VIRT_DEVFN_AUTO ) { /*indicate a static assignment(not hotplug), so find a free PCI hot plug slot */ diff -r 0361bcf5d310 tools/ioemu/xenstore.c --- a/tools/ioemu/xenstore.c Tue Jul 01 14:48:29 2008 +0100 +++ b/tools/ioemu/xenstore.c Wed Jul 02 13:43:01 2008 +0100 @@ -322,7 +322,7 @@ /* get the pci pass-through parameter */ if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs", - domid, pci_devid) == -1) + hvm_domid, pci_devid) == -1) goto out; free(params); @@ -333,7 +333,7 @@ for ( i = 0; i < num; i++ ) { if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d", - domid, pci_devid, i) != -1) { + hvm_domid, pci_devid, i) != -1) { free(dev); dev = xs_read(xsh, XBT_NULL, buf, &len); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Note however that it can not work as such because ioemu needs to perform some domctls, which the hypervisor will not let the stub domain do. We need to find a secure way to allow a domain to call memory/IO mapping and IRQ/MSI binding domctls when it is allowed to, i.e. probably have xend tell the hypervisor which PCI cards are controlled by which domains and then accept domctls for their resources. Samuel _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Shouldn''t they happen from xend or pciback? -- Keir On 2/7/08 13:58, "Samuel Thibault" <samuel.thibault@eu.citrix.com> wrote:> Note however that it can not work as such because ioemu needs to perform > some domctls, which the hypervisor will not let the stub domain do. We > need to find a secure way to allow a domain to call memory/IO mapping > and IRQ/MSI binding domctls when it is allowed to, i.e. probably have > xend tell the hypervisor which PCI cards are controlled by which domains > and then accept domctls for their resources. > > Samuel > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xensource.com > http://lists.xensource.com/xen-devel_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Samuel Thibault
2008-Jul-02 13:29 UTC
Re: [Xen-devel] Re: PCI passthrough support via PV-PCI
Keir Fraser, le Wed 02 Jul 2008 13:59:42 +0100, a écrit :> Shouldn''t they happen from xend or pciback?For PV guests it looks like something is done indeed, because else it wouldn''t work. It is probably a matter of having domctl permit the stub domain to transfer these rights to the HVM guest. Samuel _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Espen Skoglund
2008-Jul-02 14:18 UTC
Re: [Xen-devel] Re: PCI passthrough support via PV-PCI
[Samuel Thibault]> Keir Fraser, le Wed 02 Jul 2008 13:59:42 +0100, a écrit : >> Shouldn''t they happen from xend or pciback?> For PV guests it looks like something is done indeed, because else > it wouldn''t work. It is probably a matter of having domctl permit > the stub domain to transfer these rights to the HVM guest.When I added VT-d support for PV guests I made xend do the device assignment iff the destination was a PV domain. Is there any reason why device assignment can not be performed by xend for HVM guests as well? Other resource assignment (IOMEM and IRQs) still seems to happen in xend for HVM guests as well as for PV guest. What other domctls does ioemu need to perform? eSk _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Samuel Thibault
2008-Jul-02 14:28 UTC
Re: [Xen-devel] Re: PCI passthrough support via PV-PCI
Espen Skoglund, le Wed 02 Jul 2008 15:18:16 +0100, a écrit :> [Samuel Thibault] > > Keir Fraser, le Wed 02 Jul 2008 13:59:42 +0100, a écrit : > >> Shouldn''t they happen from xend or pciback? > > > For PV guests it looks like something is done indeed, because else > > it wouldn''t work. It is probably a matter of having domctl permit > > the stub domain to transfer these rights to the HVM guest. > > When I added VT-d support for PV guests I made xend do the device > assignment iff the destination was a PV domain. Is there any reason > why device assignment can not be performed by xend for HVM guests as > well? > > Other resource assignment (IOMEM and IRQs) still seems to happen in > xend for HVM guests as well as for PV guest. What other domctls does > ioemu need to perform?ioemu needs to update the mappings, see the pt_iomem_map() function. Samuel _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On 2/7/08 15:28, "Samuel Thibault" <samuel.thibault@eu.citrix.com> wrote:>> When I added VT-d support for PV guests I made xend do the device >> assignment iff the destination was a PV domain. Is there any reason >> why device assignment can not be performed by xend for HVM guests as >> well? >> >> Other resource assignment (IOMEM and IRQs) still seems to happen in >> xend for HVM guests as well as for PV guest. What other domctls does >> ioemu need to perform? > > ioemu needs to update the mappings, see the pt_iomem_map() function.I suggest the domctls should set up access permissions (e.g., by use of existing iomem_premission domctl). And then extend XENMEM_add_to_physmap to allow (re-)mapping of permitted I/O ranges into pseudophysical address space. The new passthru-specific domctls may well be ill conceived. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel