1*499e53ccSCédric Le Goater /* 2*499e53ccSCédric Le Goater * VFIO regions 3*499e53ccSCédric Le Goater * 4*499e53ccSCédric Le Goater * Copyright Red Hat, Inc. 2012 5*499e53ccSCédric Le Goater * 6*499e53ccSCédric Le Goater * Authors: 7*499e53ccSCédric Le Goater * Alex Williamson <alex.williamson@redhat.com> 8*499e53ccSCédric Le Goater * 9*499e53ccSCédric Le Goater * This work is licensed under the terms of the GNU GPL, version 2. See 10*499e53ccSCédric Le Goater * the COPYING file in the top-level directory. 11*499e53ccSCédric Le Goater * 12*499e53ccSCédric Le Goater * Based on qemu-kvm device-assignment: 13*499e53ccSCédric Le Goater * Adapted for KVM by Qumranet. 14*499e53ccSCédric Le Goater * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) 15*499e53ccSCédric Le Goater * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) 16*499e53ccSCédric Le Goater * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) 17*499e53ccSCédric Le Goater * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) 18*499e53ccSCédric Le Goater * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) 19*499e53ccSCédric Le Goater */ 20*499e53ccSCédric Le Goater 21*499e53ccSCédric Le Goater #include "qemu/osdep.h" 22*499e53ccSCédric Le Goater #include <sys/ioctl.h> 23*499e53ccSCédric Le Goater 24*499e53ccSCédric Le Goater #include "hw/vfio/vfio-common.h" 25*499e53ccSCédric Le Goater #include "hw/vfio/pci.h" 26*499e53ccSCédric Le Goater #include "hw/hw.h" 27*499e53ccSCédric Le Goater #include "trace.h" 28*499e53ccSCédric Le Goater #include "qapi/error.h" 29*499e53ccSCédric Le Goater #include "qemu/error-report.h" 30*499e53ccSCédric Le Goater #include "qemu/units.h" 31*499e53ccSCédric Le Goater #include "monitor/monitor.h" 32*499e53ccSCédric Le Goater 33*499e53ccSCédric Le Goater /* 34*499e53ccSCédric Le Goater * IO Port/MMIO - Beware of the endians, VFIO is always little endian 35*499e53ccSCédric Le Goater */ 36*499e53ccSCédric Le Goater void vfio_region_write(void *opaque, hwaddr addr, 37*499e53ccSCédric Le Goater uint64_t data, unsigned size) 38*499e53ccSCédric Le Goater { 39*499e53ccSCédric Le Goater VFIORegion *region = opaque; 40*499e53ccSCédric Le Goater VFIODevice *vbasedev = region->vbasedev; 41*499e53ccSCédric Le Goater union { 42*499e53ccSCédric Le Goater uint8_t byte; 43*499e53ccSCédric Le Goater uint16_t word; 44*499e53ccSCédric Le Goater uint32_t dword; 45*499e53ccSCédric Le Goater uint64_t qword; 46*499e53ccSCédric Le Goater } buf; 47*499e53ccSCédric Le Goater 48*499e53ccSCédric Le Goater switch (size) { 49*499e53ccSCédric Le Goater case 1: 50*499e53ccSCédric Le Goater buf.byte = data; 51*499e53ccSCédric Le Goater break; 52*499e53ccSCédric Le Goater case 2: 53*499e53ccSCédric Le Goater buf.word = cpu_to_le16(data); 54*499e53ccSCédric Le Goater break; 55*499e53ccSCédric Le Goater case 4: 56*499e53ccSCédric Le Goater buf.dword = cpu_to_le32(data); 57*499e53ccSCédric Le Goater break; 58*499e53ccSCédric Le Goater case 8: 59*499e53ccSCédric Le Goater buf.qword = cpu_to_le64(data); 60*499e53ccSCédric Le Goater break; 61*499e53ccSCédric Le Goater default: 62*499e53ccSCédric Le Goater hw_error("vfio: unsupported write size, %u bytes", size); 63*499e53ccSCédric Le Goater break; 64*499e53ccSCédric Le Goater } 65*499e53ccSCédric Le Goater 66*499e53ccSCédric Le Goater if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { 67*499e53ccSCédric Le Goater error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 68*499e53ccSCédric Le Goater ",%d) failed: %m", 69*499e53ccSCédric Le Goater __func__, vbasedev->name, region->nr, 70*499e53ccSCédric Le Goater addr, data, size); 71*499e53ccSCédric Le Goater } 72*499e53ccSCédric Le Goater 73*499e53ccSCédric Le Goater trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); 74*499e53ccSCédric Le Goater 75*499e53ccSCédric Le Goater /* 76*499e53ccSCédric Le Goater * A read or write to a BAR always signals an INTx EOI. This will 77*499e53ccSCédric Le Goater * do nothing if not pending (including not in INTx mode). We assume 78*499e53ccSCédric Le Goater * that a BAR access is in response to an interrupt and that BAR 79*499e53ccSCédric Le Goater * accesses will service the interrupt. Unfortunately, we don't know 80*499e53ccSCédric Le Goater * which access will service the interrupt, so we're potentially 81*499e53ccSCédric Le Goater * getting quite a few host interrupts per guest interrupt. 82*499e53ccSCédric Le Goater */ 83*499e53ccSCédric Le Goater vbasedev->ops->vfio_eoi(vbasedev); 84*499e53ccSCédric Le Goater } 85*499e53ccSCédric Le Goater 86*499e53ccSCédric Le Goater uint64_t vfio_region_read(void *opaque, 87*499e53ccSCédric Le Goater hwaddr addr, unsigned size) 88*499e53ccSCédric Le Goater { 89*499e53ccSCédric Le Goater VFIORegion *region = opaque; 90*499e53ccSCédric Le Goater VFIODevice *vbasedev = region->vbasedev; 91*499e53ccSCédric Le Goater union { 92*499e53ccSCédric Le Goater uint8_t byte; 93*499e53ccSCédric Le Goater uint16_t word; 94*499e53ccSCédric Le Goater uint32_t dword; 95*499e53ccSCédric Le Goater uint64_t qword; 96*499e53ccSCédric Le Goater } buf; 97*499e53ccSCédric Le Goater uint64_t data = 0; 98*499e53ccSCédric Le Goater 99*499e53ccSCédric Le Goater if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { 100*499e53ccSCédric Le Goater error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", 101*499e53ccSCédric Le Goater __func__, vbasedev->name, region->nr, 102*499e53ccSCédric Le Goater addr, size); 103*499e53ccSCédric Le Goater return (uint64_t)-1; 104*499e53ccSCédric Le Goater } 105*499e53ccSCédric Le Goater switch (size) { 106*499e53ccSCédric Le Goater case 1: 107*499e53ccSCédric Le Goater data = buf.byte; 108*499e53ccSCédric Le Goater break; 109*499e53ccSCédric Le Goater case 2: 110*499e53ccSCédric Le Goater data = le16_to_cpu(buf.word); 111*499e53ccSCédric Le Goater break; 112*499e53ccSCédric Le Goater case 4: 113*499e53ccSCédric Le Goater data = le32_to_cpu(buf.dword); 114*499e53ccSCédric Le Goater break; 115*499e53ccSCédric Le Goater case 8: 116*499e53ccSCédric Le Goater data = le64_to_cpu(buf.qword); 117*499e53ccSCédric Le Goater break; 118*499e53ccSCédric Le Goater default: 119*499e53ccSCédric Le Goater hw_error("vfio: unsupported read size, %u bytes", size); 120*499e53ccSCédric Le Goater break; 121*499e53ccSCédric Le Goater } 122*499e53ccSCédric Le Goater 123*499e53ccSCédric Le Goater trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); 124*499e53ccSCédric Le Goater 125*499e53ccSCédric Le Goater /* Same as write above */ 126*499e53ccSCédric Le Goater vbasedev->ops->vfio_eoi(vbasedev); 127*499e53ccSCédric Le Goater 128*499e53ccSCédric Le Goater return data; 129*499e53ccSCédric Le Goater } 130*499e53ccSCédric Le Goater 131*499e53ccSCédric Le Goater static const MemoryRegionOps vfio_region_ops = { 132*499e53ccSCédric Le Goater .read = vfio_region_read, 133*499e53ccSCédric Le Goater .write = vfio_region_write, 134*499e53ccSCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 135*499e53ccSCédric Le Goater .valid = { 136*499e53ccSCédric Le Goater .min_access_size = 1, 137*499e53ccSCédric Le Goater .max_access_size = 8, 138*499e53ccSCédric Le Goater }, 139*499e53ccSCédric Le Goater .impl = { 140*499e53ccSCédric Le Goater .min_access_size = 1, 141*499e53ccSCédric Le Goater .max_access_size = 8, 142*499e53ccSCédric Le Goater }, 143*499e53ccSCédric Le Goater }; 144*499e53ccSCédric Le Goater 145*499e53ccSCédric Le Goater static int vfio_setup_region_sparse_mmaps(VFIORegion *region, 146*499e53ccSCédric Le Goater struct vfio_region_info *info) 147*499e53ccSCédric Le Goater { 148*499e53ccSCédric Le Goater struct vfio_info_cap_header *hdr; 149*499e53ccSCédric Le Goater struct vfio_region_info_cap_sparse_mmap *sparse; 150*499e53ccSCédric Le Goater int i, j; 151*499e53ccSCédric Le Goater 152*499e53ccSCédric Le Goater hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); 153*499e53ccSCédric Le Goater if (!hdr) { 154*499e53ccSCédric Le Goater return -ENODEV; 155*499e53ccSCédric Le Goater } 156*499e53ccSCédric Le Goater 157*499e53ccSCédric Le Goater sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); 158*499e53ccSCédric Le Goater 159*499e53ccSCédric Le Goater trace_vfio_region_sparse_mmap_header(region->vbasedev->name, 160*499e53ccSCédric Le Goater region->nr, sparse->nr_areas); 161*499e53ccSCédric Le Goater 162*499e53ccSCédric Le Goater region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); 163*499e53ccSCédric Le Goater 164*499e53ccSCédric Le Goater for (i = 0, j = 0; i < sparse->nr_areas; i++) { 165*499e53ccSCédric Le Goater if (sparse->areas[i].size) { 166*499e53ccSCédric Le Goater trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, 167*499e53ccSCédric Le Goater sparse->areas[i].offset + 168*499e53ccSCédric Le Goater sparse->areas[i].size - 1); 169*499e53ccSCédric Le Goater region->mmaps[j].offset = sparse->areas[i].offset; 170*499e53ccSCédric Le Goater region->mmaps[j].size = sparse->areas[i].size; 171*499e53ccSCédric Le Goater j++; 172*499e53ccSCédric Le Goater } 173*499e53ccSCédric Le Goater } 174*499e53ccSCédric Le Goater 175*499e53ccSCédric Le Goater region->nr_mmaps = j; 176*499e53ccSCédric Le Goater region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); 177*499e53ccSCédric Le Goater 178*499e53ccSCédric Le Goater return 0; 179*499e53ccSCédric Le Goater } 180*499e53ccSCédric Le Goater 181*499e53ccSCédric Le Goater int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, 182*499e53ccSCédric Le Goater int index, const char *name) 183*499e53ccSCédric Le Goater { 184*499e53ccSCédric Le Goater g_autofree struct vfio_region_info *info = NULL; 185*499e53ccSCédric Le Goater int ret; 186*499e53ccSCédric Le Goater 187*499e53ccSCédric Le Goater ret = vfio_get_region_info(vbasedev, index, &info); 188*499e53ccSCédric Le Goater if (ret) { 189*499e53ccSCédric Le Goater return ret; 190*499e53ccSCédric Le Goater } 191*499e53ccSCédric Le Goater 192*499e53ccSCédric Le Goater region->vbasedev = vbasedev; 193*499e53ccSCédric Le Goater region->flags = info->flags; 194*499e53ccSCédric Le Goater region->size = info->size; 195*499e53ccSCédric Le Goater region->fd_offset = info->offset; 196*499e53ccSCédric Le Goater region->nr = index; 197*499e53ccSCédric Le Goater 198*499e53ccSCédric Le Goater if (region->size) { 199*499e53ccSCédric Le Goater region->mem = g_new0(MemoryRegion, 1); 200*499e53ccSCédric Le Goater memory_region_init_io(region->mem, obj, &vfio_region_ops, 201*499e53ccSCédric Le Goater region, name, region->size); 202*499e53ccSCédric Le Goater 203*499e53ccSCédric Le Goater if (!vbasedev->no_mmap && 204*499e53ccSCédric Le Goater region->flags & VFIO_REGION_INFO_FLAG_MMAP) { 205*499e53ccSCédric Le Goater 206*499e53ccSCédric Le Goater ret = vfio_setup_region_sparse_mmaps(region, info); 207*499e53ccSCédric Le Goater 208*499e53ccSCédric Le Goater if (ret) { 209*499e53ccSCédric Le Goater region->nr_mmaps = 1; 210*499e53ccSCédric Le Goater region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); 211*499e53ccSCédric Le Goater region->mmaps[0].offset = 0; 212*499e53ccSCédric Le Goater region->mmaps[0].size = region->size; 213*499e53ccSCédric Le Goater } 214*499e53ccSCédric Le Goater } 215*499e53ccSCédric Le Goater } 216*499e53ccSCédric Le Goater 217*499e53ccSCédric Le Goater trace_vfio_region_setup(vbasedev->name, index, name, 218*499e53ccSCédric Le Goater region->flags, region->fd_offset, region->size); 219*499e53ccSCédric Le Goater return 0; 220*499e53ccSCédric Le Goater } 221*499e53ccSCédric Le Goater 222*499e53ccSCédric Le Goater static void vfio_subregion_unmap(VFIORegion *region, int index) 223*499e53ccSCédric Le Goater { 224*499e53ccSCédric Le Goater trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), 225*499e53ccSCédric Le Goater region->mmaps[index].offset, 226*499e53ccSCédric Le Goater region->mmaps[index].offset + 227*499e53ccSCédric Le Goater region->mmaps[index].size - 1); 228*499e53ccSCédric Le Goater memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); 229*499e53ccSCédric Le Goater munmap(region->mmaps[index].mmap, region->mmaps[index].size); 230*499e53ccSCédric Le Goater object_unparent(OBJECT(®ion->mmaps[index].mem)); 231*499e53ccSCédric Le Goater region->mmaps[index].mmap = NULL; 232*499e53ccSCédric Le Goater } 233*499e53ccSCédric Le Goater 234*499e53ccSCédric Le Goater int vfio_region_mmap(VFIORegion *region) 235*499e53ccSCédric Le Goater { 236*499e53ccSCédric Le Goater int i, ret, prot = 0; 237*499e53ccSCédric Le Goater char *name; 238*499e53ccSCédric Le Goater 239*499e53ccSCédric Le Goater if (!region->mem) { 240*499e53ccSCédric Le Goater return 0; 241*499e53ccSCédric Le Goater } 242*499e53ccSCédric Le Goater 243*499e53ccSCédric Le Goater prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; 244*499e53ccSCédric Le Goater prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; 245*499e53ccSCédric Le Goater 246*499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 247*499e53ccSCédric Le Goater size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB); 248*499e53ccSCédric Le Goater void *map_base, *map_align; 249*499e53ccSCédric Le Goater 250*499e53ccSCédric Le Goater /* 251*499e53ccSCédric Le Goater * Align the mmap for more efficient mapping in the kernel. Ideally 252*499e53ccSCédric Le Goater * we'd know the PMD and PUD mapping sizes to use as discrete alignment 253*499e53ccSCédric Le Goater * intervals, but we don't. As of Linux v6.12, the largest PUD size 254*499e53ccSCédric Le Goater * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set 255*499e53ccSCédric Le Goater * on x86_64). Align by power-of-two size, capped at 1GiB. 256*499e53ccSCédric Le Goater * 257*499e53ccSCédric Le Goater * NB. qemu_memalign() and friends actually allocate memory, whereas 258*499e53ccSCédric Le Goater * the region size here can exceed host memory, therefore we manually 259*499e53ccSCédric Le Goater * create an oversized anonymous mapping and clean it up for alignment. 260*499e53ccSCédric Le Goater */ 261*499e53ccSCédric Le Goater map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE, 262*499e53ccSCédric Le Goater MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 263*499e53ccSCédric Le Goater if (map_base == MAP_FAILED) { 264*499e53ccSCédric Le Goater ret = -errno; 265*499e53ccSCédric Le Goater goto no_mmap; 266*499e53ccSCédric Le Goater } 267*499e53ccSCédric Le Goater 268*499e53ccSCédric Le Goater map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align); 269*499e53ccSCédric Le Goater munmap(map_base, map_align - map_base); 270*499e53ccSCédric Le Goater munmap(map_align + region->mmaps[i].size, 271*499e53ccSCédric Le Goater align - (map_align - map_base)); 272*499e53ccSCédric Le Goater 273*499e53ccSCédric Le Goater region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot, 274*499e53ccSCédric Le Goater MAP_SHARED | MAP_FIXED, 275*499e53ccSCédric Le Goater region->vbasedev->fd, 276*499e53ccSCédric Le Goater region->fd_offset + 277*499e53ccSCédric Le Goater region->mmaps[i].offset); 278*499e53ccSCédric Le Goater if (region->mmaps[i].mmap == MAP_FAILED) { 279*499e53ccSCédric Le Goater ret = -errno; 280*499e53ccSCédric Le Goater goto no_mmap; 281*499e53ccSCédric Le Goater } 282*499e53ccSCédric Le Goater 283*499e53ccSCédric Le Goater name = g_strdup_printf("%s mmaps[%d]", 284*499e53ccSCédric Le Goater memory_region_name(region->mem), i); 285*499e53ccSCédric Le Goater memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, 286*499e53ccSCédric Le Goater memory_region_owner(region->mem), 287*499e53ccSCédric Le Goater name, region->mmaps[i].size, 288*499e53ccSCédric Le Goater region->mmaps[i].mmap); 289*499e53ccSCédric Le Goater g_free(name); 290*499e53ccSCédric Le Goater memory_region_add_subregion(region->mem, region->mmaps[i].offset, 291*499e53ccSCédric Le Goater ®ion->mmaps[i].mem); 292*499e53ccSCédric Le Goater 293*499e53ccSCédric Le Goater trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), 294*499e53ccSCédric Le Goater region->mmaps[i].offset, 295*499e53ccSCédric Le Goater region->mmaps[i].offset + 296*499e53ccSCédric Le Goater region->mmaps[i].size - 1); 297*499e53ccSCédric Le Goater } 298*499e53ccSCédric Le Goater 299*499e53ccSCédric Le Goater return 0; 300*499e53ccSCédric Le Goater 301*499e53ccSCédric Le Goater no_mmap: 302*499e53ccSCédric Le Goater trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, 303*499e53ccSCédric Le Goater region->fd_offset + region->mmaps[i].offset, 304*499e53ccSCédric Le Goater region->fd_offset + region->mmaps[i].offset + 305*499e53ccSCédric Le Goater region->mmaps[i].size - 1, ret); 306*499e53ccSCédric Le Goater 307*499e53ccSCédric Le Goater region->mmaps[i].mmap = NULL; 308*499e53ccSCédric Le Goater 309*499e53ccSCédric Le Goater for (i--; i >= 0; i--) { 310*499e53ccSCédric Le Goater vfio_subregion_unmap(region, i); 311*499e53ccSCédric Le Goater } 312*499e53ccSCédric Le Goater 313*499e53ccSCédric Le Goater return ret; 314*499e53ccSCédric Le Goater } 315*499e53ccSCédric Le Goater 316*499e53ccSCédric Le Goater void vfio_region_unmap(VFIORegion *region) 317*499e53ccSCédric Le Goater { 318*499e53ccSCédric Le Goater int i; 319*499e53ccSCédric Le Goater 320*499e53ccSCédric Le Goater if (!region->mem) { 321*499e53ccSCédric Le Goater return; 322*499e53ccSCédric Le Goater } 323*499e53ccSCédric Le Goater 324*499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 325*499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 326*499e53ccSCédric Le Goater vfio_subregion_unmap(region, i); 327*499e53ccSCédric Le Goater } 328*499e53ccSCédric Le Goater } 329*499e53ccSCédric Le Goater } 330*499e53ccSCédric Le Goater 331*499e53ccSCédric Le Goater void vfio_region_exit(VFIORegion *region) 332*499e53ccSCédric Le Goater { 333*499e53ccSCédric Le Goater int i; 334*499e53ccSCédric Le Goater 335*499e53ccSCédric Le Goater if (!region->mem) { 336*499e53ccSCédric Le Goater return; 337*499e53ccSCédric Le Goater } 338*499e53ccSCédric Le Goater 339*499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 340*499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 341*499e53ccSCédric Le Goater memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); 342*499e53ccSCédric Le Goater } 343*499e53ccSCédric Le Goater } 344*499e53ccSCédric Le Goater 345*499e53ccSCédric Le Goater trace_vfio_region_exit(region->vbasedev->name, region->nr); 346*499e53ccSCédric Le Goater } 347*499e53ccSCédric Le Goater 348*499e53ccSCédric Le Goater void vfio_region_finalize(VFIORegion *region) 349*499e53ccSCédric Le Goater { 350*499e53ccSCédric Le Goater int i; 351*499e53ccSCédric Le Goater 352*499e53ccSCédric Le Goater if (!region->mem) { 353*499e53ccSCédric Le Goater return; 354*499e53ccSCédric Le Goater } 355*499e53ccSCédric Le Goater 356*499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 357*499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 358*499e53ccSCédric Le Goater munmap(region->mmaps[i].mmap, region->mmaps[i].size); 359*499e53ccSCédric Le Goater object_unparent(OBJECT(®ion->mmaps[i].mem)); 360*499e53ccSCédric Le Goater } 361*499e53ccSCédric Le Goater } 362*499e53ccSCédric Le Goater 363*499e53ccSCédric Le Goater object_unparent(OBJECT(region->mem)); 364*499e53ccSCédric Le Goater 365*499e53ccSCédric Le Goater g_free(region->mem); 366*499e53ccSCédric Le Goater g_free(region->mmaps); 367*499e53ccSCédric Le Goater 368*499e53ccSCédric Le Goater trace_vfio_region_finalize(region->vbasedev->name, region->nr); 369*499e53ccSCédric Le Goater 370*499e53ccSCédric Le Goater region->mem = NULL; 371*499e53ccSCédric Le Goater region->mmaps = NULL; 372*499e53ccSCédric Le Goater region->nr_mmaps = 0; 373*499e53ccSCédric Le Goater region->size = 0; 374*499e53ccSCédric Le Goater region->flags = 0; 375*499e53ccSCédric Le Goater region->nr = 0; 376*499e53ccSCédric Le Goater } 377*499e53ccSCédric Le Goater 378*499e53ccSCédric Le Goater void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) 379*499e53ccSCédric Le Goater { 380*499e53ccSCédric Le Goater int i; 381*499e53ccSCédric Le Goater 382*499e53ccSCédric Le Goater if (!region->mem) { 383*499e53ccSCédric Le Goater return; 384*499e53ccSCédric Le Goater } 385*499e53ccSCédric Le Goater 386*499e53ccSCédric Le Goater for (i = 0; i < region->nr_mmaps; i++) { 387*499e53ccSCédric Le Goater if (region->mmaps[i].mmap) { 388*499e53ccSCédric Le Goater memory_region_set_enabled(®ion->mmaps[i].mem, enabled); 389*499e53ccSCédric Le Goater } 390*499e53ccSCédric Le Goater } 391*499e53ccSCédric Le Goater 392*499e53ccSCédric Le Goater trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), 393*499e53ccSCédric Le Goater enabled); 394*499e53ccSCédric Le Goater } 395