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" 1254857b08SSteve Sistare #include "migration/blocker.h" 1354857b08SSteve Sistare #include "migration/cpr.h" 1454857b08SSteve Sistare #include "migration/migration.h" 1554857b08SSteve Sistare #include "migration/vmstate.h" 1654857b08SSteve Sistare #include "qapi/error.h" 1754857b08SSteve Sistare 18*1faadd96SSteve Sistare static bool vfio_dma_unmap_vaddr_all(VFIOContainer *container, Error **errp) 19*1faadd96SSteve Sistare { 20*1faadd96SSteve Sistare struct vfio_iommu_type1_dma_unmap unmap = { 21*1faadd96SSteve Sistare .argsz = sizeof(unmap), 22*1faadd96SSteve Sistare .flags = VFIO_DMA_UNMAP_FLAG_VADDR | VFIO_DMA_UNMAP_FLAG_ALL, 23*1faadd96SSteve Sistare .iova = 0, 24*1faadd96SSteve Sistare .size = 0, 25*1faadd96SSteve Sistare }; 26*1faadd96SSteve Sistare if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { 27*1faadd96SSteve Sistare error_setg_errno(errp, errno, "vfio_dma_unmap_vaddr_all"); 28*1faadd96SSteve Sistare return false; 29*1faadd96SSteve Sistare } 30*1faadd96SSteve Sistare return true; 31*1faadd96SSteve Sistare } 32*1faadd96SSteve Sistare 33*1faadd96SSteve Sistare 3454857b08SSteve Sistare static bool vfio_cpr_supported(VFIOContainer *container, Error **errp) 3554857b08SSteve Sistare { 3654857b08SSteve Sistare if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UPDATE_VADDR)) { 3754857b08SSteve Sistare error_setg(errp, "VFIO container does not support VFIO_UPDATE_VADDR"); 3854857b08SSteve Sistare return false; 3954857b08SSteve Sistare 4054857b08SSteve Sistare } else if (!ioctl(container->fd, VFIO_CHECK_EXTENSION, VFIO_UNMAP_ALL)) { 4154857b08SSteve Sistare error_setg(errp, "VFIO container does not support VFIO_UNMAP_ALL"); 4254857b08SSteve Sistare return false; 4354857b08SSteve Sistare 4454857b08SSteve Sistare } else { 4554857b08SSteve Sistare return true; 4654857b08SSteve Sistare } 4754857b08SSteve Sistare } 4854857b08SSteve Sistare 49*1faadd96SSteve Sistare static int vfio_container_pre_save(void *opaque) 50*1faadd96SSteve Sistare { 51*1faadd96SSteve Sistare VFIOContainer *container = opaque; 52*1faadd96SSteve Sistare Error *local_err = NULL; 53*1faadd96SSteve Sistare 54*1faadd96SSteve Sistare if (!vfio_dma_unmap_vaddr_all(container, &local_err)) { 55*1faadd96SSteve Sistare error_report_err(local_err); 56*1faadd96SSteve Sistare return -1; 57*1faadd96SSteve Sistare } 58*1faadd96SSteve Sistare return 0; 59*1faadd96SSteve Sistare } 60*1faadd96SSteve Sistare 6154857b08SSteve Sistare static const VMStateDescription vfio_container_vmstate = { 6254857b08SSteve Sistare .name = "vfio-container", 6354857b08SSteve Sistare .version_id = 0, 6454857b08SSteve Sistare .minimum_version_id = 0, 65*1faadd96SSteve Sistare .pre_save = vfio_container_pre_save, 6654857b08SSteve Sistare .needed = cpr_incoming_needed, 6754857b08SSteve Sistare .fields = (VMStateField[]) { 6854857b08SSteve Sistare VMSTATE_END_OF_LIST() 6954857b08SSteve Sistare } 7054857b08SSteve Sistare }; 7154857b08SSteve Sistare 7254857b08SSteve Sistare bool vfio_legacy_cpr_register_container(VFIOContainer *container, Error **errp) 7354857b08SSteve Sistare { 7454857b08SSteve Sistare VFIOContainerBase *bcontainer = &container->bcontainer; 7554857b08SSteve Sistare Error **cpr_blocker = &container->cpr.blocker; 7654857b08SSteve Sistare 7754857b08SSteve Sistare migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier, 7854857b08SSteve Sistare vfio_cpr_reboot_notifier, 7954857b08SSteve Sistare MIG_MODE_CPR_REBOOT); 8054857b08SSteve Sistare 8154857b08SSteve Sistare if (!vfio_cpr_supported(container, cpr_blocker)) { 8254857b08SSteve Sistare return migrate_add_blocker_modes(cpr_blocker, errp, 8354857b08SSteve Sistare MIG_MODE_CPR_TRANSFER, -1) == 0; 8454857b08SSteve Sistare } 8554857b08SSteve Sistare 8654857b08SSteve Sistare vmstate_register(NULL, -1, &vfio_container_vmstate, container); 8754857b08SSteve Sistare 8854857b08SSteve Sistare return true; 8954857b08SSteve Sistare } 9054857b08SSteve Sistare 9154857b08SSteve Sistare void vfio_legacy_cpr_unregister_container(VFIOContainer *container) 9254857b08SSteve Sistare { 9354857b08SSteve Sistare VFIOContainerBase *bcontainer = &container->bcontainer; 9454857b08SSteve Sistare 9554857b08SSteve Sistare migration_remove_notifier(&bcontainer->cpr_reboot_notifier); 9654857b08SSteve Sistare migrate_del_blocker(&container->cpr.blocker); 9754857b08SSteve Sistare vmstate_unregister(NULL, &vfio_container_vmstate, container); 9854857b08SSteve Sistare } 99c29a65edSSteve Sistare 100c29a65edSSteve Sistare int vfio_cpr_group_get_device_fd(int d, const char *name) 101c29a65edSSteve Sistare { 102c29a65edSSteve Sistare const int id = 0; 103c29a65edSSteve Sistare int fd = cpr_find_fd(name, id); 104c29a65edSSteve Sistare 105c29a65edSSteve Sistare if (fd < 0) { 106c29a65edSSteve Sistare fd = ioctl(d, VFIO_GROUP_GET_DEVICE_FD, name); 107c29a65edSSteve Sistare if (fd >= 0) { 108c29a65edSSteve Sistare cpr_save_fd(name, id, fd); 109c29a65edSSteve Sistare } 110c29a65edSSteve Sistare } 111c29a65edSSteve Sistare return fd; 112c29a65edSSteve Sistare } 113c29a65edSSteve Sistare 114c29a65edSSteve Sistare static bool same_device(int fd1, int fd2) 115c29a65edSSteve Sistare { 116c29a65edSSteve Sistare struct stat st1, st2; 117c29a65edSSteve Sistare 118c29a65edSSteve Sistare return !fstat(fd1, &st1) && !fstat(fd2, &st2) && st1.st_dev == st2.st_dev; 119c29a65edSSteve Sistare } 120c29a65edSSteve Sistare 121c29a65edSSteve Sistare bool vfio_cpr_container_match(VFIOContainer *container, VFIOGroup *group, 122c29a65edSSteve Sistare int fd) 123c29a65edSSteve Sistare { 124c29a65edSSteve Sistare if (container->fd == fd) { 125c29a65edSSteve Sistare return true; 126c29a65edSSteve Sistare } 127c29a65edSSteve Sistare if (!same_device(container->fd, fd)) { 128c29a65edSSteve Sistare return false; 129c29a65edSSteve Sistare } 130c29a65edSSteve Sistare /* 131c29a65edSSteve Sistare * Same device, different fd. This occurs when the container fd is 132c29a65edSSteve Sistare * cpr_save'd multiple times, once for each groupid, so SCM_RIGHTS 133c29a65edSSteve Sistare * produces duplicates. De-dup it. 134c29a65edSSteve Sistare */ 135c29a65edSSteve Sistare cpr_delete_fd("vfio_container_for_group", group->groupid); 136c29a65edSSteve Sistare close(fd); 137c29a65edSSteve Sistare cpr_save_fd("vfio_container_for_group", group->groupid, container->fd); 138c29a65edSSteve Sistare return true; 139c29a65edSSteve Sistare } 140