2 * DMA memory preregistration
5 * Alexey Kardashevskiy <aik@ozlabs.ru>
7 * This work is licensed under the terms of the GNU GPL, version 2. See
8 * the COPYING file in the top-level directory.
11 #include "qemu/osdep.h"
13 #include <sys/ioctl.h>
14 #include <linux/vfio.h>
16 #include "hw/vfio/vfio-common.h"
18 #include "qemu/error-report.h"
21 static bool vfio_prereg_listener_skipped_section(MemoryRegionSection
*section
)
23 if (memory_region_is_iommu(section
->mr
)) {
24 hw_error("Cannot possibly preregister IOMMU memory");
27 return !memory_region_is_ram(section
->mr
) ||
28 memory_region_is_skip_dump(section
->mr
);
31 static void *vfio_prereg_gpa_to_vaddr(MemoryRegionSection
*section
, hwaddr gpa
)
33 return memory_region_get_ram_ptr(section
->mr
) +
34 section
->offset_within_region
+
35 (gpa
- section
->offset_within_address_space
);
38 static void vfio_prereg_listener_region_add(MemoryListener
*listener
,
39 MemoryRegionSection
*section
)
41 VFIOContainer
*container
= container_of(listener
, VFIOContainer
,
43 const hwaddr gpa
= section
->offset_within_address_space
;
46 hwaddr page_mask
= qemu_real_host_page_mask
;
47 struct vfio_iommu_spapr_register_memory reg
= {
52 if (vfio_prereg_listener_skipped_section(section
)) {
53 trace_vfio_prereg_listener_region_add_skip(
54 section
->offset_within_address_space
,
55 section
->offset_within_address_space
+
56 int128_get64(int128_sub(section
->size
, int128_one())));
60 if (unlikely((section
->offset_within_address_space
& ~page_mask
) ||
61 (section
->offset_within_region
& ~page_mask
) ||
62 (int128_get64(section
->size
) & ~page_mask
))) {
63 error_report("%s received unaligned region", __func__
);
67 end
= section
->offset_within_address_space
+ int128_get64(section
->size
);
72 memory_region_ref(section
->mr
);
74 reg
.vaddr
= (uintptr_t) vfio_prereg_gpa_to_vaddr(section
, gpa
);
77 ret
= ioctl(container
->fd
, VFIO_IOMMU_SPAPR_REGISTER_MEMORY
, ®
);
78 trace_vfio_prereg_register(reg
.vaddr
, reg
.size
, ret
? -errno
: 0);
81 * On the initfn path, store the first error in the container so we
82 * can gracefully fail. Runtime, there's not much we can do other
83 * than throw a hardware error.
85 if (!container
->initialized
) {
86 if (!container
->error
) {
87 container
->error
= ret
;
90 hw_error("vfio: Memory registering failed, unable to continue");
95 static void vfio_prereg_listener_region_del(MemoryListener
*listener
,
96 MemoryRegionSection
*section
)
98 VFIOContainer
*container
= container_of(listener
, VFIOContainer
,
100 const hwaddr gpa
= section
->offset_within_address_space
;
103 hwaddr page_mask
= qemu_real_host_page_mask
;
104 struct vfio_iommu_spapr_register_memory reg
= {
105 .argsz
= sizeof(reg
),
109 if (vfio_prereg_listener_skipped_section(section
)) {
110 trace_vfio_prereg_listener_region_del_skip(
111 section
->offset_within_address_space
,
112 section
->offset_within_address_space
+
113 int128_get64(int128_sub(section
->size
, int128_one())));
117 if (unlikely((section
->offset_within_address_space
& ~page_mask
) ||
118 (section
->offset_within_region
& ~page_mask
) ||
119 (int128_get64(section
->size
) & ~page_mask
))) {
120 error_report("%s received unaligned region", __func__
);
124 end
= section
->offset_within_address_space
+ int128_get64(section
->size
);
129 reg
.vaddr
= (uintptr_t) vfio_prereg_gpa_to_vaddr(section
, gpa
);
130 reg
.size
= end
- gpa
;
132 ret
= ioctl(container
->fd
, VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY
, ®
);
133 trace_vfio_prereg_unregister(reg
.vaddr
, reg
.size
, ret
? -errno
: 0);
136 const MemoryListener vfio_prereg_listener
= {
137 .region_add
= vfio_prereg_listener_region_add
,
138 .region_del
= vfio_prereg_listener_region_del
,
141 int vfio_spapr_create_window(VFIOContainer
*container
,
142 MemoryRegionSection
*section
,
146 unsigned pagesize
= memory_region_iommu_get_min_page_size(section
->mr
);
147 unsigned entries
, pages
;
148 struct vfio_iommu_spapr_tce_create create
= { .argsz
= sizeof(create
) };
151 * FIXME: For VFIO iommu types which have KVM acceleration to
152 * avoid bouncing all map/unmaps through qemu this way, this
153 * would be the right place to wire that up (tell the KVM
154 * device emulation the VFIO iommu handles to use).
156 create
.window_size
= int128_get64(section
->size
);
157 create
.page_shift
= ctz64(pagesize
);
159 * SPAPR host supports multilevel TCE tables, there is some
160 * heuristic to decide how many levels we want for our table:
161 * 0..64 = 1; 65..4096 = 2; 4097..262144 = 3; 262145.. = 4
163 entries
= create
.window_size
>> create
.page_shift
;
164 pages
= MAX((entries
* sizeof(uint64_t)) / getpagesize(), 1);
165 pages
= MAX(pow2ceil(pages
) - 1, 1); /* Round up */
166 create
.levels
= ctz64(pages
) / 6 + 1;
168 ret
= ioctl(container
->fd
, VFIO_IOMMU_SPAPR_TCE_CREATE
, &create
);
170 error_report("Failed to create a window, ret = %d (%m)", ret
);
174 if (create
.start_addr
!= section
->offset_within_address_space
) {
175 vfio_spapr_remove_window(container
, create
.start_addr
);
177 error_report("Host doesn't support DMA window at %"HWADDR_PRIx
", must be %"PRIx64
,
178 section
->offset_within_address_space
,
179 (uint64_t)create
.start_addr
);
182 trace_vfio_spapr_create_window(create
.page_shift
,
190 int vfio_spapr_remove_window(VFIOContainer
*container
,
191 hwaddr offset_within_address_space
)
193 struct vfio_iommu_spapr_tce_remove remove
= {
194 .argsz
= sizeof(remove
),
195 .start_addr
= offset_within_address_space
,
199 ret
= ioctl(container
->fd
, VFIO_IOMMU_SPAPR_TCE_REMOVE
, &remove
);
201 error_report("Failed to remove window at %"PRIx64
,
202 (uint64_t)remove
.start_addr
);
206 trace_vfio_spapr_remove_window(offset_within_address_space
);