QEMU will now register PCI in Xen. It will usefull to forward IO config space to the right QEMU.
Before to register a PCI device, QEMU will check with XenStore if it is autorized to register the PCI associate to a given BDF. Signed-off-by: Julien Grall <julien.gr...@citrix.com> --- hw/pci.c | 6 +++++ xen-all.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 0 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index bf046bf..4df4449 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -31,6 +31,7 @@ #include "loader.h" #include "range.h" #include "qmp-commands.h" +#include "xen.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -764,6 +765,11 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->devfn = devfn; pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); pci_dev->irq_state = 0; + + if (xen_enabled() && xen_register_pcidev(pci_dev)) { + return NULL; + } + pci_config_alloc(pci_dev); pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); diff --git a/xen-all.c b/xen-all.c index 366bafe..2f5405c 100644 --- a/xen-all.c +++ b/xen-all.c @@ -107,6 +107,76 @@ void xen_piix3_set_irq(void *opaque, int irq_num, int level) irq_num & 3, level); } +static uint32_t str_to_bdf(const char *str) +{ + /* We assume that bdf is valid */ + char *buf; + uint32_t bdf; + uint32_t tmp; + + bdf = strtol(str, &buf, 16); + buf++; + + str = buf; + tmp = strtol(str, &buf, 16); + bdf = (bdf << 16) | (tmp << 11); + buf++; + + str = buf; + tmp = strtol(str, &buf, 16); + bdf = bdf | (tmp << 8); + + return bdf; +} + +int xen_register_pcidev(PCIDevice *pci_dev) +{ + struct xs_handle *xs = NULL; + uint32_t bdf = 0; + uint32_t allowed_bdf = 0; + char **dir; + char path[50]; + unsigned int nb; + unsigned int i; + unsigned int len; + char *str; + int rc = 0; + + + /* Fix : missing bus id to be more generic */ + bdf |= pci_dev->devfn << 8; + + xs = xs_open(0); + if (!xs) { + fprintf(stderr, "pci_register: Unable to open xenstore\n"); + return 1; + } + + snprintf(path, sizeof (path), "/local/domain/%u/image/dms/%u/pci", + xen_domid, xen_dmid); + + dir = xs_directory(xs, XBT_NULL, path, &nb); + if (dir) { + for (i = 0; i < nb; i++) { + snprintf(path, sizeof (path), "/local/domain/%u/image/dms/%u/pci/%s", + xen_domid, xen_dmid, dir[i]); + str = xs_read(xs, XBT_NULL, path, &len); + allowed_bdf = str_to_bdf(str); + free(str); + if (bdf == allowed_bdf) + { + rc = xc_hvm_register_pcidev(xen_xc, xen_domid, serverid, bdf); + break; + } + } + free(dir); + } + + xs_close(xs); + + return rc; +} + void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len) { int i; -- Julien Grall