1499e53ccSCédric Le Goater /* 2499e53ccSCédric Le Goater * VFIO regions 3499e53ccSCédric Le Goater * 4499e53ccSCédric Le Goater * Copyright Red Hat, Inc. 2012 5499e53ccSCédric Le Goater * 6499e53ccSCédric Le Goater * Authors: 7499e53ccSCédric Le Goater * Alex Williamson <alex.williamson@redhat.com> 8499e53ccSCédric Le Goater * 9499e53ccSCédric Le Goater * This work is licensed under the terms of the GNU GPL, version 2. See 10499e53ccSCédric Le Goater * the COPYING file in the top-level directory. 11499e53ccSCédric Le Goater * 12499e53ccSCédric Le Goater * Based on qemu-kvm device-assignment: 13499e53ccSCédric Le Goater * Adapted for KVM by Qumranet. 14499e53ccSCédric Le Goater * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) 15499e53ccSCédric Le Goater * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) 16499e53ccSCédric Le Goater * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) 17499e53ccSCédric Le Goater * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) 18499e53ccSCédric Le Goater * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) 19499e53ccSCédric Le Goater */ 20499e53ccSCédric Le Goater 21499e53ccSCédric Le Goater #include "qemu/osdep.h" 22499e53ccSCédric Le Goater #include <sys/ioctl.h> 23499e53ccSCédric Le Goater 24*11b8b9d5SCédric Le Goater #include "hw/vfio/vfio-region.h" 25*11b8b9d5SCédric Le Goater #include "hw/vfio/vfio-device.h" 26499e53ccSCédric Le Goater #include "hw/hw.h" 27499e53ccSCédric Le Goater #include "trace.h" 28499e53ccSCédric Le Goater #include "qapi/error.h" 29499e53ccSCédric Le Goater #include "qemu/error-report.h" 30499e53ccSCédric Le Goater #include "qemu/units.h" 31499e53ccSCédric Le Goater #include "monitor/monitor.h" 32ac28680dSCédric Le Goater #include "vfio-helpers.h" 33499e53ccSCédric Le Goater 34499e53ccSCédric Le Goater /* 35499e53ccSCédric Le Goater * IO Port/MMIO - Beware of the endians, VFIO is always little endian 36499e53ccSCédric Le Goater */ 37499e53ccSCédric Le Goater void vfio_region_write(void *opaque, hwaddr addr, 38499e53ccSCédric Le Goater uint64_t data, unsigned size) 39499e53ccSCédric Le Goater { 40499e53ccSCédric Le Goater VFIORegion *region = opaque; 41499e53ccSCédric Le Goater VFIODevice *vbasedev = region->vbasedev; 42499e53ccSCédric Le Goater union { 43499e53ccSCédric Le Goater uint8_t byte; 44499e53ccSCédric Le Goater uint16_t word; 45499e53ccSCédric Le Goater uint32_t dword; 46499e53ccSCédric Le Goater uint64_t qword; 47499e53ccSCédric Le Goater } buf; 48499e53ccSCédric Le Goater 49499e53ccSCédric Le Goater switch (size) { 50499e53ccSCédric Le Goater case 1: 51499e53ccSCédric Le Goater buf.byte = data; 52499e53ccSCédric Le Goater break; 53499e53ccSCédric Le Goater case 2: 54499e53ccSCédric Le Goater buf.word = cpu_to_le16(data); 55499e53ccSCédric Le Goater break; 56499e53ccSCédric Le Goater case 4: 57499e53ccSCédric Le Goater buf.dword = cpu_to_le32(data); 58499e53ccSCédric Le Goater break; 59499e53ccSCédric Le Goater case 8: 60499e53ccSCédric Le Goater buf.qword = cpu_to_le64(data); 61499e53ccSCédric Le Goater break; 62499e53ccSCédric Le Goater default: 63499e53ccSCédric Le Goater hw_error("vfio: unsupported write size, %u bytes", size); 64499e53ccSCédric Le Goater break; 65499e53ccSCédric Le Goater } 66499e53ccSCédric Le Goater 67499e53ccSCédric Le Goater if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { 68499e53ccSCédric Le Goater error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 69499e53ccSCédric Le Goater ",%d) failed: %m", 70499e53ccSCédric Le Goater __func__, vbasedev->name, region->nr, 71499e53ccSCédric Le Goater addr, data, size); 72499e53ccSCédric Le Goater } 73499e53ccSCédric Le Goater 74499e53ccSCédric Le Goater trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); 75499e53ccSCédric Le Goater 76499e53ccSCédric Le Goater /* 77499e53ccSCédric Le Goater * A read or write to a BAR always signals an INTx EOI. This will 78499e53ccSCédric Le Goater * do nothing if not pending (including not in INTx mode). We assume 79499e53ccSCédric Le Goater * that a BAR access is in response to an interrupt and that BAR 80499e53ccSCédric Le Goater * accesses will service the interrupt. Unfortunately, we don't know 81499e53ccSCédric Le Goater * which access will service the interrupt, so we're potentially 82499e53ccSCédric Le Goater * getting quite a few host interrupts per guest interrupt. 83499e53ccSCédric Le Goater */ 84499e53ccSCédric Le Goater vbasedev->ops->vfio_eoi(vbasedev); 85499e53ccSCédric Le Goater } 86499e53ccSCédric Le Goater 87499e53ccSCédric Le Goater uint64_t vfio_region_read(void *opaque, 88499e53ccSCédric Le Goater hwaddr addr, unsigned size) 89499e53ccSCédric Le Goater { 90499e53ccSCédric Le Goater VFIORegion *region = opaque; 91499e53ccSCédric Le Goater VFIODevice *vbasedev = region->vbasedev; 92499e53ccSCédric Le Goater union { 93499e53ccSCédric Le Goater uint8_t byte; 94499e53ccSCédric Le Goater uint16_t word; 95499e53ccSCédric Le Goater uint32_t dword; 96499e53ccSCédric Le Goater uint64_t qword; 97499e53ccSCédric Le Goater } buf; 98499e53ccSCédric Le Goater uint64_t data = 0; 99499e53ccSCédric Le Goater 100499e53ccSCédric Le Goater if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { 101499e53ccSCédric Le Goater error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", 102499e53ccSCédric Le Goater __func__, vbasedev->name, region->nr, 103499e53ccSCédric Le Goater addr, size); 104499e53ccSCédric Le Goater return (uint64_t)-1; 105499e53ccSCédric Le Goater } 106499e53ccSCédric Le Goater switch (size) { 107499e53ccSCédric Le Goater case 1: 108499e53ccSCédric Le Goater data = buf.byte; 109499e53ccSCédric Le Goater break; 110499e53ccSCédric Le Goater case 2: 111499e53ccSCédric Le Goater data = le16_to_cpu(buf.word); 112499e53ccSCédric Le Goater break; 113499e53ccSCédric Le Goater case 4: 114499e53ccSCédric Le Goater data = le32_to_cpu(buf.dword); 115499e53ccSCédric Le Goater break; 116499e53ccSCédric Le Goater case 8: 117499e53ccSCédric Le Goater data = le64_to_cpu(buf.qword); 118499e53ccSCédric Le Goater break; 119499e53ccSCédric Le Goater default: 120499e53ccSCédric Le Goater hw_error("vfio: unsupported read size, %u bytes", size); 121499e53ccSCédric Le Goater break; 122499e53ccSCédric Le Goater } 123499e53ccSCédric Le Goater 124499e53ccSCédric Le Goater trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); 125499e53ccSCédric Le Goater 126499e53ccSCédric Le Goater /* Same as write above */ 127499e53ccSCédric Le Goater vbasedev->ops->vfio_eoi(vbasedev); 128499e53ccSCédric Le Goater 129499e53ccSCédric Le Goater return data; 130499e53ccSCédric Le Goater } 131499e53ccSCédric Le Goater 132499e53ccSCédric Le Goater static const MemoryRegionOps vfio_region_ops = { 133499e53ccSCédric Le Goater .read = vfio_region_read, 134499e53ccSCédric Le Goater .write = vfio_region_write, 135499e53ccSCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 136499e53ccSCédric Le Goater .valid = { 137499e53ccSCédric Le Goater .min_access_size = 1, 138499e53ccSCédric Le Goater .max_access_size = 8, 139499e53ccSCédric Le Goater }, 140499e53ccSCédric Le Goater .impl = { 141499e53ccSCédric Le Goater .min_access_size = 1, 142499e53ccSCédric Le Goater .max_access_size = 8, 143499e53ccSCédric Le Goater }, 144499e53ccSCédric Le Goater }; 145499e53ccSCédric Le Goater 146499e53ccSCédric Le Goater static int vfio_setup_region_sparse_mmaps(VFIORegion *region, 147499e53ccSCédric Le Goater struct vfio_region_info *info) 148499e53ccSCédric Le Goater { 149499e53ccSCédric Le Goater struct vfio_info_cap_header *hdr; 150499e53ccSCédric Le Goater struct vfio_region_info_cap_sparse_mmap *sparse; 151499e53ccSCédric Le Goater int i, j; 152499e53ccSCédric Le Goater 153499e53ccSCédric Le Goater hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); 154499e53ccSCédric Le Goater if (!hdr) { 155499e53ccSCédric Le Goater return -ENODEV; 156499e53ccSCédric Le Goater } 157499e53ccSCédric Le Goater 158499e53ccSCédric Le Goater sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); 159499e53ccSCédric Le Goater 160499e53ccSCédric Le Goater trace_vfio_region_sparse_mmap_header(region->vbasedev->name, 161499e53ccSCédric Le Goater region->nr, sparse->nr_areas); 162499e53ccSCédric Le Goater 163499e53ccSCédric Le Goater region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); 164499e53ccSCédric Le Goater 165499e53ccSCédric Le Goater for (i = 0, j = 0; i < sparse->nr_areas; i++) { 166499e53ccSCédric Le Goater if (sparse->areas[i].size) { 167499e53ccSCédric Le Goater trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, 168499e53ccSCédric Le Goater sparse->areas[i].offset + 169499e53ccSCédric Le Goater sparse->areas[i].size - 1); 170499e53ccSCédric Le Goater region->mmaps[j].offset = sparse->areas[i].offset; 171499e53ccSCédric Le Goater region->mmaps[j].size = sparse->areas[i].size; 172499e53ccSCédric Le Goater j++; 173499e53ccSCédric Le Goater } 174499e53ccSCédric Le Goater } 175499e53ccSCédric Le Goater 176499e53ccSCédric Le Goater region->nr_mmaps = j; 177499e53ccSCédric Le Goater region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); 178499e53ccSCédric Le Goater 179499e53ccSCédric Le Goater return 0; 180499e53ccSCédric Le Goater } 181499e53ccSCédric Le Goater 182499e53ccSCédric Le Goater int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, 183499e53ccSCédric Le Goater int index, const char *name) 184499e53ccSCédric Le Goater { 185499e53ccSCédric Le Goater g_autofree struct vfio_region_info *info = NULL; 186499e53ccSCédric Le Goater int ret; 187499e53ccSCédric Le Goater 188499e53ccSCédric Le Goater ret = vfio_get_region_info(vbasedev, index, &info); 189499e53ccSCédric Le Goater if (ret) { 190499e53ccSCédric Le Goater return ret; 191499e53ccSCédric Le Goater } 192499e53ccSCédric Le Goater 193499e53ccSCédric Le Goater region->vbasedev = vbasedev; 194499e53ccSCédric Le Goater region->flags = info->flags; 195499e53ccSCédric Le Goater region->size = info->size; 196499e53ccSCédric Le Goater region->fd_offset = info->offset; 197499e53ccSCédric Le Goater region->nr = index; 198499e53ccSCédric Le Goater 199499e53ccSCédric Le Goater if (region->size) { 200499e53ccSCédric Le Goater region->mem = g_new0(MemoryRegion, 1); 201499e53ccSCédric Le Goater memory_region_init_io(region->mem, obj, &vfio_region_ops, 202499e53ccSCédric Le Goater region, name, region->size); 203499e53ccSCédric Le Goater 204499e53ccSCédric Le Goater if (!vbasedev->no_mmap && 205499e53ccSCédric Le Goater region->flags & VFIO_REGION_INFO_FLAG_MMAP) { 206499e53ccSCédric Le Goater 207499e53ccSCédric Le Goater ret = vfio_setup_region_sparse_mmaps(region, info); 208499e53ccSCédric Le Goater 209499e53ccSCédric Le Goater if (ret) { 210499e53ccSCédric Le Goater region->nr_mmaps = 1; 211499e53ccSCédric Le Goater region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); 212499e53ccSCédric Le Goater region->mmaps[0].offset = 0; 213499e53ccSCédric Le Goater region->mmaps[0].size = region->size; 214499e53ccSCédric Le Goater } 215499e53ccSCédric Le Goater } 216499e53ccSCédric Le Goater } 217499e53ccSCédric Le Goater 218499e53ccSCédric Le Goater trace_vfio_region_setup(vbasedev->name, index, name, 219499e53ccSCédric Le Goater region->flags, region->fd_offset, region->size); 220499e53ccSCédric Le Goater return 0; 221499e53ccSCédric Le Goater } 222499e53ccSCédric Le Goater 223499e53ccSCédric Le Goater static void vfio_subregion_unmap(VFIORegion *region, int index) 224499e53ccSCédric Le Goater { 225499e53ccSCédric Le Goater trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), 226499e53ccSCédric Le Goater region->mmaps[index].offset, 227499e53ccSCédric Le Goater region->mmaps[index].offset + 228499e53ccSCédric Le Goater region->mmaps[index].size - 1); 229499e53ccSCédric Le Goater memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); 230499e53ccSCédric Le Goater munmap(region->mmaps[index].mmap, region->mmaps[index].size); 231499e53ccSCédric Le Goater object_unparent(OBJECT(®ion->mmaps[index].mem)); 232499e53ccSCédric Le Goater region->mmaps[index].mmap = NULL; 233499e53ccSCédric Le Goater } 234499e53ccSCédric Le Goater 235499e53ccSCédric Le Goater int vfio_region_mmap(VFIORegion *region) 236499e53ccSCédric Le Goater { 237499e53ccSCédric Le Goater int i, ret, prot = 0; 238499e53ccSCédric Le Goater char *name; 239499e53ccSCédric Le Goater 240499e53ccSCédric Le Goater if (!region->mem) { 241499e53ccSCédric Le Goater return 0; 242499e53ccSCédric Le Goater } 243499e53ccSCédric Le Goater 244499e53ccSCédric Le Goater prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; 245499e53ccSCédric Le Goater prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; 246499e53ccSCédric Le Goater 247499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 248499e53ccSCédric Le Goater size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB); 249499e53ccSCédric Le Goater void *map_base, *map_align; 250499e53ccSCédric Le Goater 251499e53ccSCédric Le Goater /* 252499e53ccSCédric Le Goater * Align the mmap for more efficient mapping in the kernel. Ideally 253499e53ccSCédric Le Goater * we'd know the PMD and PUD mapping sizes to use as discrete alignment 254499e53ccSCédric Le Goater * intervals, but we don't. As of Linux v6.12, the largest PUD size 255499e53ccSCédric Le Goater * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set 256499e53ccSCédric Le Goater * on x86_64). Align by power-of-two size, capped at 1GiB. 257499e53ccSCédric Le Goater * 258499e53ccSCédric Le Goater * NB. qemu_memalign() and friends actually allocate memory, whereas 259499e53ccSCédric Le Goater * the region size here can exceed host memory, therefore we manually 260499e53ccSCédric Le Goater * create an oversized anonymous mapping and clean it up for alignment. 261499e53ccSCédric Le Goater */ 262499e53ccSCédric Le Goater map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE, 263499e53ccSCédric Le Goater MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 264499e53ccSCédric Le Goater if (map_base == MAP_FAILED) { 265499e53ccSCédric Le Goater ret = -errno; 266499e53ccSCédric Le Goater goto no_mmap; 267499e53ccSCédric Le Goater } 268499e53ccSCédric Le Goater 269499e53ccSCédric Le Goater map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align); 270499e53ccSCédric Le Goater munmap(map_base, map_align - map_base); 271499e53ccSCédric Le Goater munmap(map_align + region->mmaps[i].size, 272499e53ccSCédric Le Goater align - (map_align - map_base)); 273499e53ccSCédric Le Goater 274499e53ccSCédric Le Goater region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot, 275499e53ccSCédric Le Goater MAP_SHARED | MAP_FIXED, 276499e53ccSCédric Le Goater region->vbasedev->fd, 277499e53ccSCédric Le Goater region->fd_offset + 278499e53ccSCédric Le Goater region->mmaps[i].offset); 279499e53ccSCédric Le Goater if (region->mmaps[i].mmap == MAP_FAILED) { 280499e53ccSCédric Le Goater ret = -errno; 281499e53ccSCédric Le Goater goto no_mmap; 282499e53ccSCédric Le Goater } 283499e53ccSCédric Le Goater 284499e53ccSCédric Le Goater name = g_strdup_printf("%s mmaps[%d]", 285499e53ccSCédric Le Goater memory_region_name(region->mem), i); 286499e53ccSCédric Le Goater memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, 287499e53ccSCédric Le Goater memory_region_owner(region->mem), 288499e53ccSCédric Le Goater name, region->mmaps[i].size, 289499e53ccSCédric Le Goater region->mmaps[i].mmap); 290499e53ccSCédric Le Goater g_free(name); 291499e53ccSCédric Le Goater memory_region_add_subregion(region->mem, region->mmaps[i].offset, 292499e53ccSCédric Le Goater ®ion->mmaps[i].mem); 293499e53ccSCédric Le Goater 294499e53ccSCédric Le Goater trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), 295499e53ccSCédric Le Goater region->mmaps[i].offset, 296499e53ccSCédric Le Goater region->mmaps[i].offset + 297499e53ccSCédric Le Goater region->mmaps[i].size - 1); 298499e53ccSCédric Le Goater } 299499e53ccSCédric Le Goater 300499e53ccSCédric Le Goater return 0; 301499e53ccSCédric Le Goater 302499e53ccSCédric Le Goater no_mmap: 303499e53ccSCédric Le Goater trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, 304499e53ccSCédric Le Goater region->fd_offset + region->mmaps[i].offset, 305499e53ccSCédric Le Goater region->fd_offset + region->mmaps[i].offset + 306499e53ccSCédric Le Goater region->mmaps[i].size - 1, ret); 307499e53ccSCédric Le Goater 308499e53ccSCédric Le Goater region->mmaps[i].mmap = NULL; 309499e53ccSCédric Le Goater 310499e53ccSCédric Le Goater for (i--; i >= 0; i--) { 311499e53ccSCédric Le Goater vfio_subregion_unmap(region, i); 312499e53ccSCédric Le Goater } 313499e53ccSCédric Le Goater 314499e53ccSCédric Le Goater return ret; 315499e53ccSCédric Le Goater } 316499e53ccSCédric Le Goater 317499e53ccSCédric Le Goater void vfio_region_unmap(VFIORegion *region) 318499e53ccSCédric Le Goater { 319499e53ccSCédric Le Goater int i; 320499e53ccSCédric Le Goater 321499e53ccSCédric Le Goater if (!region->mem) { 322499e53ccSCédric Le Goater return; 323499e53ccSCédric Le Goater } 324499e53ccSCédric Le Goater 325499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 326499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 327499e53ccSCédric Le Goater vfio_subregion_unmap(region, i); 328499e53ccSCédric Le Goater } 329499e53ccSCédric Le Goater } 330499e53ccSCédric Le Goater } 331499e53ccSCédric Le Goater 332499e53ccSCédric Le Goater void vfio_region_exit(VFIORegion *region) 333499e53ccSCédric Le Goater { 334499e53ccSCédric Le Goater int i; 335499e53ccSCédric Le Goater 336499e53ccSCédric Le Goater if (!region->mem) { 337499e53ccSCédric Le Goater return; 338499e53ccSCédric Le Goater } 339499e53ccSCédric Le Goater 340499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 341499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 342499e53ccSCédric Le Goater memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); 343499e53ccSCédric Le Goater } 344499e53ccSCédric Le Goater } 345499e53ccSCédric Le Goater 346499e53ccSCédric Le Goater trace_vfio_region_exit(region->vbasedev->name, region->nr); 347499e53ccSCédric Le Goater } 348499e53ccSCédric Le Goater 349499e53ccSCédric Le Goater void vfio_region_finalize(VFIORegion *region) 350499e53ccSCédric Le Goater { 351499e53ccSCédric Le Goater int i; 352499e53ccSCédric Le Goater 353499e53ccSCédric Le Goater if (!region->mem) { 354499e53ccSCédric Le Goater return; 355499e53ccSCédric Le Goater } 356499e53ccSCédric Le Goater 357499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 358499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 359499e53ccSCédric Le Goater munmap(region->mmaps[i].mmap, region->mmaps[i].size); 360499e53ccSCédric Le Goater object_unparent(OBJECT(®ion->mmaps[i].mem)); 361499e53ccSCédric Le Goater } 362499e53ccSCédric Le Goater } 363499e53ccSCédric Le Goater 364499e53ccSCédric Le Goater object_unparent(OBJECT(region->mem)); 365499e53ccSCédric Le Goater 366499e53ccSCédric Le Goater g_free(region->mem); 367499e53ccSCédric Le Goater g_free(region->mmaps); 368499e53ccSCédric Le Goater 369499e53ccSCédric Le Goater trace_vfio_region_finalize(region->vbasedev->name, region->nr); 370499e53ccSCédric Le Goater 371499e53ccSCédric Le Goater region->mem = NULL; 372499e53ccSCédric Le Goater region->mmaps = NULL; 373499e53ccSCédric Le Goater region->nr_mmaps = 0; 374499e53ccSCédric Le Goater region->size = 0; 375499e53ccSCédric Le Goater region->flags = 0; 376499e53ccSCédric Le Goater region->nr = 0; 377499e53ccSCédric Le Goater } 378499e53ccSCédric Le Goater 379499e53ccSCédric Le Goater void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) 380499e53ccSCédric Le Goater { 381499e53ccSCédric Le Goater int i; 382499e53ccSCédric Le Goater 383499e53ccSCédric Le Goater if (!region->mem) { 384499e53ccSCédric Le Goater return; 385499e53ccSCédric Le Goater } 386499e53ccSCédric Le Goater 387499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 388499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 389499e53ccSCédric Le Goater memory_region_set_enabled(®ion->mmaps[i].mem, enabled); 390499e53ccSCédric Le Goater } 391499e53ccSCédric Le Goater } 392499e53ccSCédric Le Goater 393499e53ccSCédric Le Goater trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), 394499e53ccSCédric Le Goater enabled); 395499e53ccSCédric Le Goater } 396