79c4324644
Change-Id: I2d302dda68298877c65c99147f5bf22186a59aac
281 lines
11 KiB
Diff
281 lines
11 KiB
Diff
From dab969657d8ff8b175856f91b035b74849cf69ba Mon Sep 17 00:00:00 2001
|
|
From: Eric Auger <eric.auger@redhat.com>
|
|
Date: Thu, 30 Aug 2018 15:04:25 +0200
|
|
Subject: [PATCH] vfio: Introduce helpers to DMA map/unmap a RAM section
|
|
|
|
Let's introduce two helpers that allow to DMA map/unmap a RAM
|
|
section. Those helpers will be called for nested stage setup in
|
|
another call site. Also the vfio_listener_region_add/del()
|
|
structure may be clearer.
|
|
|
|
Signed-off-by: Eric Auger <eric.auger@redhat.com>
|
|
Signed-off-by: Kunkun Jiang <jiangkunkun@huawei.com>
|
|
---
|
|
hw/vfio/common.c | 206 +++++++++++++++++++++++++------------------
|
|
hw/vfio/trace-events | 4 +-
|
|
2 files changed, 123 insertions(+), 87 deletions(-)
|
|
|
|
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
|
|
index d358789f19..b3dc090840 100644
|
|
--- a/hw/vfio/common.c
|
|
+++ b/hw/vfio/common.c
|
|
@@ -922,13 +922,130 @@ hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end)
|
|
return NULL;
|
|
}
|
|
|
|
+static int vfio_dma_map_ram_section(VFIOContainer *container,
|
|
+ MemoryRegionSection *section, Error **err)
|
|
+{
|
|
+ VFIOHostDMAWindow *hostwin;
|
|
+ Int128 llend, llsize;
|
|
+ hwaddr iova, end;
|
|
+ void *vaddr;
|
|
+ int ret;
|
|
+
|
|
+ assert(memory_region_is_ram(section->mr));
|
|
+
|
|
+ iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
|
|
+ llend = int128_make64(section->offset_within_address_space);
|
|
+ llend = int128_add(llend, section->size);
|
|
+ llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
|
|
+ end = int128_get64(int128_sub(llend, int128_one()));
|
|
+
|
|
+ vaddr = memory_region_get_ram_ptr(section->mr) +
|
|
+ section->offset_within_region +
|
|
+ (iova - section->offset_within_address_space);
|
|
+
|
|
+ hostwin = hostwin_from_range(container, iova, end);
|
|
+ if (!hostwin) {
|
|
+ error_setg(err, "Container %p can't map guest IOVA region"
|
|
+ " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ trace_vfio_dma_map_ram(iova, end, vaddr);
|
|
+
|
|
+ llsize = int128_sub(llend, int128_make64(iova));
|
|
+
|
|
+ if (memory_region_is_ram_device(section->mr)) {
|
|
+ hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
|
|
+
|
|
+ if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) {
|
|
+ trace_vfio_listener_region_add_no_dma_map(
|
|
+ memory_region_name(section->mr),
|
|
+ section->offset_within_address_space,
|
|
+ int128_getlo(section->size),
|
|
+ pgmask + 1);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = vfio_dma_map(container, iova, int128_get64(llsize),
|
|
+ vaddr, section->readonly);
|
|
+ if (ret) {
|
|
+ error_setg(err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
|
|
+ "0x%"HWADDR_PRIx", %p) = %d (%m)",
|
|
+ container, iova, int128_get64(llsize), vaddr, ret);
|
|
+ if (memory_region_is_ram_device(section->mr)) {
|
|
+ /* Allow unexpected mappings not to be fatal for RAM devices */
|
|
+ error_report_err(*err);
|
|
+ return 0;
|
|
+ }
|
|
+ return ret;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void vfio_dma_unmap_ram_section(VFIOContainer *container,
|
|
+ MemoryRegionSection *section)
|
|
+{
|
|
+ Int128 llend, llsize;
|
|
+ hwaddr iova, end;
|
|
+ bool try_unmap = true;
|
|
+ int ret;
|
|
+
|
|
+ iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
|
|
+ llend = int128_make64(section->offset_within_address_space);
|
|
+ llend = int128_add(llend, section->size);
|
|
+ llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask));
|
|
+
|
|
+ if (int128_ge(int128_make64(iova), llend)) {
|
|
+ return;
|
|
+ }
|
|
+ end = int128_get64(int128_sub(llend, int128_one()));
|
|
+
|
|
+ llsize = int128_sub(llend, int128_make64(iova));
|
|
+
|
|
+ trace_vfio_dma_unmap_ram(iova, end);
|
|
+
|
|
+ if (memory_region_is_ram_device(section->mr)) {
|
|
+ hwaddr pgmask;
|
|
+ VFIOHostDMAWindow *hostwin = hostwin_from_range(container, iova, end);
|
|
+
|
|
+ assert(hostwin); /* or region_add() would have failed */
|
|
+
|
|
+ pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
|
|
+ try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask));
|
|
+ } else if (memory_region_has_ram_discard_manager(section->mr)) {
|
|
+ vfio_unregister_ram_discard_listener(container, section);
|
|
+ /* Unregistering will trigger an unmap. */
|
|
+ try_unmap = false;
|
|
+ }
|
|
+
|
|
+ if (try_unmap) {
|
|
+ if (int128_eq(llsize, int128_2_64())) {
|
|
+ /* The unmap ioctl doesn't accept a full 64-bit span. */
|
|
+ llsize = int128_rshift(llsize, 1);
|
|
+ ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL);
|
|
+ if (ret) {
|
|
+ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
|
|
+ "0x%"HWADDR_PRIx") = %d (%m)",
|
|
+ container, iova, int128_get64(llsize), ret);
|
|
+ }
|
|
+ iova += int128_get64(llsize);
|
|
+ }
|
|
+ ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL);
|
|
+ if (ret) {
|
|
+ error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
|
|
+ "0x%"HWADDR_PRIx") = %d (%m)",
|
|
+ container, iova, int128_get64(llsize), ret);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
static void vfio_listener_region_add(MemoryListener *listener,
|
|
MemoryRegionSection *section)
|
|
{
|
|
VFIOContainer *container = container_of(listener, VFIOContainer, listener);
|
|
hwaddr iova, end;
|
|
- Int128 llend, llsize;
|
|
- void *vaddr;
|
|
+ Int128 llend;
|
|
int ret;
|
|
VFIOHostDMAWindow *hostwin;
|
|
Error *err = NULL;
|
|
@@ -1092,38 +1209,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|
return;
|
|
}
|
|
|
|
- vaddr = memory_region_get_ram_ptr(section->mr) +
|
|
- section->offset_within_region +
|
|
- (iova - section->offset_within_address_space);
|
|
-
|
|
- trace_vfio_listener_region_add_ram(iova, end, vaddr);
|
|
-
|
|
- llsize = int128_sub(llend, int128_make64(iova));
|
|
-
|
|
- if (memory_region_is_ram_device(section->mr)) {
|
|
- hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
|
|
-
|
|
- if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) {
|
|
- trace_vfio_listener_region_add_no_dma_map(
|
|
- memory_region_name(section->mr),
|
|
- section->offset_within_address_space,
|
|
- int128_getlo(section->size),
|
|
- pgmask + 1);
|
|
- return;
|
|
- }
|
|
- }
|
|
-
|
|
- ret = vfio_dma_map(container, iova, int128_get64(llsize),
|
|
- vaddr, section->readonly);
|
|
- if (ret) {
|
|
- error_setg(&err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
|
|
- "0x%"HWADDR_PRIx", %p) = %d (%m)",
|
|
- container, iova, int128_get64(llsize), vaddr, ret);
|
|
- if (memory_region_is_ram_device(section->mr)) {
|
|
- /* Allow unexpected mappings not to be fatal for RAM devices */
|
|
- error_report_err(err);
|
|
- return;
|
|
- }
|
|
+ if (vfio_dma_map_ram_section(container, section, &err)) {
|
|
goto fail;
|
|
}
|
|
|
|
@@ -1157,10 +1243,6 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
|
MemoryRegionSection *section)
|
|
{
|
|
VFIOContainer *container = container_of(listener, VFIOContainer, listener);
|
|
- hwaddr iova, end;
|
|
- Int128 llend, llsize;
|
|
- int ret;
|
|
- bool try_unmap = true;
|
|
|
|
if (vfio_listener_skipped_section(section)) {
|
|
trace_vfio_listener_region_del_skip(
|
|
@@ -1200,53 +1282,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
|
*/
|
|
}
|
|
|
|
- iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
|
|
- llend = int128_make64(section->offset_within_address_space);
|
|
- llend = int128_add(llend, section->size);
|
|
- llend = int128_and(llend, int128_exts64(qemu_real_host_page_mask));
|
|
-
|
|
- if (int128_ge(int128_make64(iova), llend)) {
|
|
- return;
|
|
- }
|
|
- end = int128_get64(int128_sub(llend, int128_one()));
|
|
-
|
|
- llsize = int128_sub(llend, int128_make64(iova));
|
|
-
|
|
- trace_vfio_listener_region_del(iova, end);
|
|
-
|
|
- if (memory_region_is_ram_device(section->mr)) {
|
|
- hwaddr pgmask;
|
|
- VFIOHostDMAWindow *hostwin = hostwin_from_range(container, iova, end);
|
|
-
|
|
- assert(hostwin); /* or region_add() would have failed */
|
|
-
|
|
- pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1;
|
|
- try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask));
|
|
- } else if (memory_region_has_ram_discard_manager(section->mr)) {
|
|
- vfio_unregister_ram_discard_listener(container, section);
|
|
- /* Unregistering will trigger an unmap. */
|
|
- try_unmap = false;
|
|
- }
|
|
-
|
|
- if (try_unmap) {
|
|
- if (int128_eq(llsize, int128_2_64())) {
|
|
- /* The unmap ioctl doesn't accept a full 64-bit span. */
|
|
- llsize = int128_rshift(llsize, 1);
|
|
- ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL);
|
|
- if (ret) {
|
|
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
|
|
- "0x%"HWADDR_PRIx") = %d (%m)",
|
|
- container, iova, int128_get64(llsize), ret);
|
|
- }
|
|
- iova += int128_get64(llsize);
|
|
- }
|
|
- ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL);
|
|
- if (ret) {
|
|
- error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
|
|
- "0x%"HWADDR_PRIx") = %d (%m)",
|
|
- container, iova, int128_get64(llsize), ret);
|
|
- }
|
|
- }
|
|
+ vfio_dma_unmap_ram_section(container, section);
|
|
|
|
memory_region_unref(section->mr);
|
|
|
|
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
|
|
index 0ef1b5f4a6..a37563a315 100644
|
|
--- a/hw/vfio/trace-events
|
|
+++ b/hw/vfio/trace-events
|
|
@@ -99,10 +99,10 @@ vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "i
|
|
vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add 0x%"PRIx64" - 0x%"PRIx64
|
|
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
|
|
vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64
|
|
-vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]"
|
|
+vfio_dma_map_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]"
|
|
vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA"
|
|
vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64
|
|
-vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
|
|
+vfio_dma_unmap_ram(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
|
|
vfio_disconnect_container(int fd) "close container->fd=%d"
|
|
vfio_put_group(int fd) "close group->fd=%d"
|
|
vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u"
|
|
--
|
|
2.27.0
|
|
|