xref: /qemu/hw/vfio/cpr-legacy.c (revision 7e9f21411302d823e9ee563ff6a2a40b1ffc1266)
154857b08SSteve Sistare /*
254857b08SSteve Sistare  * Copyright (c) 2021-2025 Oracle and/or its affiliates.
354857b08SSteve Sistare  *
454857b08SSteve Sistare  * SPDX-License-Identifier: GPL-2.0-or-later
554857b08SSteve Sistare  */
654857b08SSteve Sistare 
754857b08SSteve Sistare #include <sys/ioctl.h>
854857b08SSteve Sistare #include <linux/vfio.h>
954857b08SSteve Sistare #include "qemu/osdep.h"
1054857b08SSteve Sistare #include "hw/vfio/vfio-container.h"
11c29a65edSSteve Sistare #include "hw/vfio/vfio-device.h"
12*7e9f2141SSteve Sistare #include "hw/vfio/vfio-listener.h"
1354857b08SSteve Sistare #include "migration/blocker.h"
1454857b08SSteve Sistare #include "migration/cpr.h"
1554857b08SSteve Sistare #include "migration/migration.h"
1654857b08SSteve Sistare #include "migration/vmstate.h"
1754857b08SSteve Sistare #include "qapi/error.h"
18*7e9f2141SSteve Sistare #include "qemu/error-report.h"
1954857b08SSteve Sistare 
201faadd96SSteve Sistare static bool vfio_dma_unmap_vaddr_all(VFIOContainer *container, Error **errp)
211faadd96SSteve Sistare {
221faadd96SSteve Sistare     struct vfio_iommu_type1_dma_unmap unmap = {
231faadd96SSteve Sistare         .argsz = sizeof(unmap),
241faadd96SSteve Sistare         .flags = VFIO_DMA_UNMAP_FLAG_VADDR | VFIO_DMA_UNMAP_FLAG_ALL,
251faadd96SSteve Sistare         .iova = 0,
261faadd96SSteve Sistare         .size = 0,
271faadd96SSteve Sistare     };
281faadd96SSteve Sistare     if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
291faadd96SSteve Sistare         error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all");
301faadd96SSteve Sistare         return false;
311faadd96SSteve Sistare     }
321faadd96SSteve Sistare     return true;
331faadd96SSteve Sistare }
341faadd96SSteve Sistare 
35*7e9f2141SSteve Sistare /*
36*7e9f2141SSteve Sistare  * Set the new @vaddr for any mappings registered during cpr load.
37*7e9f2141SSteve Sistare  * The incoming state is cleared thereafter.
38*7e9f2141SSteve Sistare  */
39*7e9f2141SSteve Sistare static int vfio_legacy_cpr_dma_map(const VFIOContainerBase *bcontainer,
40*7e9f2141SSteve Sistare                                    hwaddr iova, ram_addr_t size, void *vaddr,
41*7e9f2141SSteve Sistare                                    bool readonly, MemoryRegion *mr)
42*7e9f2141SSteve Sistare {
43*7e9f2141SSteve Sistare     const VFIOContainer *container = container_of(bcontainer, VFIOContainer,
44*7e9f2141SSteve Sistare                                                   bcontainer);
45*7e9f2141SSteve Sistare     struct vfio_iommu_type1_dma_map map = {
46*7e9f2141SSteve Sistare         .argsz = sizeof(map),
47*7e9f2141SSteve Sistare         .flags = VFIO_DMA_MAP_FLAG_VADDR,
48*7e9f2141SSteve Sistare         .vaddr = (__u64)(uintptr_t)vaddr,
49*7e9f2141SSteve Sistare         .iova = iova,
50*7e9f2141SSteve Sistare         .size = size,
51*7e9f2141SSteve Sistare     };
52*7e9f2141SSteve Sistare 
53*7e9f2141SSteve Sistare     g_assert(cpr_is_incoming());
54*7e9f2141SSteve Sistare 
55*7e9f2141SSteve Sistare     if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map)) {
56*7e9f2141SSteve Sistare         return -errno;
57*7e9f2141SSteve Sistare     }
58*7e9f2141SSteve Sistare 
59*7e9f2141SSteve Sistare     return 0;
60*7e9f2141SSteve Sistare }
611faadd96SSteve Sistare 
6254857b08SSteve Sistare static bool vfio_cpr_supported(VFIOContainer *container, Error **errp)
6354857b08SSteve Sistare {
6454857b08SSteve Sistare     if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) {
6554857b08SSteve Sistare         error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR");
6654857b08SSteve Sistare         return false;
6754857b08SSteve Sistare 
6854857b08SSteve Sistare     } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) {
6954857b08SSteve Sistare         error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL");
7054857b08SSteve Sistare         return false;
7154857b08SSteve Sistare 
7254857b08SSteve Sistare     } else {
7354857b08SSteve Sistare         return true;
7454857b08SSteve Sistare     }
7554857b08SSteve Sistare }
7654857b08SSteve Sistare 
771faadd96SSteve Sistare static int vfio_container_pre_save(void *opaque)
781faadd96SSteve Sistare {
791faadd96SSteve Sistare     VFIOContainer *container = opaque;
801faadd96SSteve Sistare     Error *local_err = NULL;
811faadd96SSteve Sistare 
821faadd96SSteve Sistare     if (!vfio_dma_unmap_vaddr_all(container, &local_err)) {
831faadd96SSteve Sistare         error_report_err(local_err);
841faadd96SSteve Sistare         return -1;
851faadd96SSteve Sistare     }
861faadd96SSteve Sistare     return 0;
871faadd96SSteve Sistare }
881faadd96SSteve Sistare 
89*7e9f2141SSteve Sistare static int vfio_container_post_load(void *opaque, int version_id)
90*7e9f2141SSteve Sistare {
91*7e9f2141SSteve Sistare     VFIOContainer *container = opaque;
92*7e9f2141SSteve Sistare     VFIOContainerBase *bcontainer = &container->bcontainer;
93*7e9f2141SSteve Sistare     VFIOGroup *group;
94*7e9f2141SSteve Sistare     Error *local_err = NULL;
95*7e9f2141SSteve Sistare 
96*7e9f2141SSteve Sistare     if (!vfio_listener_register(bcontainer, &local_err)) {
97*7e9f2141SSteve Sistare         error_report_err(local_err);
98*7e9f2141SSteve Sistare         return -1;
99*7e9f2141SSteve Sistare     }
100*7e9f2141SSteve Sistare 
101*7e9f2141SSteve Sistare     QLIST_FOREACH(group, &container->group_list, container_next) {
102*7e9f2141SSteve Sistare         VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
103*7e9f2141SSteve Sistare 
104*7e9f2141SSteve Sistare         /* Restore original dma_map function */
105*7e9f2141SSteve Sistare         vioc->dma_map = container->cpr.saved_dma_map;
106*7e9f2141SSteve Sistare     }
107*7e9f2141SSteve Sistare     return 0;
108*7e9f2141SSteve Sistare }
109*7e9f2141SSteve Sistare 
11054857b08SSteve Sistare static const VMStateDescription vfio_container_vmstate = {
11154857b08SSteve Sistare     .name = "vfio-container",
11254857b08SSteve Sistare     .version_id = 0,
11354857b08SSteve Sistare     .minimum_version_id = 0,
114*7e9f2141SSteve Sistare     .priority = MIG_PRI_LOW,  /* Must happen after devices and groups */
1151faadd96SSteve Sistare     .pre_save = vfio_container_pre_save,
116*7e9f2141SSteve Sistare     .post_load = vfio_container_post_load,
11754857b08SSteve Sistare     .needed = cpr_incoming_needed,
11854857b08SSteve Sistare     .fields = (VMStateField[]) {
11954857b08SSteve Sistare         VMSTATE_END_OF_LIST()
12054857b08SSteve Sistare     }
12154857b08SSteve Sistare };
12254857b08SSteve Sistare 
12354857b08SSteve Sistare bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp)
12454857b08SSteve Sistare {
12554857b08SSteve Sistare     VFIOContainerBase *bcontainer = &container->bcontainer;
12654857b08SSteve Sistare     Error **cpr_blocker = &container->cpr.blocker;
12754857b08SSteve Sistare 
12854857b08SSteve Sistare     migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier,
12954857b08SSteve Sistare                                 vfio_cpr_reboot_notifier,
13054857b08SSteve Sistare                                 MIG_MODE_CPR_REBOOT);
13154857b08SSteve Sistare 
13254857b08SSteve Sistare     if (!vfio_cpr_supported(container, cpr_blocker)) {
13354857b08SSteve Sistare         return migrate_add_blocker_modes(cpr_blocker, errp,
13454857b08SSteve Sistare                                          MIG_MODE_CPR_TRANSFER, -1) == 0;
13554857b08SSteve Sistare     }
13654857b08SSteve Sistare 
13754857b08SSteve Sistare     vmstate_register(NULL, -1, &vfio_container_vmstate, container);
13854857b08SSteve Sistare 
139*7e9f2141SSteve Sistare     /* During incoming CPR, divert calls to dma_map. */
140*7e9f2141SSteve Sistare     if (cpr_is_incoming()) {
141*7e9f2141SSteve Sistare         VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
142*7e9f2141SSteve Sistare         container->cpr.saved_dma_map = vioc->dma_map;
143*7e9f2141SSteve Sistare         vioc->dma_map = vfio_legacy_cpr_dma_map;
144*7e9f2141SSteve Sistare     }
14554857b08SSteve Sistare     return true;
14654857b08SSteve Sistare }
14754857b08SSteve Sistare 
14854857b08SSteve Sistare void vfio_legacy_cpr_unregister_container(VFIOContainer *container)
14954857b08SSteve Sistare {
15054857b08SSteve Sistare     VFIOContainerBase *bcontainer = &container->bcontainer;
15154857b08SSteve Sistare 
15254857b08SSteve Sistare     migration_remove_notifier(&bcontainer->cpr_reboot_notifier);
15354857b08SSteve Sistare     migrate_del_blocker(&container->cpr.blocker);
15454857b08SSteve Sistare     vmstate_unregister(NULL, &vfio_container_vmstate, container);
15554857b08SSteve Sistare }
156c29a65edSSteve Sistare 
157c29a65edSSteve Sistare int vfio_cpr_group_get_device_fd(int d, const char *name)
158c29a65edSSteve Sistare {
159c29a65edSSteve Sistare     const int id = 0;
160c29a65edSSteve Sistare     int fd = cpr_find_fd(name, id);
161c29a65edSSteve Sistare 
162c29a65edSSteve Sistare     if (fd < 0) {
163c29a65edSSteve Sistare         fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name);
164c29a65edSSteve Sistare         if (fd >= 0) {
165c29a65edSSteve Sistare             cpr_save_fd(name, id, fd);
166c29a65edSSteve Sistare         }
167c29a65edSSteve Sistare     }
168c29a65edSSteve Sistare     return fd;
169c29a65edSSteve Sistare }
170c29a65edSSteve Sistare 
171c29a65edSSteve Sistare static bool same_device(int fd1, int fd2)
172c29a65edSSteve Sistare {
173c29a65edSSteve Sistare     struct stat st1, st2;
174c29a65edSSteve Sistare 
175c29a65edSSteve Sistare     return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev;
176c29a65edSSteve Sistare }
177c29a65edSSteve Sistare 
178c29a65edSSteve Sistare bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group,
179c29a65edSSteve Sistare                               int fd)
180c29a65edSSteve Sistare {
181c29a65edSSteve Sistare     if (container->fd == fd) {
182c29a65edSSteve Sistare         return true;
183c29a65edSSteve Sistare     }
184c29a65edSSteve Sistare     if (!same_device(container->fd, fd)) {
185c29a65edSSteve Sistare         return false;
186c29a65edSSteve Sistare     }
187c29a65edSSteve Sistare     /*
188c29a65edSSteve Sistare      * Same device, different fd.  This occurs when the container fd is
189c29a65edSSteve Sistare      * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS
190c29a65edSSteve Sistare      * produces duplicates.  De-dup it.
191c29a65edSSteve Sistare      */
192c29a65edSSteve Sistare     cpr_delete_fd("vfio_container_for_group", group->groupid);
193c29a65edSSteve Sistare     close(fd);
194c29a65edSSteve Sistare     cpr_save_fd("vfio_container_for_group", group->groupid, container->fd);
195c29a65edSSteve Sistare     return true;
196c29a65edSSteve Sistare }
197