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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel