1 /*
2 * VFIO BASE CONTAINER
3 *
4 * Copyright (C) 2023 Intel Corporation.
5 * Copyright Red Hat, Inc. 2023
6 *
7 * Authors: Yi Liu <yi.l.liu@intel.com>
8 * Eric Auger <eric.auger@redhat.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 #include <sys/ioctl.h>
14 #include <linux/vfio.h>
15
16 #include "qemu/osdep.h"
17 #include "system/tcg.h"
18 #include "system/ram_addr.h"
19 #include "qapi/error.h"
20 #include "qemu/error-report.h"
21 #include "hw/vfio/vfio-container-base.h"
22 #include "hw/vfio/vfio-device.h" /* vfio_device_reset_handler */
23 #include "system/reset.h"
24 #include "vfio-helpers.h"
25
26 #include "trace.h"
27
28 static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
29 QLIST_HEAD_INITIALIZER(vfio_address_spaces);
30
vfio_address_space_get(AddressSpace * as)31 VFIOAddressSpace *vfio_address_space_get(AddressSpace *as)
32 {
33 VFIOAddressSpace *space;
34
35 QLIST_FOREACH(space, &vfio_address_spaces, list) {
36 if (space->as == as) {
37 return space;
38 }
39 }
40
41 /* No suitable VFIOAddressSpace, create a new one */
42 space = g_malloc0(sizeof(*space));
43 space->as = as;
44 QLIST_INIT(&space->containers);
45
46 if (QLIST_EMPTY(&vfio_address_spaces)) {
47 qemu_register_reset(vfio_device_reset_handler, NULL);
48 }
49
50 QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
51
52 return space;
53 }
54
vfio_address_space_put(VFIOAddressSpace * space)55 void vfio_address_space_put(VFIOAddressSpace *space)
56 {
57 if (!QLIST_EMPTY(&space->containers)) {
58 return;
59 }
60
61 QLIST_REMOVE(space, list);
62 g_free(space);
63
64 if (QLIST_EMPTY(&vfio_address_spaces)) {
65 qemu_unregister_reset(vfio_device_reset_handler, NULL);
66 }
67 }
68
vfio_address_space_insert(VFIOAddressSpace * space,VFIOContainerBase * bcontainer)69 void vfio_address_space_insert(VFIOAddressSpace *space,
70 VFIOContainerBase *bcontainer)
71 {
72 QLIST_INSERT_HEAD(&space->containers, bcontainer, next);
73 bcontainer->space = space;
74 }
75
vfio_container_dma_map(VFIOContainerBase * bcontainer,hwaddr iova,ram_addr_t size,void * vaddr,bool readonly)76 int vfio_container_dma_map(VFIOContainerBase *bcontainer,
77 hwaddr iova, ram_addr_t size,
78 void *vaddr, bool readonly)
79 {
80 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
81
82 g_assert(vioc->dma_map);
83 return vioc->dma_map(bcontainer, iova, size, vaddr, readonly);
84 }
85
vfio_container_dma_unmap(VFIOContainerBase * bcontainer,hwaddr iova,ram_addr_t size,IOMMUTLBEntry * iotlb,bool unmap_all)86 int vfio_container_dma_unmap(VFIOContainerBase *bcontainer,
87 hwaddr iova, ram_addr_t size,
88 IOMMUTLBEntry *iotlb, bool unmap_all)
89 {
90 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
91
92 g_assert(vioc->dma_unmap);
93 return vioc->dma_unmap(bcontainer, iova, size, iotlb, unmap_all);
94 }
95
vfio_container_add_section_window(VFIOContainerBase * bcontainer,MemoryRegionSection * section,Error ** errp)96 bool vfio_container_add_section_window(VFIOContainerBase *bcontainer,
97 MemoryRegionSection *section,
98 Error **errp)
99 {
100 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
101
102 if (!vioc->add_window) {
103 return true;
104 }
105
106 return vioc->add_window(bcontainer, section, errp);
107 }
108
vfio_container_del_section_window(VFIOContainerBase * bcontainer,MemoryRegionSection * section)109 void vfio_container_del_section_window(VFIOContainerBase *bcontainer,
110 MemoryRegionSection *section)
111 {
112 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
113
114 if (!vioc->del_window) {
115 return;
116 }
117
118 return vioc->del_window(bcontainer, section);
119 }
120
vfio_container_set_dirty_page_tracking(VFIOContainerBase * bcontainer,bool start,Error ** errp)121 int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer,
122 bool start, Error **errp)
123 {
124 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
125 int ret;
126
127 if (!bcontainer->dirty_pages_supported) {
128 return 0;
129 }
130
131 g_assert(vioc->set_dirty_page_tracking);
132 if (bcontainer->dirty_pages_started == start) {
133 return 0;
134 }
135
136 ret = vioc->set_dirty_page_tracking(bcontainer, start, errp);
137 if (!ret) {
138 bcontainer->dirty_pages_started = start;
139 }
140
141 return ret;
142 }
143
vfio_container_devices_dirty_tracking_is_started(const VFIOContainerBase * bcontainer)144 static bool vfio_container_devices_dirty_tracking_is_started(
145 const VFIOContainerBase *bcontainer)
146 {
147 VFIODevice *vbasedev;
148
149 QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
150 if (!vbasedev->dirty_tracking) {
151 return false;
152 }
153 }
154
155 return true;
156 }
157
vfio_container_dirty_tracking_is_started(const VFIOContainerBase * bcontainer)158 bool vfio_container_dirty_tracking_is_started(
159 const VFIOContainerBase *bcontainer)
160 {
161 return vfio_container_devices_dirty_tracking_is_started(bcontainer) ||
162 bcontainer->dirty_pages_started;
163 }
164
vfio_container_devices_dirty_tracking_is_supported(const VFIOContainerBase * bcontainer)165 bool vfio_container_devices_dirty_tracking_is_supported(
166 const VFIOContainerBase *bcontainer)
167 {
168 VFIODevice *vbasedev;
169
170 QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
171 if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
172 return false;
173 }
174 if (!vbasedev->dirty_pages_supported) {
175 return false;
176 }
177 }
178
179 return true;
180 }
181
vfio_device_dma_logging_report(VFIODevice * vbasedev,hwaddr iova,hwaddr size,void * bitmap)182 static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova,
183 hwaddr size, void *bitmap)
184 {
185 uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) +
186 sizeof(struct vfio_device_feature_dma_logging_report),
187 sizeof(uint64_t))] = {};
188 struct vfio_device_feature *feature = (struct vfio_device_feature *)buf;
189 struct vfio_device_feature_dma_logging_report *report =
190 (struct vfio_device_feature_dma_logging_report *)feature->data;
191
192 report->iova = iova;
193 report->length = size;
194 report->page_size = qemu_real_host_page_size();
195 report->bitmap = (uintptr_t)bitmap;
196
197 feature->argsz = sizeof(buf);
198 feature->flags = VFIO_DEVICE_FEATURE_GET |
199 VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT;
200
201 return vbasedev->io_ops->device_feature(vbasedev, feature);
202 }
203
vfio_container_iommu_query_dirty_bitmap(const VFIOContainerBase * bcontainer,VFIOBitmap * vbmap,hwaddr iova,hwaddr size,Error ** errp)204 static int vfio_container_iommu_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
205 VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
206 {
207 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
208
209 g_assert(vioc->query_dirty_bitmap);
210 return vioc->query_dirty_bitmap(bcontainer, vbmap, iova, size,
211 errp);
212 }
213
vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase * bcontainer,VFIOBitmap * vbmap,hwaddr iova,hwaddr size,Error ** errp)214 static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
215 VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp)
216 {
217 VFIODevice *vbasedev;
218 int ret;
219
220 QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
221 ret = vfio_device_dma_logging_report(vbasedev, iova, size,
222 vbmap->bitmap);
223 if (ret) {
224 error_setg_errno(errp, -ret,
225 "%s: Failed to get DMA logging report, iova: "
226 "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx,
227 vbasedev->name, iova, size);
228
229 return ret;
230 }
231 }
232
233 return 0;
234 }
235
vfio_container_query_dirty_bitmap(const VFIOContainerBase * bcontainer,uint64_t iova,uint64_t size,ram_addr_t ram_addr,Error ** errp)236 int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova,
237 uint64_t size, ram_addr_t ram_addr, Error **errp)
238 {
239 bool all_device_dirty_tracking =
240 vfio_container_devices_dirty_tracking_is_supported(bcontainer);
241 uint64_t dirty_pages;
242 VFIOBitmap vbmap;
243 int ret;
244
245 if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) {
246 cpu_physical_memory_set_dirty_range(ram_addr, size,
247 tcg_enabled() ? DIRTY_CLIENTS_ALL :
248 DIRTY_CLIENTS_NOCODE);
249 return 0;
250 }
251
252 ret = vfio_bitmap_alloc(&vbmap, size);
253 if (ret) {
254 error_setg_errno(errp, -ret,
255 "Failed to allocate dirty tracking bitmap");
256 return ret;
257 }
258
259 if (all_device_dirty_tracking) {
260 ret = vfio_container_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
261 errp);
262 } else {
263 ret = vfio_container_iommu_query_dirty_bitmap(bcontainer, &vbmap, iova, size,
264 errp);
265 }
266
267 if (ret) {
268 goto out;
269 }
270
271 dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr,
272 vbmap.pages);
273
274 trace_vfio_container_query_dirty_bitmap(iova, size, vbmap.size, ram_addr,
275 dirty_pages);
276 out:
277 g_free(vbmap.bitmap);
278
279 return ret;
280 }
281
copy_iova_range(gconstpointer src,gpointer data)282 static gpointer copy_iova_range(gconstpointer src, gpointer data)
283 {
284 Range *source = (Range *)src;
285 Range *dest = g_new(Range, 1);
286
287 range_set_bounds(dest, range_lob(source), range_upb(source));
288 return dest;
289 }
290
vfio_container_get_iova_ranges(const VFIOContainerBase * bcontainer)291 GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer)
292 {
293 assert(bcontainer);
294 return g_list_copy_deep(bcontainer->iova_ranges, copy_iova_range, NULL);
295 }
296
vfio_container_instance_finalize(Object * obj)297 static void vfio_container_instance_finalize(Object *obj)
298 {
299 VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);
300 VFIOGuestIOMMU *giommu, *tmp;
301
302 QLIST_SAFE_REMOVE(bcontainer, next);
303
304 QLIST_FOREACH_SAFE(giommu, &bcontainer->giommu_list, giommu_next, tmp) {
305 memory_region_unregister_iommu_notifier(
306 MEMORY_REGION(giommu->iommu_mr), &giommu->n);
307 QLIST_REMOVE(giommu, giommu_next);
308 g_free(giommu);
309 }
310
311 g_list_free_full(bcontainer->iova_ranges, g_free);
312 }
313
vfio_container_instance_init(Object * obj)314 static void vfio_container_instance_init(Object *obj)
315 {
316 VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);
317
318 bcontainer->error = NULL;
319 bcontainer->dirty_pages_supported = false;
320 bcontainer->dma_max_mappings = 0;
321 bcontainer->iova_ranges = NULL;
322 QLIST_INIT(&bcontainer->giommu_list);
323 QLIST_INIT(&bcontainer->vrdl_list);
324 }
325
326 static const TypeInfo types[] = {
327 {
328 .name = TYPE_VFIO_IOMMU,
329 .parent = TYPE_OBJECT,
330 .instance_init = vfio_container_instance_init,
331 .instance_finalize = vfio_container_instance_finalize,
332 .instance_size = sizeof(VFIOContainerBase),
333 .class_size = sizeof(VFIOIOMMUClass),
334 .abstract = true,
335 },
336 };
337
338 DEFINE_TYPES(types)
339