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

Han, Weidong
2008-10-28T15:31:49Z

Han, Weidong wrote:
> 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

should be r_access->u.r_portbase

>
>> +
>> + 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

r_access->u.r_portbase, and remove "__func__".

>
>> +
>> + 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

r_access->u.r_portbase, and remove "%s"

>
>> +
>> + 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

r_access->u.r_portbase

>
>> +
>> + 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

r_access->u.r_portbase

>
>> +
>> + 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

r_access->u.r_portbase

Regards,
Weidong

>
>> +
>> + 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