summary refs log tree commit diff stats
path: root/backends/iommufd.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-07-04 08:58:39 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2025-07-04 08:58:39 -0400
commit563ac3d18129a2770a285cc16c20ad50c8adc7c0 (patch)
tree7de8446bf1540d5a09ee51408cb5298097f56293 /backends/iommufd.c
parenta876b05d38c813501e60fb50c8a45b30a965e902 (diff)
parent7437caad2052d920452ff7b9b7bc84f5e8e55c90 (diff)
downloadfocaccia-qemu-563ac3d18129a2770a285cc16c20ad50c8adc7c0.tar.gz
focaccia-qemu-563ac3d18129a2770a285cc16c20ad50c8adc7c0.zip
Merge tag 'pull-vfio-20250704' of https://github.com/legoater/qemu into staging
vfio queue:

* Added small cleanups for b4 and scope
* Restricted TDX build to 64-bit target
* Fixed issues introduced in first part of VFIO live update support
* Added full VFIO live update support

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmhnlBMACgkQUaNDx8/7
# 7KFOxw//dIPpGcYIjEGpIkIh6NF3VK6xmDAG0aZEeM+5fCzdor2DPkD7ZPyqND3S
# /YkR8GSOHd+Qm5W+73LHOdV5RFMt4wagyHiAKUMpEFHY7ZLduxIXlACoUo+F5cnh
# SUnhC6KX7Gu1/Nndb4X4w6SNOyhoRKtQ2EqpRsrGdIaBkX8s6w2jF/INPTPdpg73
# lulJZCAFNzyIWytck9ohJf8To9IsvkCXTF6mcywURa9MBaAarRttXoFjuZsXb7zn
# NqGVtantNAaJmKu26X3ScUWn9P02WryhPB6KT7+B3G/b87Su1cnbAwYakNSFPJIx
# I/gaw0EPzHM+b6mavA4IdvKDJGR7GMvpJEGqUEpntc6FJ3+g1B7qsedgeBUc/RKB
# UaRmtYbvlMv5wSmaLcxsT3S3BnABbrd4EedZX5uOBFMrtnTiOqrMUEcoMaf5ogvN
# KlJkrjNQkfHxTbp5G+nXHuTzae3k2Ylm196b2yhgARfUL70jiak/B+ADeezVcVmW
# 6ZpotrAvMxu9RlFdxTSbL0/lR0rfKZTecqMOSFA+FlmjcTJ0QW1SbweMdsfgW/uU
# /2Hfmw6zUQ80/tMqYMztFWsiov7C8a8ZMmuZwDQp+AdCVGgFEigfNJVQYgujbqKz
# g9Ta9cNPyvF5hpnml5u8IzAzM95HrhIPFmmpUBZyWOCeL6chSHk=
# =Cu7b
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 04 Jul 2025 04:42:59 EDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [full]
# gpg:                 aka "Cédric Le Goater <clg@kaod.org>" [full]
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-vfio-20250704' of https://github.com/legoater/qemu: (27 commits)
  vfio: doc changes for cpr
  vfio/container: delete old cpr register
  iommufd: preserve DMA mappings
  vfio/iommufd: change process
  vfio/iommufd: reconstruct hwpt
  vfio/iommufd: reconstruct device
  vfio/iommufd: preserve descriptors
  vfio/iommufd: cpr state
  migration: vfio cpr state hook
  vfio/iommufd: register container for cpr
  vfio/iommufd: device name blocker
  vfio/iommufd: add vfio_device_free_name
  vfio/iommufd: invariant device name
  vfio/iommufd: use IOMMU_IOAS_MAP_FILE
  physmem: qemu_ram_get_fd_offset
  backends/iommufd: change process ioctl
  backends/iommufd: iommufd_backend_map_file_dma
  migration: cpr_get_fd_param helper
  migration: close kvm after cpr
  vfio-pci: preserve INTx
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'backends/iommufd.c')
-rw-r--r--backends/iommufd.c107
1 files changed, 103 insertions, 4 deletions
diff --git a/backends/iommufd.c b/backends/iommufd.c
index c2c47abf7e..2a33c7ab0b 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -16,12 +16,18 @@
 #include "qemu/module.h"
 #include "qom/object_interfaces.h"
 #include "qemu/error-report.h"
+#include "migration/cpr.h"
 #include "monitor/monitor.h"
 #include "trace.h"
 #include "hw/vfio/vfio-device.h"
 #include <sys/ioctl.h>
 #include <linux/iommufd.h>
 
+static const char *iommufd_fd_name(IOMMUFDBackend *be)
+{
+    return object_get_canonical_path_component(OBJECT(be));
+}
+
 static void iommufd_backend_init(Object *obj)
 {
     IOMMUFDBackend *be = IOMMUFD_BACKEND(obj);
@@ -64,26 +70,73 @@ static bool iommufd_backend_can_be_deleted(UserCreatable *uc)
     return !be->users;
 }
 
