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

Reply via email to