xref: /qemu/hw/vfio/region.c (revision 499e53cce9445d23ee1bf54562de558562fc8d22)
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(&region->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, &region->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(&region->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(&region->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                                     &region->mmaps[i].mem);
292*499e53ccSCédric Le Goater 
293*499e53ccSCédric Le Goater         trace_vfio_region_mmap(memory_region_name(&region->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, &region->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(&region->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(&region->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