[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.