WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] PCI passthru: tools changes (generic and

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] PCI passthru: tools changes (generic and vt-d)
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 26 Sep 2007 03:40:23 -0700
Delivery-date: Wed, 26 Sep 2007 04:29:58 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1189784367 -3600
# Node ID acfa9290746f9c00e30dca7a62e9f7a96702b3b5
# Parent  b3f681d712659582112c33b36bd31dab6f1a96b8
PCI passthru: tools changes (generic and vt-d)

I have added CONFIG_PASSTHROUGH in ioemu/Makefile.target and
ioemu/hw/pc.c in attached vtd_tools2.patch.  This should turn off
libpci usage by default until user specifically enables it.

This can be safely check-in without breaking builds for people who do
not care about pass-through devices.  I will try to think of a better
way to enable this.

Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx>
Signed-off-by: Guy Zana <guy@xxxxxxxxxxxx>
---
 tools/ioemu/Makefile.target         |    6 
 tools/ioemu/hw/pass-through.c       |  454 ++++++++++++++++++++++++++++++++++++
 tools/ioemu/hw/pass-through.h       |   89 +++++++
 tools/ioemu/hw/pc.c                 |   27 +-
 tools/ioemu/vl.c                    |   12 
 tools/ioemu/vl.h                    |    2 
 tools/libxc/xc_domain.c             |  108 ++++++++
 tools/libxc/xenctrl.h               |   39 +++
 tools/python/xen/xend/XendConfig.py |    3 
 tools/python/xen/xend/image.py      |    2 
 tools/python/xen/xm/create.py       |    2 
 11 files changed, 732 insertions(+), 12 deletions(-)

diff -r b3f681d71265 -r acfa9290746f tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target       Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/ioemu/Makefile.target       Fri Sep 14 16:39:27 2007 +0100
@@ -197,6 +197,9 @@ LIBS+=-lm
 LIBS+=-lm
 LIBS+=-L../../libxc -lxenctrl -lxenguest
 LIBS+=-L../../xenstore -lxenstore
+ifdef CONFIG_PASSTHROUGH
+LIBS+=-lpci
+endif
 ifndef CONFIG_USER_ONLY
 LIBS+=-lz
 endif
@@ -400,6 +403,9 @@ VL_OBJS+= xenstore.o
 VL_OBJS+= xenstore.o
 VL_OBJS+= xen_platform.o
 VL_OBJS+= tpm_tis.o
+ifdef CONFIG_PASSTHROUGH
+VL_OBJS+= pass-through.o
+endif
 CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