+static void iommufd_backend_complete(UserCreatable *uc, Error **errp)
+{
+    IOMMUFDBackend *be = IOMMUFD_BACKEND(uc);
+    const char *name = iommufd_fd_name(be);
+
+    if (!be->owned) {
+        /* fd came from the command line. Fetch updated value from cpr state. */
+        if (cpr_is_incoming()) {
+            be->fd = cpr_find_fd(name, 0);
+        } else {
+            cpr_save_fd(name, 0, be->fd);
+        }
+    }
+}
+
 static void iommufd_backend_class_init(ObjectClass *oc, const void *data)
 {
     UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 
     ucc->can_be_deleted = iommufd_backend_can_be_deleted;
+    ucc->complete = iommufd_backend_complete;
 
     object_class_property_add_str(oc, "fd", NULL, iommufd_backend_set_fd);
 }
 
+bool iommufd_change_process_capable(IOMMUFDBackend *be)
+{
+    struct iommu_ioas_change_process args = {.size = sizeof(args)};
+
+    /*
+     * Call IOMMU_IOAS_CHANGE_PROCESS to verify it is a recognized ioctl.
+     * This is a no-op if the process has not changed since DMA was mapped.
+     */
+    return !ioctl(be->fd, IOMMU_IOAS_CHANGE_PROCESS, &args);
+}
+
+bool iommufd_change_process(IOMMUFDBackend *be, Error **errp)
+{
+    struct iommu_ioas_change_process args = {.size = sizeof(args)};
+    bool ret = !ioctl(be->fd, IOMMU_IOAS_CHANGE_PROCESS, &args);
+
+    if (!ret) {
+        error_setg_errno(errp, errno, "IOMMU_IOAS_CHANGE_PROCESS fd %d failed",
+                         be->fd);
+    }
+    trace_iommufd_change_process(be->fd, ret);
+    return ret;
+}
+
 bool iommufd_backend_connect(IOMMUFDBackend *be, Error **errp)
 {
     int fd;
 
     if (be->owned && !be->users) {
-        fd = qemu_open("/dev/iommu", O_RDWR, errp);
+        fd = cpr_open_fd("/dev/iommu", O_RDWR, iommufd_fd_name(be), 0, errp);
         if (fd < 0) {
             return false;
         }
         be->fd = fd;
     }
+    if (!be->users && !vfio_iommufd_cpr_register_iommufd(be, errp)) {
+        if (be->owned) {
+            close(be->fd);
+            be->fd = -1;
+        }
+        return false;
+    }
     be->users++;
 
     trace_iommufd_backend_connect(be->fd, be->owned, be->users);
@@ -96,9 +149,13 @@ void iommufd_backend_disconnect(IOMMUFDBackend *be)
         goto out;
     }
     be->users--;
-    if (!be->users && be->owned) {
-        close(be->fd);
-        be->fd = -1;
+    if (!be->users) {
+        vfio_iommufd_cpr_unregister_iommufd(be);
+        if (be->owned) {
+            cpr_delete_fd(iommufd_fd_name(be), 0);
+            close(be->fd);
+            be->fd = -1;
+        }
     }
 out:
     trace_iommufd_backend_disconnect(be->fd, be->users);
@@ -172,6 +229,44 @@ int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t ioas_id, hwaddr iova,
     return ret;
 }
 
+int iommufd_backend_map_file_dma(IOMMUFDBackend *be, uint32_t ioas_id,
+                                 hwaddr iova, ram_addr_t size,
+                                 int mfd, unsigned long start, bool readonly)
+{
+    int ret, fd = be->fd;
+    struct iommu_ioas_map_file map = {
+        .size = sizeof(map),
+        .flags = IOMMU_IOAS_MAP_READABLE |
+                 IOMMU_IOAS_MAP_FIXED_IOVA,
+        .ioas_id = ioas_id,
+        .fd = mfd,
+        .start = start,
+        .iova = iova,
+        .length = size,
+    };
+
+    if (cpr_is_incoming()) {
+        return 0;
+    }
+
+    if (!readonly) {
+        map.flags |= IOMMU_IOAS_MAP_WRITEABLE;
+    }
+
+    ret = ioctl(fd, IOMMU_IOAS_MAP_FILE, &map);
+    trace_iommufd_backend_map_file_dma(fd, ioas_id, iova, size, mfd, start,
+                                       readonly, ret);
+    if (ret) {
+        ret = -errno;
+
+        /* TODO: Not support mapping hardware PCI BAR region for now. */
+        if (errno == EFAULT) {
+            warn_report("IOMMU_IOAS_MAP_FILE failed: %m, PCI BAR?");
+        }
+    }
+    return ret;
+}
+
 int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
                               hwaddr iova, ram_addr_t size)
 {
@@ -183,6 +278,10 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
         .length = size,
     };
 
+    if (cpr_is_incoming()) {
+        return 0;
+    }
+
     ret = ioctl(fd, IOMMU_IOAS_UNMAP, &unmap);
     /*
      * IOMMUFD takes mapping as some kind of object, unmapping