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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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