diff -r b3f681d71265 -r acfa9290746f tools/ioemu/hw/pass-through.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/hw/pass-through.c     Fri Sep 14 16:39:27 2007 +0100
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Alex Novik <alex@xxxxxxxxxxxx>
+ * Allen Kay <allen.m.kay@xxxxxxxxx>
+ * Guy Zana <guy@xxxxxxxxxxxx>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ *
+ */
+#include "vl.h"
+#include "pass-through.h"
+#include "pci/header.h"
+#include "pci/pci.h"
+
+extern FILE *logfile;
+char *token;
+
+int pci_devs(const char *direct_pci)
+{
+    int count = 0;
+    const char *c;
+
+    /* skip first "[" character */
+    c = direct_pci + 1;
+    while ((c = strchr(c, '[')) != NULL) {
+        c++;
+        count++;
+    }
+    return (count);
+}
+
+int next_token(char *direct_pci)
+{
+    if (token == NULL)
+        token = strtok(direct_pci, ",");
+    else 
+        token = strtok(NULL, ",");
+    token = strchr(token, 'x');
+    token = token + 1;
+    return ((int) strtol(token, NULL, 16));
+}
+
+void next_bdf(char *direct_pci, int *seg,
+              int *bus, int *dev, int *func)
+{
+    *seg  = next_token(direct_pci);
+    *bus  = next_token(direct_pci);
+    *dev  = next_token(direct_pci);
+    *func = next_token(direct_pci);
+}
+
+uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
+{
+    int id;
+    int max_cap = 48;
+    int pos = PCI_CAPABILITY_LIST;
+    int status;
+
+    status = pci_read_byte(pci_dev, PCI_STATUS);
+    if ( (status & PCI_STATUS_CAP_LIST) == 0 )
+        return 0;
+
+    while ( max_cap-- )
+    {
+        pos = pci_read_byte(pci_dev, pos);
+        if ( pos < 0x40 )
+            break;
+
+        pos &= ~3;
+        id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);
+
+        if ( id == 0xff )
+            break;
+        if ( id == cap )
+            return pos;
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+void pdev_flr(struct pci_dev *pci_dev)
+{
+    int pos;
+    int dev_cap;
+    int dev_status;
+
+    pos = find_cap_offset(pci_dev, PCI_CAP_ID_EXP);
+    if ( pos )
+    {
+        dev_cap = pci_read_long(pci_dev, pos + PCI_EXP_DEVCAP);
+        if ( dev_cap & PCI_EXP_DEVCAP_FLR )
+        {
+            pci_write_word(pci_dev, pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
+            do {
+                dev_status = pci_read_long(pci_dev, pos + PCI_EXP_DEVSTA);
+            } while (dev_status & PCI_EXP_DEVSTA_TRPND);
+        }
+    }
+}
+
+/* Being called each time a mmio region has been updated */
+void pt_iomem_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size,
+                  int type)
+{
+    struct pt_dev *assigned_device  = (struct pt_dev *)d; 
+    uint32_t old_ebase = assigned_device->bases[i].e_physbase;
+    int first_map = ( assigned_device->bases[i].e_size == 0 );
+    int ret = 0;
+
+    assigned_device->bases[i].e_physbase = e_phys;
+    assigned_device->bases[i].e_size= e_size;
+
+    PT_LOG("e_phys=%08x maddr=%08x type=%d len=%08x index=%d\n",
+        e_phys, assigned_device->bases[i].access.maddr, type, e_size, i);
+
+    if ( e_size == 0 )
+        return;
+
+    if ( !first_map )
+    {
+        /* Remove old mapping */
+        ret = xc_domain_memory_mapping(xc_handle, domid, old_ebase >> 12,
+                assigned_device->bases[i].access.maddr >> 12,
+                (e_size+0xFFF) >> 12,
+                DPCI_REMOVE_MAPPING);
+        if ( ret != 0 )
+        {
+            PT_LOG("Error: remove old mapping failed!\n");
+            return;
+        }
+    }
+
+    /* Create new mapping */
+    ret = xc_domain_memory_mapping(xc_handle, domid,
+            assigned_device->bases[i].e_physbase >> 12,
+            assigned_device->bases[i].access.maddr >> 12,
+            (e_size+0xFFF) >> 12,
+            DPCI_ADD_MAPPING);
+    if ( ret != 0 )
+        PT_LOG("Error: create new mapping failed!\n");
+
+}
+
+/* Being called each time a pio region has been updated */
+void pt_ioport_map(PCIDevice *d, int i,
+                   uint32_t e_phys, uint32_t e_size, int type)
+{
+    struct pt_dev *assigned_device  = (struct pt_dev *)d;
+    uint32_t old_ebase = assigned_device->bases[i].e_physbase;
+    int first_map = ( assigned_device->bases[i].e_size == 0 );
+    int ret = 0;
+
+    assigned_device->bases[i].e_physbase = e_phys;
+    assigned_device->bases[i].e_size= e_size;
+
+    PT_LOG("e_phys=%04x pio_base=%04x len=%04x index=%d\n",
+        (uint16_t)e_phys, (uint16_t)assigned_device->bases[i].access.pio_base,
+        (uint16_t)e_size, i);
+
+    if ( e_size == 0 )
+        return;
+
+    if ( !first_map )
+    {
+        /* Remove old mapping */
+        ret = xc_domain_ioport_mapping(xc_handle, domid, old_ebase,
+                    assigned_device->bases[i].access.pio_base, e_size,
+                    DPCI_REMOVE_MAPPING);
+        if ( ret != 0 )
+        {
+            PT_LOG("Error: remove old mapping failed!\n");
+            return;
+        }
+    }
+
+    /* Create new mapping */
+    ret = xc_domain_ioport_mapping(xc_handle, domid, e_phys,
+                assigned_device->bases[i].access.pio_base, e_size,
+                DPCI_ADD_MAPPING);
+    if ( ret != 0 )
+        PT_LOG("Error: create new mapping failed!\n");
+
+}
+
+static void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val,
+                                int len)
+{
+    struct pt_dev *assigned_device = (struct pt_dev *)d;
+    struct pci_dev *pci_dev = assigned_device->pci_dev;
+
+#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
+    PT_LOG("(%x.%x): address=%04x val=0x%08x len=%d\n",
+       (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
+#endif
+
+    /* Pre-write hooking */
+    switch ( address ) {
+    case 0x0C ... 0x3F:
+        pci_default_write_config(d, address, val, len);
+        return;
+    }
+
+    /* PCI config pass-through */
+    if (address == 0x4) {
+        switch (len){
+        case 1:
+            pci_write_byte(pci_dev, address, val);
+            break;
+        case 2:
+            pci_write_word(pci_dev, address, val);
+            break;
+        case 4:
+            pci_write_long(pci_dev, address, val);
+            break;
+        }
+    }
+
+    if (address == 0x4) {
+        /* Post-write hooking */
+        pci_default_write_config(d, address, val, len);
+    }
+}
+
+static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len)
+{
+    struct pt_dev *assigned_device = (struct pt_dev *)d;
+    struct pci_dev *pci_dev = assigned_device->pci_dev;
+    uint32_t val = 0xFF;
+
+    /* Pre-hooking */
+    switch ( address ) {
+    case 0x0C ... 0x3F:
+        val = pci_default_read_config(d, address, len);
+        goto exit;
+    }
+
+    switch ( len ) {
+    case 1:
+        val = pci_read_byte(pci_dev, address);
+        break;
+    case 2:
+        val = pci_read_word(pci_dev, address);
+        break;
+    case 4:
+        val = pci_read_long(pci_dev, address);
+        break;
+    }
+
+exit:
+
+#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
+    PT_LOG("(%x.%x): address=%04x val=0x%08x len=%d\n",
+       (d->devfn >> 3) & 0x1F, (d->devfn & 0x7), address, val, len);
+#endif
+
+    return val;
+}
+
+static int pt_register_regions(struct pt_dev *assigned_device)
+{
+    int i = 0;
+    uint32_t bar_data = 0;
+    struct pci_dev *pci_dev = assigned_device->pci_dev;
+    PCIDevice *d = &assigned_device->dev;
+
+    /* Register PIO/MMIO BARs */
+    for ( i=0; i < PCI_BAR_ENTRIES; i++ )
+    {
+        if ( pci_dev->base_addr[i] )
+        {
+            assigned_device->bases[i].e_physbase = pci_dev->base_addr[i];
+            assigned_device->bases[i].access.u = pci_dev->base_addr[i];
+
+            /* Register current region */
+            bar_data = *((uint32_t*)(d->config + PCI_BASE_ADDRESS_0) + i);
+            if ( bar_data & PCI_ADDRESS_SPACE_IO )
+                pci_register_io_region((PCIDevice *)assigned_device, i,
+                    (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_IO,
+                    pt_ioport_map);
+            else if ( bar_data & PCI_ADDRESS_SPACE_MEM_PREFETCH )
+                pci_register_io_region((PCIDevice *)assigned_device, i,
+                    (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM_PREFETCH,
+                    pt_iomem_map);
+            else
+                pci_register_io_region((PCIDevice *)assigned_device, i, 
+                    (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM,
+                    pt_iomem_map);
+
+            PT_LOG("IO region registered (size=0x%08x base_addr=0x%08x)\n",
+                (uint32_t)(pci_dev->size[i]),
+                (uint32_t)(pci_dev->base_addr[i]));
+        }
+    }
+
+    /* Register expansion ROM address */
+    if ( pci_dev->rom_base_addr && pci_dev->rom_size )
+    {
+        assigned_device->bases[PCI_ROM_SLOT].e_physbase =
+            pci_dev->rom_base_addr;
+        assigned_device->bases[PCI_ROM_SLOT].access.maddr =
+            pci_dev->rom_base_addr;
+        pci_register_io_region((PCIDevice *)assigned_device, PCI_ROM_SLOT,
+            pci_dev->rom_size, PCI_ADDRESS_SPACE_MEM_PREFETCH,
+            pt_iomem_map);
+
+        PT_LOG("Expansion ROM registered (size=0x%08x base_addr=0x%08x)\n",
+            (uint32_t)(pci_dev->rom_size), (uint32_t)(pci_dev->rom_base_addr));
+    }
+
+    return 0;
+}
+
+struct pt_dev * register_real_device(PCIBus *e_bus,
+        const char *e_dev_name, int e_devfn, uint8_t r_bus, uint8_t r_dev,
+        uint8_t r_func, uint32_t machine_irq, struct pci_access *pci_access)
+{
+    int rc, i;
+    struct pt_dev *assigned_device = NULL;
+    struct pci_dev *pci_dev;
+    struct pci_config_cf8 machine_bdf;
+    uint8_t e_device, e_intx;
+
+    PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
+        r_bus, r_dev, r_func);
+
+    /* Find real device structure */
+    for (pci_dev = pci_access->devices; pci_dev != NULL;
+         pci_dev = pci_dev->next)
+    {
+        if ((r_bus == pci_dev->bus) && (r_dev == pci_dev->dev)
+            && (r_func == pci_dev->func))
+            break;
+    }
+    if ( pci_dev == NULL )
+    {
+        PT_LOG("Error: couldn't locate device in libpci structures\n");
+        return NULL;
+    }
+
+    /* Register device */
+    assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name,
+                                sizeof(struct pt_dev), e_devfn,
+                                pt_pci_read_config, pt_pci_write_config);
+    if ( assigned_device == NULL )
+    {
+        PT_LOG("Error: couldn't register real device\n");
+        return NULL;
+    }
+
+    assigned_device->pci_dev = pci_dev;
+
+    /* Issue PCIe FLR */
+    pdev_flr(pci_dev);
+
+    /* Tell XEN vmm to change iommu settings */
+    machine_bdf.reg = 0;
+    machine_bdf.bus = r_bus;
+    machine_bdf.dev = r_dev;
+    machine_bdf.func = r_func;
+    rc = xc_assign_device(xc_handle, domid, machine_bdf.value);
+    if ( rc < 0 )
+        PT_LOG("Error: xc_domain_assign_device error %d\n", rc);
+
+    /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
+    for ( i = 0; i < PCI_CONFIG_SIZE; i++ )
+        assigned_device->dev.config[i] = pci_read_byte(pci_dev, i);
+
+    /* Handle real device's MMIO/PIO BARs */
+    pt_register_regions(assigned_device);
+    
+    /* Bind interrupt */
+    e_device = (assigned_device->dev.devfn >> 3) & 0x1f;
+    e_intx = assigned_device->dev.config[0x3d]-1;
+
+    if ( PT_MACHINE_IRQ_AUTO == machine_irq )
+        machine_irq = pci_dev->irq;
+
+    /* bind machine_irq to device */
+    if ( 0 != machine_irq )
+    {
+        rc = xc_domain_bind_pt_pci_irq(xc_handle, domid, machine_irq, 0,
+                                       e_device, e_intx);
+        if ( rc < 0 )
+        {
+            /* TBD: unregister device in case of an error */
+            PT_LOG("Error: Binding of interrupt failed! rc=%d\n", rc);
+        }
+    }
+    else {
+        /* Disable PCI intx assertion (turn on bit10 of devctl) */
+        assigned_device->dev.config[0x05] |= 0x04;
+        pci_write_word(pci_dev, 0x04,
+            *(uint16_t *)(&assigned_device->dev.config[0x04]));
+    }
+
+    PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n", 
+        r_bus, r_dev, r_func);
+
+    return assigned_device;
+}
+
+int pt_init(PCIBus *e_bus, char *direct_pci)
+{
+    int i;
+    int seg, b, d, f;
+    struct pt_dev *pt_dev;
+    struct pci_access *pci_access;
+    int dev_count = pci_devs(direct_pci);
+
+    /* Initialize libpci */
+    pci_access = pci_alloc();
+    if ( pci_access == NULL )
+    {
+        PT_LOG("pci_access is NULL\n");
+        return -1;
+    }
+    pci_init(pci_access);
+    pci_scan_bus(pci_access);
+
+    /* Assign given devices to guest */
+    for ( i = 0; i < dev_count; i++ )
+    {
+        /* Get next device bdf (bus, device, function) */
+        next_bdf(direct_pci, &seg, &b, &d, &f);
+
+        /* Register real device with the emulated bus */
+        pt_dev = register_real_device(e_bus, "DIRECT PCI", PT_VIRT_DEVFN_AUTO,
+            b, d, f, PT_MACHINE_IRQ_AUTO, pci_access);
+        if ( pt_dev == NULL )
+        {
+            PT_LOG("Error: Registration failed (%02x:%02x.%x)\n", b, d, f);
+            return -1;
+        }
+    }
+
+    /* Success */
+    return 0;
+}
diff -r b3f681d71265 -r acfa9290746f tools/ioemu/hw/pass-through.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/hw/pass-through.h     Fri Sep 14 16:39:27 2007 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PASSTHROUGH_H__
+#define __PASSTHROUGH_H__
+
+#include "vl.h"
+#include "pci/header.h"
+#include "pci/pci.h"
+
+/* Log acesss */
+#define PT_LOGGING_ENABLED
+
+#ifdef PT_LOGGING_ENABLED
+#define PT_LOG(_f, _a...)   fprintf(logfile, "%s: " _f, __func__, ##_a)
+#else
+#define PT_LOG(_f, _a...)
+#endif
+
+/* Some compilation flags */
+// #define PT_DEBUG_PCI_CONFIG_ACCESS
+
+#define PT_MACHINE_IRQ_AUTO (0xFFFFFFFF)
+#define PT_VIRT_DEVFN_AUTO  (-1)
+
+/* Misc PCI constants that should be moved to a separate library :) */
+#define PCI_CONFIG_SIZE         (256)
+#define PCI_EXP_DEVCAP_FLR      (1 << 28)
+#define PCI_EXP_DEVCTL_FLR      (0x1b)
+#define PCI_BAR_ENTRIES         (6)
+
+struct pt_region {
+    /* Virtual phys base & size */
+    uint32_t e_physbase;
+    uint32_t e_size;
+    /* Index of region in qemu */
+    uint32_t memory_index;
+    /* Translation of the emulated address */
+    union {
+        uint32_t maddr;
+        uint32_t pio_base;
+        uint32_t u;
+    } access;
+};
+
+/*
+    This structure holds the context of the mapping functions
+    and data that is relevant for qemu device management.
+*/
+struct pt_dev {
+    PCIDevice dev;
+    struct pci_dev *pci_dev;                     /* libpci struct */
+    struct pt_region bases[PCI_NUM_REGIONS];    /* Access regions */
+};
+
+/* Used for formatting PCI BDF into cf8 format */
+struct pci_config_cf8 {
+    union {
+        unsigned int value;
+        struct {
+            unsigned int reserved1:2;
+            unsigned int reg:6;
+            unsigned int func:3;
+            unsigned int dev:5;
+            unsigned int bus:8;
+            unsigned int reserved2:7;
+            unsigned int enable:1;
+        };
+    };
+};
+
+int pt_init(PCIBus * e_bus, char * direct_pci);
+
+#endif /* __PASSTHROUGH_H__ */
+
diff -r b3f681d71265 -r acfa9290746f tools/ioemu/hw/pc.c
--- a/tools/ioemu/hw/pc.c       Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/ioemu/hw/pc.c       Fri Sep 14 16:39:27 2007 +0100
@@ -465,7 +465,7 @@ static void pc_init1(uint64_t ram_size, 
                      DisplayState *ds, const char **fd_filename, int snapshot,
                      const char *kernel_filename, const char *kernel_cmdline,
                      const char *initrd_filename,
-                     int pci_enabled)
+                     int pci_enabled, const char *direct_pci)
 {
 #ifndef NOBIOS
     char buf[1024];
@@ -480,6 +480,7 @@ static void pc_init1(uint64_t ram_size, 
     int piix3_devfn = -1;
     CPUState *env;
     NICInfo *nd;
+    int rc;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -665,6 +666,19 @@ static void pc_init1(uint64_t ram_size, 
         }
     }
 
+#ifdef CONFIG_PASSTHROUGH
+    /* Pass-through Initialization */
+    if ( pci_enabled && direct_pci )
+    {
+        rc = pt_init(pci_bus, direct_pci); 
+        if ( rc < 0 )
+        {
+            fprintf(logfile, "Error: Initialization failed for pass-through 
devices\n");
+            exit(1);
+        }
+    }
+#endif
+
     rtc_state = rtc_init(0x70, 8);
 
     register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
@@ -801,12 +815,14 @@ static void pc_init_pci(uint64_t ram_siz
                         int snapshot, 
                         const char *kernel_filename, 
                         const char *kernel_cmdline,
-                        const char *initrd_filename)
+                        const char *initrd_filename,
+                        const char *direct_pci)
 {
     pc_init1(ram_size, vga_ram_size, boot_device,
              ds, fd_filename, snapshot,
              kernel_filename, kernel_cmdline,
-             initrd_filename, 1);
+             initrd_filename, 1,
+             direct_pci);
 }
 
 static void pc_init_isa(uint64_t ram_size, int vga_ram_size, char *boot_device,
@@ -814,12 +830,13 @@ static void pc_init_isa(uint64_t ram_siz
                         int snapshot, 
                         const char *kernel_filename, 
                         const char *kernel_cmdline,
-                        const char *initrd_filename)
+                        const char *initrd_filename,
+                        const char *unused)
 {
     pc_init1(ram_size, vga_ram_size, boot_device,
              ds, fd_filename, snapshot,
              kernel_filename, kernel_cmdline,
-             initrd_filename, 0);
+             initrd_filename, 0, NULL);
 }
 
 QEMUMachine pc_machine = {
diff -r b3f681d71265 -r acfa9290746f tools/ioemu/vl.c
--- a/tools/ioemu/vl.c  Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/ioemu/vl.c  Fri Sep 14 16:39:27 2007 +0100
@@ -6513,6 +6513,7 @@ enum {
     QEMU_OPTION_acpi,
     QEMU_OPTION_vncviewer,
     QEMU_OPTION_vncunused,
+    QEMU_OPTION_pci,
 };
 
 typedef struct QEMUOption {
@@ -6610,6 +6611,7 @@ const QEMUOption qemu_options[] = {
     { "d", HAS_ARG, QEMU_OPTION_d },
     { "vcpus", 1, QEMU_OPTION_vcpus },
     { "acpi", 0, QEMU_OPTION_acpi },
+    { "pci", HAS_ARG, QEMU_OPTION_pci},
     { NULL },
 };
 
@@ -7065,9 +7067,9 @@ int main(int argc, char **argv)
     extern void *buffered_pio_page;
 #endif
     sigset_t set;
-
     char qemu_dm_logfilename[128];
-    
+    const char *direct_pci = NULL;
+
     /* Ensure that SIGUSR2 is blocked by default when a new thread is created,
        then only the threads that use the signal unblock it -- this fixes a
        race condition in Qcow support where the AIO signal is misdelivered.  */
@@ -7560,6 +7562,9 @@ int main(int argc, char **argv)
             case QEMU_OPTION_vncunused:
                 vncunused++;
                 break;
+            case QEMU_OPTION_pci:
+                direct_pci = optarg;
+                break;
             }
         }
     }
@@ -7926,7 +7931,8 @@ int main(int argc, char **argv)
 
     machine->init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
-                  kernel_filename, kernel_cmdline, initrd_filename);
+                  kernel_filename, kernel_cmdline, initrd_filename,
+                  direct_pci);
     free(boot_device);
 
     /* init USB devices */
diff -r b3f681d71265 -r acfa9290746f tools/ioemu/vl.h
--- a/tools/ioemu/vl.h  Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/ioemu/vl.h  Fri Sep 14 16:39:27 2007 +0100
@@ -717,7 +717,7 @@ typedef void QEMUMachineInitFunc(uint64_
                                  char *boot_device,
              DisplayState *ds, const char **fd_filename, int snapshot,
              const char *kernel_filename, const char *kernel_cmdline,
-             const char *initrd_filename);
+             const char *initrd_filename, const char *direct_pci);
 
 typedef struct QEMUMachine {
     const char *name;
diff -r b3f681d71265 -r acfa9290746f tools/libxc/xc_domain.c
--- a/tools/libxc/xc_domain.c   Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/libxc/xc_domain.c   Fri Sep 14 16:39:27 2007 +0100
@@ -734,6 +734,114 @@ int xc_domain_setdebugging(int xc_handle
     return do_domctl(xc_handle, &domctl);
 }
 
+int xc_assign_device(
+    int xc_handle,
+    uint32_t domid,
+    uint32_t machine_bdf)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_assign_device;
+    domctl.domain = domid;
+    domctl.u.assign_device.machine_bdf = machine_bdf;
+ 
+    return do_domctl(xc_handle, &domctl);
+}
+
+/* Pass-through: binds machine irq to guests irq */
+int xc_domain_bind_pt_irq(
+    int xc_handle,
+    uint32_t domid,
+    uint8_t machine_irq,
+    uint8_t irq_type,
+    uint8_t bus,
+    uint8_t device,
+    uint8_t intx,
+                                                 uint8_t isa_irq)
+{
+    int rc;
+    xen_domctl_bind_pt_irq_t * bind;
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_bind_pt_irq;
+    domctl.domain = (domid_t)domid;
+
+    bind = &(domctl.u.bind_pt_irq);
+    bind->hvm_domid = domid;
+    bind->irq_type = irq_type;
+    bind->machine_irq = machine_irq;
+    bind->u.pci.bus = bus;
+    bind->u.pci.device = device;    
+    bind->u.pci.intx = intx;
+    bind->u.isa.isa_irq = isa_irq;
+    
+    rc = do_domctl(xc_handle, &domctl);
+    return rc;
+}
+
+int xc_domain_bind_pt_pci_irq(
+    int xc_handle,
+    uint32_t domid,
+    uint8_t machine_irq,
+    uint8_t bus,
+    uint8_t device,
+    uint8_t intx)
+{
+
+    return (xc_domain_bind_pt_irq(xc_handle, domid, machine_irq,
+                                  PT_IRQ_TYPE_PCI, bus, device, intx, 0));
+}
+
+int xc_domain_bind_pt_isa_irq(
+    int xc_handle,
+    uint32_t domid,
+    uint8_t machine_irq)
+{
+
+    return (xc_domain_bind_pt_irq(xc_handle, domid, machine_irq,
+                                  PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq));
+}
+
+int xc_domain_memory_mapping(
+    int xc_handle,
+    uint32_t domid,
+    unsigned long first_gfn,
+    unsigned long first_mfn,
+    unsigned long nr_mfns,
+    uint32_t add_mapping)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_memory_mapping;
+    domctl.domain = domid;
+    domctl.u.memory_mapping.first_gfn = first_gfn;
+    domctl.u.memory_mapping.first_mfn = first_mfn;
+    domctl.u.memory_mapping.nr_mfns = nr_mfns;
+    domctl.u.memory_mapping.add_mapping = add_mapping;
+
+    return do_domctl(xc_handle, &domctl);
+}
+
+int xc_domain_ioport_mapping(
+    int xc_handle,
+    uint32_t domid,
+    uint32_t first_gport,
+    uint32_t first_mport,
+    uint32_t nr_ports,
+    uint32_t add_mapping)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_ioport_mapping;
+    domctl.domain = domid;
+    domctl.u.ioport_mapping.first_gport = first_gport;
+    domctl.u.ioport_mapping.first_mport = first_mport;
+    domctl.u.ioport_mapping.nr_ports = nr_ports;
+    domctl.u.ioport_mapping.add_mapping = add_mapping;
+
+    return do_domctl(xc_handle, &domctl);
+}
+
 /*
  * Local variables:
  * mode: C
diff -r b3f681d71265 -r acfa9290746f tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/libxc/xenctrl.h     Fri Sep 14 16:39:27 2007 +0100
@@ -897,4 +897,43 @@ int xc_ia64_save_to_nvram(int xc_handle,
 /* IA64 specific, nvram init */
 int xc_ia64_nvram_init(int xc_handle, char *dom_name, uint32_t dom);
 
