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           |   24 ++++++++----
 qemu/hw/pci-passthrough.c |   88 +++++++++++---------------------------------
 qemu/hw/pci-passthrough.h |    2 +
 3 files changed, 40 insertions(+), 74 deletions(-)

diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
index a49cbdc..35bc411 100644
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -400,7 +400,7 @@ void *kvm_create_userspace_phys_mem(kvm_context_t kvm, 
unsigned long phys_start,
 {
        int r;
        int prot = PROT_READ;
-       void *ptr;
+       void *ptr = NULL;
        struct kvm_userspace_memory_region memory = {
                .memory_size = len,
                .guest_phys_addr = phys_start,
@@ -410,16 +410,24 @@ void *kvm_create_userspace_phys_mem(kvm_context_t kvm, 
unsigned long phys_start,
        if (writable)
                prot |= PROT_WRITE;
 
-       ptr = mmap(NULL, len, prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
-       if (ptr == MAP_FAILED) {
-               fprintf(stderr, "create_userspace_phys_mem: %s", 
strerror(errno));
-               return 0;
-       }
+       if (len > 0) {
+               ptr = mmap(NULL, len, prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+               if (ptr == MAP_FAILED) {
+                       fprintf(stderr, "create_userspace_phys_mem: %s",
+                               strerror(errno));
+                       return 0;
+               }
 
-       memset(ptr, 0, len);
+               memset(ptr, 0, len);
+       }
 
        memory.userspace_addr = (unsigned long)ptr;
-       memory.slot = get_free_slot(kvm);
+
+       if (len > 0)
+               memory.slot = get_free_slot(kvm);
+       else
+               memory.slot = get_slot(phys_start);
+
        r = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &memory);
        if (r == -1) {
                fprintf(stderr, "create_userspace_phys_mem: %s", 
strerror(errno));
diff --git a/qemu/hw/pci-passthrough.c b/qemu/hw/pci-passthrough.c
index 250d7ef..08e339d 100644
--- a/qemu/hw/pci-passthrough.c
+++ b/qemu/hw/pci-passthrough.c
@@ -51,59 +51,6 @@ extern FILE *logfile;
 #define DEBUG(fmt, args...)
 #endif
 
-#define pt_mmio_write(suffix, type)                                    \
-static void pt_mmio_write##suffix(void *opaque, target_phys_addr_t e_phys, \
-                               uint32_t value)                         \
-{                                                                      \
-       pt_region_t *r_access = (pt_region_t *)opaque;                  \
-       void *r_virt = (uint8_t *)r_access->r_virtbase +                \
-                       (e_phys - r_access->e_physbase);                \
-       if (r_access->debug & PT_DEBUG_MMIO) {                          \
-               fprintf(logfile, "pt_mmio_write" #suffix                \
-                       ": e_physbase=%p e_phys=%p r_virt=%p value=%08x\n", \
-                       (void *)r_access->e_physbase, (void *)e_phys,   \
-                       r_virt, value);                                 \
-       }                                                               \
-       *(type *)r_virt = (type)value;                                  \
-}
-
-pt_mmio_write(b, uint8_t)
-pt_mmio_write(w, uint16_t)
-pt_mmio_write(l, uint32_t)
-
-#define pt_mmio_read(suffix, type)                                     \
-static uint32_t pt_mmio_read##suffix(void *opaque, target_phys_addr_t e_phys) \
-{                                                                      \
-       pt_region_t *r_access = (pt_region_t *)opaque;                  \
-       void *r_virt = (uint8_t *)r_access->r_virtbase +                \
-                       (e_phys - r_access->e_physbase);                \
-       uint32_t value = (uint32_t) (*(type *) r_virt);                 \
-       if (r_access->debug & PT_DEBUG_MMIO) {                          \
-               fprintf(logfile,                                        \
-                       "pt_mmio_read" #suffix ": e_physbase=%p "       \
-                       "e_phys=%p r_virt=%p value=%08x\n",             \
-                       (void *)r_access->e_physbase,                   \
-                       (void *)e_phys, r_virt, value);                 \
-       }                                                               \
-       return value;                                                   \
-}
-
-pt_mmio_read(b, uint8_t)
-pt_mmio_read(w, uint16_t)
-pt_mmio_read(l, uint32_t)
-
-CPUReadMemoryFunc *pt_mmio_read_cb[3] = {
-       pt_mmio_readb,
-       pt_mmio_readw,
-       pt_mmio_readl
-};
-
-CPUWriteMemoryFunc *pt_mmio_write_cb[3] = {
-       pt_mmio_writeb,
-       pt_mmio_writew,
-       pt_mmio_writel
-};
-
 #define pt_ioport_write(suffix)                                                
\
 static void pt_ioport_write##suffix(void *opaque, uint32_t addr, uint32_t 
value) \
 {                                                                      \
@@ -145,20 +92,32 @@ 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];
+       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)
+               kvm_destroy_phys_mem(kvm_context, e_phys, e_size);
+
+       if (e_size > 0)
+               ret = kvm_register_userspace_phys_mem(kvm_context,
+                                                     e_phys,
+                                                     region->r_virtbase,
+                                                     e_size,
+                                                     0);
+       if (ret != 0)
+               fprintf(logfile, "Error: create new mapping failed\n");
 }
 
 static void pt_ioport_map(PCIDevice *pci_dev, int region_num,
@@ -295,6 +254,8 @@ static int pt_register_regions(pci_region_t *io_regions,
                                        (uint32_t) (cur_region->base_addr));
                                return -1;
                        }
+                       pci_dev->v_addrs[i].r_size = cur_region->size;
+                       pci_dev->v_addrs[i].e_size = 0;
 
                        /* add offset */
                        pci_dev->v_addrs[i].r_virtbase +=
@@ -304,11 +265,6 @@ static int pt_register_regions(pci_region_t *io_regions,
                                               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/pci-passthrough.h b/qemu/hw/pci-passthrough.h
index 60df017..7a98b0e 100644
--- a/qemu/hw/pci-passthrough.h
+++ b/qemu/hw/pci-passthrough.h
@@ -65,6 +65,8 @@ typedef struct pt_region_s {
        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.6

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

Reply via email to