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) 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); 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 if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { 202 return -errno; 203 } 204 205 return 0; 206 } 207 208 static int vfio_container_iommu_query_dirty_bitmap(const VFIOContainerBase *bcontainer, 209 VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) 210 { 211 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 212 213 g_assert(vioc->query_dirty_bitmap); 214 return vioc->query_dirty_bitmap(bcontainer, vbmap, iova, size, 215 errp); 216 } 217 218 static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, 219 VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) 220 { 221 VFIODevice *vbasedev; 222 int ret; 223 224 QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { 225 ret = vfio_device_dma_logging_report(vbasedev, iova, size, 226 vbmap->bitmap); 227 if (ret) { 228 error_setg_errno(errp, -ret, 229 "%s: Failed to get DMA logging report, iova: " 230 "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx, 231 vbasedev->name, iova, size); 232 233 return ret; 234 } 235 } 236 237 return 0; 238 } 239 240 int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, 241 uint64_t size, ram_addr_t ram_addr, Error **errp) 242 { 243 bool all_device_dirty_tracking = 244 vfio_container_devices_dirty_tracking_is_supported(bcontainer); 245 uint64_t dirty_pages; 246 VFIOBitmap vbmap; 247 int ret; 248 249 if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) { 250 cpu_physical_memory_set_dirty_range(ram_addr, size, 251 tcg_enabled() ? DIRTY_CLIENTS_ALL : 252 DIRTY_CLIENTS_NOCODE); 253 return 0; 254 } 255 256 ret = vfio_bitmap_alloc(&vbmap, size); 257 if (ret) { 258 error_setg_errno(errp, -ret, 259 "Failed to allocate dirty tracking bitmap"); 260 return ret; 261 } 262 263 if (all_device_dirty_tracking) { 264 ret = vfio_container_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, 265 errp); 266 } else { 267 ret = vfio_container_iommu_query_dirty_bitmap(bcontainer, &vbmap, iova, size, 268 errp); 269 } 270 271 if (ret) { 272 goto out; 273 } 274 275 dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr, 276 vbmap.pages); 277 278 trace_vfio_container_query_dirty_bitmap(iova, size, vbmap.size, ram_addr, 279 dirty_pages); 280 out: 281 g_free(vbmap.bitmap); 282 283 return ret; 284 } 285 286 static gpointer copy_iova_range(gconstpointer src, gpointer data) 287 { 288 Range *source = (Range *)src; 289 Range *dest = g_new(Range, 1); 290 291 range_set_bounds(dest, range_lob(source), range_upb(source)); 292 return dest; 293 } 294 295 GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer) 296 { 297 assert(bcontainer); 298 return g_list_copy_deep(bcontainer->iova_ranges, copy_iova_range, NULL); 299 } 300 301 static void vfio_container_instance_finalize(Object *obj) 302 { 303 VFIOContainerBase *bcontainer = VFIO_IOMMU(obj); 304 VFIOGuestIOMMU *giommu, *tmp; 305 306 QLIST_SAFE_REMOVE(bcontainer, next); 307 308 QLIST_FOREACH_SAFE(giommu, &bcontainer->giommu_list, giommu_next, tmp) { 309 memory_region_unregister_iommu_notifier( 310 MEMORY_REGION(giommu->iommu_mr), &giommu->n); 311 QLIST_REMOVE(giommu, giommu_next); 312 g_free(giommu); 313 } 314 315 g_list_free_full(bcontainer->iova_ranges, g_free); 316 } 317 318 static void vfio_container_instance_init(Object *obj) 319 { 320 VFIOContainerBase *bcontainer = VFIO_IOMMU(obj); 321 322 bcontainer->error = NULL; 323 bcontainer->dirty_pages_supported = false; 324 bcontainer->dma_max_mappings = 0; 325 bcontainer->iova_ranges = NULL; 326 QLIST_INIT(&bcontainer->giommu_list); 327 QLIST_INIT(&bcontainer->vrdl_list); 328 } 329 330 static const TypeInfo types[] = { 331 { 332 .name = TYPE_VFIO_IOMMU, 333 .parent = TYPE_OBJECT, 334 .instance_init = vfio_container_instance_init, 335 .instance_finalize = vfio_container_instance_finalize, 336 .instance_size = sizeof(VFIOContainerBase), 337 .class_size = sizeof(VFIOIOMMUClass), 338 .abstract = true, 339 }, 340 }; 341 342 DEFINE_TYPES(types) 343