From cc885c623f06ef22a04ab352d38e4ff32e7e6f57 Mon Sep 17 00:00:00 2001 From: Chen Qun 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 Signed-off-by: Kunkun Jiang Signed-off-by: imxcc (cherry picked from commit 68e372b0530d234ce4a3facb486d401595cf59ba) --- ...elpers-to-DMA-map-unmap-a-RAM-sectio.patch | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch diff --git a/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch b/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch new file mode 100644 index 0000000..fd6deff --- /dev/null +++ b/vfio-Introduce-helpers-to-DMA-map-unmap-a-RAM-sectio.patch @@ -0,0 +1,280 @@ +From dab969657d8ff8b175856f91b035b74849cf69ba Mon Sep 17 00:00:00 2001 +From: Eric Auger +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 +Signed-off-by: Kunkun Jiang +--- + 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 +