1 /* 2 * Copyright (c) 2021-2025 Oracle and/or its affiliates. 3 * 4 * SPDX-License-Identifier: GPL-2.0-or-later 5 */ 6 7 #include <sys/ioctl.h> 8 #include <linux/vfio.h> 9 #include "qemu/osdep.h" 10 #include "hw/vfio/vfio-container.h" 11 #include "hw/vfio/vfio-device.h" 12 #include "hw/vfio/vfio-listener.h" 13 #include "migration/blocker.h" 14 #include "migration/cpr.h" 15 #include "migration/migration.h" 16 #include "migration/vmstate.h" 17 #include "qapi/error.h" 18 #include "qemu/error-report.h" 19 20 static bool vfio_dma_unmap_vaddr_all(VFIOContainer *container, Error **errp) 21 { 22 struct vfio_iommu_type1_dma_unmap unmap = { 23 .argsz = sizeof(unmap), 24 .flags = VFIO_DMA_UNMAP_FLAG_VADDR | VFIO_DMA_UNMAP_FLAG_ALL, 25 .iova = 0, 26 .size = 0, 27 }; 28 if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { 29 error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all"); 30 return false; 31 } 32 return true; 33 } 34 35 /* 36 * Set the new @vaddr for any mappings registered during cpr load. 37 * The incoming state is cleared thereafter. 38 */ 39 static int vfio_legacy_cpr_dma_map(const VFIOContainerBase *bcontainer, 40 hwaddr iova, ram_addr_t size, void *vaddr, 41 bool readonly, MemoryRegion *mr) 42 { 43 const VFIOContainer *container = container_of(bcontainer, VFIOContainer, 44 bcontainer); 45 struct vfio_iommu_type1_dma_map map = { 46 .argsz = sizeof(map), 47 .flags = VFIO_DMA_MAP_FLAG_VADDR, 48 .vaddr = (__u64)(uintptr_t)vaddr, 49 .iova = iova, 50 .size = size, 51 }; 52 53 g_assert(cpr_is_incoming()); 54 55 if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map)) { 56 return -errno; 57 } 58 59 return 0; 60 } 61 62 static bool vfio_cpr_supported(VFIOContainer *container, Error **errp) 63 { 64 if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) { 65 error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR"); 66 return false; 67 68 } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) { 69 error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL"); 70 return false; 71 72 } else { 73 return true; 74 } 75 } 76 77 static int vfio_container_pre_save(void *opaque) 78 { 79 VFIOContainer *container = opaque; 80 Error *local_err = NULL; 81 82 if (!vfio_dma_unmap_vaddr_all(container, &local_err)) { 83 error_report_err(local_err); 84 return -1; 85 } 86 return 0; 87 } 88 89 static int vfio_container_post_load(void *opaque, int version_id) 90 { 91 VFIOContainer *container = opaque; 92 VFIOContainerBase *bcontainer = &container->bcontainer; 93 VFIOGroup *group; 94 Error *local_err = NULL; 95 96 if (!vfio_listener_register(bcontainer, &local_err)) { 97 error_report_err(local_err); 98 return -1; 99 } 100 101 QLIST_FOREACH(group, &container->group_list, container_next) { 102 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 103 104 /* Restore original dma_map function */ 105 vioc->dma_map = container->cpr.saved_dma_map; 106 } 107 return 0; 108 } 109 110 static const VMStateDescription vfio_container_vmstate = { 111 .name = "vfio-container", 112 .version_id = 0, 113 .minimum_version_id = 0, 114 .priority = MIG_PRI_LOW, /* Must happen after devices and groups */ 115 .pre_save = vfio_container_pre_save, 116 .post_load = vfio_container_post_load, 117 .needed = cpr_incoming_needed, 118 .fields = (VMStateField[]) { 119 VMSTATE_END_OF_LIST() 120 } 121 }; 122 123 bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp) 124 { 125 VFIOContainerBase *bcontainer = &container->bcontainer; 126 Error **cpr_blocker = &container->cpr.blocker; 127 128 migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier, 129 vfio_cpr_reboot_notifier, 130 MIG_MODE_CPR_REBOOT); 131 132 if (!vfio_cpr_supported(container, cpr_blocker)) { 133 return migrate_add_blocker_modes(cpr_blocker, errp, 134 MIG_MODE_CPR_TRANSFER, -1) == 0; 135 } 136 137 vmstate_register(NULL, -1, &vfio_container_vmstate, container); 138 139 /* During incoming CPR, divert calls to dma_map. */ 140 if (cpr_is_incoming()) { 141 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 142 container->cpr.saved_dma_map = vioc->dma_map; 143 vioc->dma_map = vfio_legacy_cpr_dma_map; 144 } 145 return true; 146 } 147 148 void vfio_legacy_cpr_unregister_container(VFIOContainer *container) 149 { 150 VFIOContainerBase *bcontainer = &container->bcontainer; 151 152 migration_remove_notifier(&bcontainer->cpr_reboot_notifier); 153 migrate_del_blocker(&container->cpr.blocker); 154 vmstate_unregister(NULL, &vfio_container_vmstate, container); 155 } 156 157 int vfio_cpr_group_get_device_fd(int d, const char *name) 158 { 159 const int id = 0; 160 int fd = cpr_find_fd(name, id); 161 162 if (fd < 0) { 163 fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name); 164 if (fd >= 0) { 165 cpr_save_fd(name, id, fd); 166 } 167 } 168 return fd; 169 } 170 171 static bool same_device(int fd1, int fd2) 172 { 173 struct stat st1, st2; 174 175 return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev; 176 } 177 178 bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group, 179 int fd) 180 { 181 if (container->fd == fd) { 182 return true; 183 } 184 if (!same_device(container->fd, fd)) { 185 return false; 186 } 187 /* 188 * Same device, different fd. This occurs when the container fd is 189 * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS 190 * produces duplicates. De-dup it. 191 */ 192 cpr_delete_fd("vfio_container_for_group", group->groupid); 193 close(fd); 194 cpr_save_fd("vfio_container_for_group", group->groupid, container->fd); 195 return true; 196 } 197