[This still doesn't include some fixes to review comments. I'm posting this just so that people can use this to test or base their work off the latest patch.]
From: Or Sagi <[EMAIL PROTECTED]> From: Nir Peleg <[EMAIL PROTECTED]> From: Amit Shah <[EMAIL PROTECTED]> From: Ben-Ami Yassour <[EMAIL PROTECTED]> From: Glauber de Oliveira Costa <[EMAIL PROTECTED]> With this patch, we can assign a device on the host machine to a guest. A new command-line option, -pcidevice is added. For example, to invoke it for a device sitting at PCI bus:dev.fn 04:08.0 with host IRQ 18, use this: -pcidevice host=04:08.0 The host driver for the device, if any, is to be removed before assigning the device. This works only with the in-kernel irqchip method; to use the userspace irqchip, a kernel module (irqhook) and some extra changes are needed. Signed-off-by: Amit Shah <[EMAIL PROTECTED]> --- libkvm/libkvm-x86.c | 14 ++++++++++++++ libkvm/libkvm.h | 27 +++++++++++++++++++++++++++ qemu/Makefile.target | 1 + qemu/hw/isa.h | 2 ++ qemu/hw/pc.c | 9 +++++++++ qemu/hw/pci.c | 12 ++++++++++++ qemu/hw/pci.h | 1 + qemu/hw/piix_pci.c | 19 +++++++++++++++++++ qemu/qemu-kvm-x86.c | 3 +++ qemu/vl.c | 18 ++++++++++++++++++ 10 files changed, 106 insertions(+), 0 deletions(-) diff --git a/libkvm/libkvm-x86.c b/libkvm/libkvm-x86.c index a8cca15..6157f75 100644 --- a/libkvm/libkvm-x86.c +++ b/libkvm/libkvm-x86.c @@ -53,6 +53,20 @@ static int kvm_init_tss(kvm_context_t kvm) return 0; } +#ifdef KVM_CAP_DEVICE_ASSIGNMENT +int kvm_assign_pci_device(kvm_context_t kvm, + struct kvm_assigned_pci_dev *assigned_dev) +{ + return ioctl(kvm->vm_fd, KVM_ASSIGN_PCI_DEVICE, assigned_dev); +} + +int kvm_assign_irq(kvm_context_t kvm, + struct kvm_assigned_irq *assigned_irq) +{ + return ioctl(kvm->vm_fd, KVM_ASSIGN_IRQ, assigned_irq); +} +#endif + int kvm_create_pit(kvm_context_t kvm) { #ifdef KVM_CAP_PIT diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h index 79dd769..edf8e9e 100644 --- a/libkvm/libkvm.h +++ b/libkvm/libkvm.h @@ -658,4 +658,31 @@ int kvm_s390_interrupt(kvm_context_t kvm, int slot, int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw); int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr); #endif + +#ifdef KVM_CAP_DEVICE_ASSIGNMENT +/*! + * \brief Notifies host kernel aboud a PCI device assigned to guest + * + * Used for PCI device assignment, this function notifies the host + * kernel about the assigning of the physical PCI device. + * + * \param kvm Pointer to the current kvm_context + * \param assigned_dev Parameters, like bus, devfn number, etc + */ +int kvm_assign_pci_device(kvm_context_t kvm, + struct kvm_assigned_pci_dev *assigned_dev); + +/*! + * \brief Notifies host kernel about changes to a irq assignment + * + * Used for PCI device assignment, this function notifies the host + * kernel about the assigning of the irq for an assigned physical + * PCI device. + * + * \param kvm Pointer to the current kvm_context + * \param assigned_irq Parameters, like dev id, host irq, guest irq, etc + */ +int kvm_assign_irq(kvm_context_t kvm, + struct kvm_assigned_irq *assigned_irq); +#endif #endif diff --git a/qemu/Makefile.target b/qemu/Makefile.target index 89814fd..958c33b 100644 --- a/qemu/Makefile.target +++ b/qemu/Makefile.target @@ -611,6 +611,7 @@ 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 +OBJS+= device-assignment.o ifeq ($(USE_KVM_PIT), 1) OBJS+= i8254-kvm.o endif diff --git a/qemu/hw/isa.h b/qemu/hw/isa.h index 89b3004..c720f5e 100644 --- a/qemu/hw/isa.h +++ b/qemu/hw/isa.h @@ -1,5 +1,7 @@ /* ISA bus */ +#include "hw.h" + extern target_phys_addr_t isa_mem_base; int register_ioport_read(int start, int length, int size, diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c index 8a50096..59c2098 100644 --- a/qemu/hw/pc.c +++ b/qemu/hw/pc.c @@ -32,6 +32,7 @@ #include "smbus.h" #include "boards.h" #include "console.h" +#include "device-assignment.h" #include "qemu-kvm.h" @@ -1013,6 +1014,14 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, } } + /* Initialize assigned devices */ + if (pci_enabled) { + int r = -1; + do { + init_assigned_device(pci_bus, &r); + } while (r >= 0); + } + rtc_state = rtc_init(0x70, i8259[8]); qemu_register_boot_set(pc_boot_set, rtc_state); diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c index 07d37a8..e4e8386 100644 --- a/qemu/hw/pci.c +++ b/qemu/hw/pci.c @@ -50,6 +50,7 @@ struct PCIBus { static void pci_update_mappings(PCIDevice *d); static void pci_set_irq(void *opaque, int irq_num, int level); +void assigned_dev_update_irq(PCIDevice *d); target_phys_addr_t pci_mem_base; static int pci_irq_index; @@ -453,6 +454,12 @@ void pci_default_write_config(PCIDevice *d, val >>= 8; } +#ifdef KVM_CAP_DEVICE_ASSIGNMENT + if (kvm_enabled() && qemu_kvm_irqchip_in_kernel() && + address >= 0x60 && address <= 0x63) + assigned_dev_update_irq(d); +#endif + end = address + len; if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) { /* if the command register is modified, we must modify the mappings */ @@ -560,6 +567,11 @@ static void pci_set_irq(void *opaque, int irq_num, int level) bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } +int pci_map_irq(PCIDevice *pci_dev, int pin) +{ + return pci_dev->bus->map_irq(pci_dev, pin); +} + /***********************************************************/ /* monitor info on PCI */ diff --git a/qemu/hw/pci.h b/qemu/hw/pci.h index 60e4094..e11fbbf 100644 --- a/qemu/hw/pci.h +++ b/qemu/hw/pci.h @@ -81,6 +81,7 @@ void pci_register_io_region(PCIDevice *pci_dev, int region_num, uint32_t size, int type, PCIMapIORegionFunc *map_func); +int pci_map_irq(PCIDevice *pci_dev, int pin); uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len); void pci_default_write_config(PCIDevice *d, diff --git a/qemu/hw/piix_pci.c b/qemu/hw/piix_pci.c index 6fbf47b..dc12c8a 100644 --- a/qemu/hw/piix_pci.c +++ b/qemu/hw/piix_pci.c @@ -243,6 +243,25 @@ static void piix3_set_irq(qemu_irq *pic, int irq_num, int level) } } +int piix3_get_pin(int pic_irq) +{ + int i; + for (i = 0; i < 4; i++) + if (piix3_dev->config[0x60+i] == pic_irq) + return i; + return -1; +} + +int piix_get_irq(int pin) +{ + if (piix3_dev) + return piix3_dev->config[0x60+pin]; + if (piix4_dev) + return piix4_dev->config[0x60+pin]; + + return 0; +} + static void piix3_reset(PCIDevice *d) { uint8_t *pci_conf = d->config; diff --git a/qemu/qemu-kvm-x86.c b/qemu/qemu-kvm-x86.c index 5daedd1..5123e52 100644 --- a/qemu/qemu-kvm-x86.c +++ b/qemu/qemu-kvm-x86.c @@ -530,6 +530,9 @@ struct kvm_para_features { #ifdef KVM_CAP_CR3_CACHE { KVM_CAP_CR3_CACHE, KVM_FEATURE_CR3_CACHE }, #endif +#ifdef KVM_CAP_PV_DMA + { KVM_CAP_PV_DMA, KVM_FEATURE_DMA_OP }, +#endif { -1, -1 } }; diff --git a/qemu/vl.c b/qemu/vl.c index 022b3b8..bab720d 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -37,6 +37,7 @@ #include "qemu-char.h" #include "block.h" #include "audio/audio.h" +#include "hw/device-assignment.h" #include "migration.h" #include "balloon.h" #include "qemu-kvm.h" @@ -8478,6 +8479,12 @@ static void help(int exitcode) #endif "-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC\n" "-no-kvm-pit disable KVM kernel mode PIT\n" +#if defined(TARGET_I386) || defined(TARGET_X86_64) + "-pcidevice host=bus:dev.func[,dma=none][,name=\"string\"]\n" + " expose a PCI device to the guest OS.\n" + " dma=none: don't perform any dma translations (default is to use an iommu)\n" + " 'string' is used in log output.\n" +#endif #endif #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" @@ -8601,6 +8608,9 @@ enum { QEMU_OPTION_no_kvm, QEMU_OPTION_no_kvm_irqchip, QEMU_OPTION_no_kvm_pit, +#if defined(TARGET_I386) || defined(TARGET_X86_64) + QEMU_OPTION_pcidevice, +#endif QEMU_OPTION_no_reboot, QEMU_OPTION_no_shutdown, QEMU_OPTION_show_cursor, @@ -8689,6 +8699,9 @@ const QEMUOption qemu_options[] = { #endif { "no-kvm-irqchip", 0, QEMU_OPTION_no_kvm_irqchip }, { "no-kvm-pit", 0, QEMU_OPTION_no_kvm_pit }, +#if defined(TARGET_I386) || defined(TARGET_X86_64) + { "pcidevice", HAS_ARG, QEMU_OPTION_pcidevice }, +#endif #endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, @@ -9595,6 +9608,11 @@ int main(int argc, char **argv) kvm_pit = 0; break; } +#if defined(TARGET_I386) || defined(TARGET_X86_64) + case QEMU_OPTION_pcidevice: + add_assigned_device(optarg); + break; +#endif #endif case QEMU_OPTION_usb: usb_enabled = 1; -- 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html