+/* HVM guest pass-through */
+int xc_assign_device(int xc_handle,
+                     uint32_t domid,
+                     uint32_t machine_bdf);
+
+int xc_domain_memory_mapping(int xc_handle,
+                             uint32_t domid,
+                             unsigned long first_gfn,
+                             unsigned long first_mfn,
+                             unsigned long nr_mfns,
+                             uint32_t add_mapping);
+
+int xc_domain_ioport_mapping(int xc_handle,
+                             uint32_t domid,
+                             uint32_t first_gport,
+                             uint32_t first_mport,
+                             uint32_t nr_ports,
+                             uint32_t add_mapping);
+
+int xc_domain_bind_pt_irq(int xc_handle,
+                          uint32_t domid,
+                          uint8_t machine_irq,
+                          uint8_t irq_type,
+                          uint8_t bus,
+                          uint8_t device,
+                          uint8_t intx,
+                          uint8_t isa_irq);
+
+int xc_domain_bind_pt_pci_irq(int xc_handle,
+                              uint32_t domid,
+                              uint8_t machine_irq,
+                              uint8_t bus,
+                              uint8_t device,
+                              uint8_t intx);
+
+int xc_domain_bind_pt_isa_irq(int xc_handle,
+                              uint32_t domid,
+                              uint8_t machine_irq);
+
 #endif /* XENCTRL_H */
diff -r b3f681d71265 -r acfa9290746f tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/python/xen/xend/XendConfig.py       Fri Sep 14 16:39:27 2007 +0100
@@ -127,7 +127,7 @@ XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 
                         'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl',
                         'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
                         'vncconsole', 'vncdisplay', 'vnclisten',
-                        'vncpasswd', 'vncunused', 'xauthority']
+                        'vncpasswd', 'vncunused', 'xauthority', 'pci']
 
 # Xen API console 'other_config' keys.
 XENAPI_CONSOLE_OTHER_CFG = ['vncunused', 'vncdisplay', 'vnclisten',
@@ -168,6 +168,7 @@ XENAPI_CFG_TYPES = {
     'tools_version': dict,
     'other_config': dict,
     'security_label': str,
+    'pci': str,
 }
 
 # List of legacy configuration keys that have no equivalent in the
diff -r b3f681d71265 -r acfa9290746f tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py    Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/python/xen/xend/image.py    Fri Sep 14 16:39:27 2007 +0100
@@ -309,7 +309,7 @@ class HVMImageHandler(ImageHandler):
     def parseDeviceModelArgs(self, vmConfig):
         dmargs = [ 'boot', 'fda', 'fdb', 'soundhw',
                    'localtime', 'serial', 'stdvga', 'isa',
-                   'acpi', 'usb', 'usbdevice', 'keymap' ]
+                   'acpi', 'usb', 'usbdevice', 'keymap', 'pci' ]
         
         ret = ['-vcpus', str(self.vm.getVCpuCount())]
 
diff -r b3f681d71265 -r acfa9290746f tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Fri Sep 14 16:10:08 2007 +0100
+++ b/tools/python/xen/xm/create.py     Fri Sep 14 16:39:27 2007 +0100
@@ -721,7 +721,7 @@ def configure_hvm(config_image, vals):
              'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
              'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
              'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
-             'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ]
+             'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci' ]
     for a in args:
         if a in vals.__dict__ and vals.__dict__[a] is not None:
             config_image.append([a, vals.__dict__[a]])

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] PCI passthru: tools changes (generic and vt-d), Xen patchbot-unstable <=