RE: [PATCH 5/6] device assignment: support for assigning PCI devices to guests

Han, Weidong
2008-10-28T14:29:16Z

muli@il.ibm.com wrote:
> From: Muli Ben-Yehuda <muli@il.ibm.com>
>
> This patch has been contributed to by the following people:
>
> Or Sagi <ors@tutis.com>
> Nir Peleg <nir@tutis.com>
> Amit Shah <amit.shah@redhat.com>
> Ben-Ami Yassour <benami@il.ibm.com>
> Weidong Han <weidong.han@intel.com>
> Glauber de Oliveira Costa <gcosta@redhat.com>
> Muli Ben-Yehuda <muli@il.ibm.com>
>
> With this patch, we can assign a device on the host machine to a
> guest.
>
> A new command-line option, -pcidevice is added.
> To invoke it for a device sitting at PCI bus:dev.fn 04:08.0, use this:
>
> -pcidevice host=04:08.0
>
> * The host driver for the device, if any, is to be removed before
> assigning the device (else device assignment will fail).
>
> * A device that shares IRQ with another host device cannot currently
> be assigned.
>
> * The RAW_IO capability is needed for this to work
>
> This works only with the in-kernel irqchip method; to use the
> userspace irqchip, a kernel module (irqhook) and some extra changes
> are needed.
>
> [muli: lots of small fixes from Muli and Weidong Han addressing all v7
> review comments]
>
> Signed-off-by: Amit Shah <amit.shah@redhat.com>
> Signed-off-by: Muli Ben-Yehuda <muli@il.ibm.com>
> ---
> qemu/Makefile.target | 3 +
> qemu/hw/device-assignment.c | 641
> +++++++++++++++++++++++++++++++++++++++++++
> qemu/hw/device-assignment.h | 117 ++++++++ qemu/hw/pc.c
> | 16 + qemu/hw/pci.c | 7 +
> qemu/qemu-kvm.c | 14 +
> qemu/qemu-kvm.h | 8 +
> qemu/vl.c | 28 ++
> 8 files changed, 834 insertions(+), 0 deletions(-)
> create mode 100644 qemu/hw/device-assignment.c
> create mode 100644 qemu/hw/device-assignment.h
>
> diff --git a/qemu/Makefile.target b/qemu/Makefile.target
> index d9bdeca..5d44e08 100644
> --- a/qemu/Makefile.target
> +++ b/qemu/Makefile.target
> @@ -621,6 +621,9 @@ OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
> OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
> OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
> OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o extboot.o
> +ifeq ($(USE_KVM), 1)
> +OBJS+= device-assignment.o
> +endif
> ifeq ($(USE_KVM_PIT), 1)
> OBJS+= i8254-kvm.o
> endif
> diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
> new file mode 100644
> index 0000000..89b05f9
> --- /dev/null
> +++ b/qemu/hw/device-assignment.c
> @@ -0,0 +1,641 @@
> +/*
> + * Copyright (c) 2007, Neocleus 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. + *
> + *
> + * Assign a PCI device from the host to a guest VM.
> + *
> + * Adapted for KVM by Qumranet.
> + *
> + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
> + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
> + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
> + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
> + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
> + */
> +#include <stdio.h>
> +#include <sys/io.h>
> +#include "qemu-kvm.h"
> +#include "hw.h"
> +#include "pc.h"
> +#include "sysemu.h"
> +#include "console.h"
> +#include "device-assignment.h"
> +
> +/* From linux/ioport.h */
> +#define IORESOURCE_IO 0x00000100 /* Resource type */
> +#define IORESOURCE_MEM 0x00000200
> +#define IORESOURCE_IRQ 0x00000400
> +#define IORESOURCE_DMA 0x00000800
> +#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
> +
> +/* #define DEVICE_ASSIGNMENT_DEBUG 1 */
> +
> +#ifdef DEVICE_ASSIGNMENT_DEBUG
> +#define DEBUG(fmt, ...) \
> + do { \
> + fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__); \
> + } while (0)
> +#else
> +#define DEBUG(fmt, ...) do { } while(0)
> +#endif
> +
> +static uint32_t guest_to_host_ioport(AssignedDevRegion *region,
> uint32_t addr) +{
> + return region->u.r_baseport + (addr - region->e_physbase);
> +}
> +
> +static void assigned_dev_ioport_writeb(void *opaque, uint32_t addr,
> + uint32_t value)
> +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> +
> + DEBUG("r_pio=%08x e_physbase=%08x r_virtbase=%08lx value=%08x\n",
> + r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

should be (unsigned long)r_access->u.r_virtbase

> +
> + outb(value, r_pio);
> +}
> +
> +static void assigned_dev_ioport_writew(void *opaque, uint32_t addr,
> + uint32_t value)
> +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> +
> + DEBUG("r_pio=%08x e_physbase=%08x r_virtbase=%08lx value=%08x\n",
> + __func__, r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

(unsigned long)r_access->u.r_virtbase

> +
> + outw(value, r_pio);
> +}
> +
> +static void assigned_dev_ioport_writel(void *opaque, uint32_t addr,
> + uint32_t value)
> +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> +
> + DEBUG("%s: r_pio=%08x e_physbase=%08x r_virtbase=%08lx
> value=%08x\n", + r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

(unsigned long)r_access->u.r_virtbase

> +
> + outl(value, r_pio);
> +}
> +
> +static uint32_t assigned_dev_ioport_readb(void *opaque, uint32_t
> addr) +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> + uint32_t value;
> +
> + value = inb(r_pio);
> +
> + DEBUG("r_pio=%08x e_physbase=%08x r_virtbase=%08lx value=%08x\n",
> + r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

(unsigned long)r_access->u.r_virtbase

> +
> + return value;
> +}
> +
> +static uint32_t assigned_dev_ioport_readw(void *opaque, uint32_t
> addr) +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> + uint32_t value;
> +
> + value = inw(r_pio);
> +
> + DEBUG("r_pio=%08x e_physbase=%08x r_virtbase=%08lx value=%08x\n",
> + r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

(unsigned long)r_access->u.r_virtbase

> +
> + return value;
> +}
> +
> +static uint32_t assigned_dev_ioport_readl(void *opaque, uint32_t
> addr) +{
> + AssignedDevRegion *r_access = opaque;
> + uint32_t r_pio = guest_to_host_ioport(r_access, addr);
> + uint32_t value;
> +
> + value = inl(r_pio);
> +
> + DEBUG("r_pio=%08x e_physbase=%08x r_virtbase=%08lx value=%08x\n",
> + r_pio, (int)r_access->e_physbase,
> + (unsigned long)r_access->r_virtbase, value);

(unsigned long)r_access->u.r_virtbase

> +
> + return value;
> +}
> +
> +static void assigned_dev_iomem_map(PCIDevice *pci_dev, int
> region_num, + uint32_t e_phys,
> uint32_t e_size, int type) +{
> + AssignedDevice *r_dev = (AssignedDevice *) pci_dev;
> + AssignedDevRegion *region = &r_dev->v_addrs[region_num];
> + uint32_t old_ephys = region->e_physbase;
> + uint32_t old_esize = region->e_size;
> + int first_map = (region->e_size == 0);
> + int ret = 0;
> +
> + DEBUG("e_phys=%08x r_virt=%x type=%d len=%08x region_num=%d \n",
> + e_phys, (uint32_t)region->r_virtbase, type, e_size,

(uint32_t)r_access->u.r_virtbase

Regards,
Weidong