From: Ben-Ami Yassour <[EMAIL PROTECTED]> Enable a guest to access a device's memory mapped I/O regions directly. When the guest changes the I/O memory mappings for a passthrough device, send the updated mmio region to the kernel.
Signed-off-by: Ben-Ami Yassour <[EMAIL PROTECTED]> Signed-off-by: Muli Ben-Yehuda <[EMAIL PROTECTED]> --- libkvm/libkvm.c | 40 +++++++++++++++++++++++ libkvm/libkvm.h | 5 +++ qemu/hw/passthrough/passthrough.c | 64 +++++++++++++++++++----------------- qemu/hw/passthrough/passthrough.h | 3 ++ 4 files changed, 82 insertions(+), 30 deletions(-) diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c index 7329f86..7afe663 100644 --- a/libkvm/libkvm.c +++ b/libkvm/libkvm.c @@ -954,3 +954,43 @@ int kvm_irqchip_in_kernel(kvm_context_t kvm) { return kvm->irqchip_in_kernel; } + +int kvm_pt_memory_mapping_add(kvm_context_t kvm, uint32_t gpa, uint32_t hpa, + unsigned long len) +{ + struct kvm_pt_memory_mapping memory_mapping; + int rc; + + memory_mapping.gpa = (__u64)gpa; + memory_mapping.hpa = (__u64)hpa; + memory_mapping.size = len; + + rc = ioctl(kvm->vm_fd, KVM_PT_MEMORY_MAPPING_ADD, &memory_mapping); + if (rc == -1) { + fprintf(stderr, + "pass through add I/O memory mapping failed\n"); + return -1; + } + + return rc; +} + +int kvm_pt_memory_mapping_remove(kvm_context_t kvm, uint32_t gpa, + uint32_t hpa, unsigned long len) +{ + struct kvm_pt_memory_mapping memory_mapping; + int rc; + + memory_mapping.gpa = (__u64)gpa; + memory_mapping.hpa = (__u64)hpa; + memory_mapping.size = len; + + rc = ioctl(kvm->vm_fd, KVM_PT_MEMORY_MAPPING_REMOVE, &memory_mapping); + if (rc == -1) { + fprintf(stderr, + "pass through remove I/O memory mapping failed\n"); + return -1; + } + + return rc; +} diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h index 34d188b..6c8ceb9 100644 --- a/libkvm/libkvm.h +++ b/libkvm/libkvm.h @@ -556,4 +556,9 @@ int kvm_enable_vapic(kvm_context_t kvm, int vcpu, uint64_t vapic); #endif +int kvm_pt_memory_mapping_add(kvm_context_t kvm, uint32_t gpa, + uint32_t hva, unsigned long len); +int kvm_pt_memory_mapping_remove(kvm_context_t kvm, uint32_t gpa, + uint32_t hva, unsigned long len); + #endif diff --git a/qemu/hw/passthrough/passthrough.c b/qemu/hw/passthrough/passthrough.c index 1b2d294..e1fb70c 100644 --- a/qemu/hw/passthrough/passthrough.c +++ b/qemu/hw/passthrough/passthrough.c @@ -129,20 +129,42 @@ pt_ioport_read(b) pt_ioport_read(w) pt_ioport_read(l) -static void pt_iomem_map(PCIDevice * d, int region_num, - uint32_t e_phys, uint32_t e_size, int type) +void pt_iomem_map(PCIDevice * pci_dev, int region_num, uint32_t e_phys, + uint32_t e_size, int type) { - pt_dev_t *r_dev = (pt_dev_t *) d; - - r_dev->v_addrs[region_num].e_physbase = e_phys; + pt_dev_t *r_dev = (pt_dev_t *) pci_dev; + pt_region_t *region = &r_dev->v_addrs[region_num]; + uint32_t old_ebase = region->e_physbase; + int first_map = (region->e_size == 0); + int ret = 0; DEBUG("e_phys=%08x r_virt=%p type=%d len=%08x region_num=%d \n", e_phys, r_dev->v_addrs[region_num].r_virtbase, type, e_size, region_num); - cpu_register_physical_memory(e_phys, - r_dev->dev.io_regions[region_num].size, - r_dev->v_addrs[region_num].memory_index); + region->e_physbase = e_phys; + region->e_size = e_size; + + if (!first_map) { + ret = kvm_pt_memory_mapping_remove(kvm_context, + old_ebase, + e_phys, + e_size); + if (ret != 0) { + fprintf(logfile, + "Error: remove old mapping failed\n"); + return; + } + } + + if (e_size > 0) + ret = kvm_pt_memory_mapping_add(kvm_context, + region->e_physbase, + region->r_physbase, + e_size); + if (ret != 0) + fprintf(logfile, + "Error: create new mapping failed\n"); } @@ -255,33 +277,15 @@ int pt_register_regions(pci_region_t * io_regions, ? PCI_ADDRESS_SPACE_MEM_PREFETCH : PCI_ADDRESS_SPACE_MEM; - /* map physical memory */ + pci_dev->v_addrs[i].r_physbase = cur_region->base_addr; pci_dev->v_addrs[i].e_physbase = cur_region->base_addr; - pci_dev->v_addrs[i].r_virtbase = - mmap(NULL, (cur_region->size + 0xFFF) & 0xFFFFF000, - PROT_WRITE | PROT_READ, MAP_SHARED, - cur_region->resource_fd, (off_t) 0); - - if ((void *) -1 == - pci_dev->v_addrs[i].r_virtbase) { - fprintf(logfile, "NEO: Error: Couldn't mmap 0x%x!\n", - (uint32_t) (cur_region->base_addr)); - return (-1); - } - - /* add offset */ - pci_dev->v_addrs[i].r_virtbase += - (cur_region->base_addr & 0xFFF); + pci_dev->v_addrs[i].r_virtbase = 0; + pci_dev->v_addrs[i].r_size = cur_region->size; + pci_dev->v_addrs[i].e_size = 0; pci_register_io_region((PCIDevice *) pci_dev, i, cur_region->size, t, pt_iomem_map); - - pci_dev->v_addrs[i].memory_index = - cpu_register_io_memory(0, pt_mmio_read_cb, - pt_mmio_write_cb, - (void *) &(pci_dev->v_addrs[i])); - continue; } /* handle port io regions */ diff --git a/qemu/hw/passthrough/passthrough.h b/qemu/hw/passthrough/passthrough.h index b24752d..a366caf 100644 --- a/qemu/hw/passthrough/passthrough.h +++ b/qemu/hw/passthrough/passthrough.h @@ -19,9 +19,12 @@ typedef struct pt_region_s { target_phys_addr_t e_physbase; + uint32_t r_physbase; /* real physical base - hpa */ uint32_t memory_index; void *r_virtbase; /* mmapped access address */ int num; /* our index within v_addrs[] */ + uint32_t e_size; /* emulated size of region in bytes */ + uint32_t r_size; /* real size of region in bytes */ uint32_t debug; } pt_region_t; -- 1.5.0.3 ------------------------------------------------------------------------- Check out the new SourceForge.net Marketplace. It's the best place to buy or sell services for just about anything Open Source. http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel