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>
This commit is contained in:
parent
6c756b3010
commit
89a04f5725
261
vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch
Normal file
261
vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch
Normal file
@ -0,0 +1,261 @@
|
||||
From eb3bfdb61025efe2891ce6732b8829a48dd75e2d 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 | 187 +++++++++++++++++++++++++++----------------
|
||||
hw/vfio/trace-events | 4 +-
|
||||
2 files changed, 119 insertions(+), 72 deletions(-)
|
||||
|
||||
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
|
||||
index a8db784ac5..8837d33c57 100644
|
||||
--- a/hw/vfio/common.c
|
||||
+++ b/hw/vfio/common.c
|
||||
@@ -709,13 +709,126 @@ hostwin_from_range(VFIOContainer *container, hwaddr iova, hwaddr end)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static int vfio_dma_map_ram_section(VFIOContainer *container,
|
||||
+ MemoryRegionSection *section)
|
||||
+{
|
||||
+ 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_report("vfio: IOMMU 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_report("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 */
|
||||
+ 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));
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
|
||||
@@ -842,38 +955,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
||||
}
|
||||
|
||||
/* Here we assume that memory_region_is_ram(section->mr)==true */
|
||||
-
|
||||
- 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_report("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 */
|
||||
- return;
|
||||
- }
|
||||
+ if (vfio_dma_map_ram_section(container, section)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -902,10 +984,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(
|
||||
@@ -945,38 +1023,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));
|
||||
- }
|
||||
-
|
||||
- if (try_unmap) {
|
||||
- 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 561dc6e758..9b6c7ca61b 100644
|
||||
--- a/hw/vfio/trace-events
|
||||
+++ b/hw/vfio/trace-events
|
||||
@@ -97,10 +97,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_connect_existing_container(int groupid, int container_fd) "group=%d existing container fd=%d"
|
||||
vfio_connect_new_container(int groupid, int container_fd) "group=%d new container fd=%d"
|
||||
--
|
||||
2.27.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user