xref: /qemu/hw/vfio-user/container.c (revision 52ce9c35f8e364e5823fc13f23929eb597bb69ac)
19fca2b7dSJohn Levon /*
29fca2b7dSJohn Levon  * Container for vfio-user IOMMU type: rather than communicating with the kernel
39fca2b7dSJohn Levon  * vfio driver, we communicate over a socket to a server using the vfio-user
49fca2b7dSJohn Levon  * protocol.
59fca2b7dSJohn Levon  *
69fca2b7dSJohn Levon  * SPDX-License-Identifier: GPL-2.0-or-later
79fca2b7dSJohn Levon  */
89fca2b7dSJohn Levon 
99fca2b7dSJohn Levon #include <sys/ioctl.h>
109fca2b7dSJohn Levon #include <linux/vfio.h>
119fca2b7dSJohn Levon #include "qemu/osdep.h"
129fca2b7dSJohn Levon 
139fca2b7dSJohn Levon #include "hw/vfio-user/container.h"
143bdb738bSJohn Levon #include "hw/vfio-user/device.h"
159fca2b7dSJohn Levon #include "hw/vfio/vfio-cpr.h"
169fca2b7dSJohn Levon #include "hw/vfio/vfio-device.h"
179fca2b7dSJohn Levon #include "hw/vfio/vfio-listener.h"
189fca2b7dSJohn Levon #include "qapi/error.h"
199fca2b7dSJohn Levon 
209fca2b7dSJohn Levon static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer,
219fca2b7dSJohn Levon                                hwaddr iova, ram_addr_t size,
229fca2b7dSJohn Levon                                IOMMUTLBEntry *iotlb, bool unmap_all)
239fca2b7dSJohn Levon {
249fca2b7dSJohn Levon     return -ENOTSUP;
259fca2b7dSJohn Levon }
269fca2b7dSJohn Levon 
279fca2b7dSJohn Levon static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
289fca2b7dSJohn Levon                              ram_addr_t size, void *vaddr, bool readonly,
299fca2b7dSJohn Levon                              MemoryRegion *mrp)
309fca2b7dSJohn Levon {
319fca2b7dSJohn Levon     return -ENOTSUP;
329fca2b7dSJohn Levon }
339fca2b7dSJohn Levon 
349fca2b7dSJohn Levon static int
359fca2b7dSJohn Levon vfio_user_set_dirty_page_tracking(const VFIOContainerBase *bcontainer,
369fca2b7dSJohn Levon                                     bool start, Error **errp)
379fca2b7dSJohn Levon {
389fca2b7dSJohn Levon     error_setg_errno(errp, ENOTSUP, "Not supported");
399fca2b7dSJohn Levon     return -ENOTSUP;
409fca2b7dSJohn Levon }
419fca2b7dSJohn Levon 
429fca2b7dSJohn Levon static int vfio_user_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
439fca2b7dSJohn Levon                                          VFIOBitmap *vbmap, hwaddr iova,
449fca2b7dSJohn Levon                                          hwaddr size, Error **errp)
459fca2b7dSJohn Levon {
469fca2b7dSJohn Levon     error_setg_errno(errp, ENOTSUP, "Not supported");
479fca2b7dSJohn Levon     return -ENOTSUP;
489fca2b7dSJohn Levon }
499fca2b7dSJohn Levon 
509fca2b7dSJohn Levon static bool vfio_user_setup(VFIOContainerBase *bcontainer, Error **errp)
519fca2b7dSJohn Levon {
52*52ce9c35SJohn Levon     VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
53*52ce9c35SJohn Levon                                                 bcontainer);
54*52ce9c35SJohn Levon 
55*52ce9c35SJohn Levon     assert(container->proxy->dma_pgsizes != 0);
56*52ce9c35SJohn Levon     bcontainer->pgsizes = container->proxy->dma_pgsizes;
57*52ce9c35SJohn Levon     bcontainer->dma_max_mappings = container->proxy->max_dma;
58*52ce9c35SJohn Levon 
59*52ce9c35SJohn Levon     /* No live migration support yet. */
60*52ce9c35SJohn Levon     bcontainer->dirty_pages_supported = false;
61*52ce9c35SJohn Levon     bcontainer->max_dirty_bitmap_size = container->proxy->max_bitmap;
62*52ce9c35SJohn Levon     bcontainer->dirty_pgsizes = container->proxy->migr_pgsize;
63*52ce9c35SJohn Levon 
64*52ce9c35SJohn Levon     return true;
659fca2b7dSJohn Levon }
669fca2b7dSJohn Levon 
67*52ce9c35SJohn Levon static VFIOUserContainer *vfio_user_create_container(VFIODevice *vbasedev,
68*52ce9c35SJohn Levon                                                      Error **errp)
699fca2b7dSJohn Levon {
709fca2b7dSJohn Levon     VFIOUserContainer *container;
719fca2b7dSJohn Levon 
729fca2b7dSJohn Levon     container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER));
73*52ce9c35SJohn Levon     container->proxy = vbasedev->proxy;
749fca2b7dSJohn Levon     return container;
759fca2b7dSJohn Levon }
769fca2b7dSJohn Levon 
779fca2b7dSJohn Levon /*
789fca2b7dSJohn Levon  * Try to mirror vfio_container_connect() as much as possible.
799fca2b7dSJohn Levon  */
809fca2b7dSJohn Levon static VFIOUserContainer *
81*52ce9c35SJohn Levon vfio_user_container_connect(AddressSpace *as, VFIODevice *vbasedev,
82*52ce9c35SJohn Levon                             Error **errp)
839fca2b7dSJohn Levon {
849fca2b7dSJohn Levon     VFIOContainerBase *bcontainer;
859fca2b7dSJohn Levon     VFIOUserContainer *container;
869fca2b7dSJohn Levon     VFIOAddressSpace *space;
879fca2b7dSJohn Levon     VFIOIOMMUClass *vioc;
88*52ce9c35SJohn Levon     int ret;
899fca2b7dSJohn Levon 
909fca2b7dSJohn Levon     space = vfio_address_space_get(as);
919fca2b7dSJohn Levon 
92*52ce9c35SJohn Levon     container = vfio_user_create_container(vbasedev, errp);
939fca2b7dSJohn Levon     if (!container) {
949fca2b7dSJohn Levon         goto put_space_exit;
959fca2b7dSJohn Levon     }
969fca2b7dSJohn Levon 
979fca2b7dSJohn Levon     bcontainer = &container->bcontainer;
989fca2b7dSJohn Levon 
999fca2b7dSJohn Levon     if (!vfio_cpr_register_container(bcontainer, errp)) {
1009fca2b7dSJohn Levon         goto free_container_exit;
1019fca2b7dSJohn Levon     }
1029fca2b7dSJohn Levon 
103*52ce9c35SJohn Levon     ret = ram_block_uncoordinated_discard_disable(true);
104*52ce9c35SJohn Levon     if (ret) {
105*52ce9c35SJohn Levon         error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
106*52ce9c35SJohn Levon         goto unregister_container_exit;
107*52ce9c35SJohn Levon     }
108*52ce9c35SJohn Levon 
1099fca2b7dSJohn Levon     vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
1109fca2b7dSJohn Levon     assert(vioc->setup);
1119fca2b7dSJohn Levon 
1129fca2b7dSJohn Levon     if (!vioc->setup(bcontainer, errp)) {
113*52ce9c35SJohn Levon         goto enable_discards_exit;
1149fca2b7dSJohn Levon     }
1159fca2b7dSJohn Levon 
1169fca2b7dSJohn Levon     vfio_address_space_insert(space, bcontainer);
1179fca2b7dSJohn Levon 
1189fca2b7dSJohn Levon     if (!vfio_listener_register(bcontainer, errp)) {
1199fca2b7dSJohn Levon         goto listener_release_exit;
1209fca2b7dSJohn Levon     }
1219fca2b7dSJohn Levon 
1229fca2b7dSJohn Levon     bcontainer->initialized = true;
1239fca2b7dSJohn Levon 
1249fca2b7dSJohn Levon     return container;
1259fca2b7dSJohn Levon 
1269fca2b7dSJohn Levon listener_release_exit:
1279fca2b7dSJohn Levon     vfio_listener_unregister(bcontainer);
1289fca2b7dSJohn Levon     if (vioc->release) {
1299fca2b7dSJohn Levon         vioc->release(bcontainer);
1309fca2b7dSJohn Levon     }
1319fca2b7dSJohn Levon 
132*52ce9c35SJohn Levon enable_discards_exit:
133*52ce9c35SJohn Levon     ram_block_uncoordinated_discard_disable(false);
134*52ce9c35SJohn Levon 
1359fca2b7dSJohn Levon unregister_container_exit:
1369fca2b7dSJohn Levon     vfio_cpr_unregister_container(bcontainer);
1379fca2b7dSJohn Levon 
1389fca2b7dSJohn Levon free_container_exit:
1399fca2b7dSJohn Levon     object_unref(container);
1409fca2b7dSJohn Levon 
1419fca2b7dSJohn Levon put_space_exit:
1429fca2b7dSJohn Levon     vfio_address_space_put(space);
1439fca2b7dSJohn Levon 
1449fca2b7dSJohn Levon     return NULL;
1459fca2b7dSJohn Levon }
1469fca2b7dSJohn Levon 
1479fca2b7dSJohn Levon static void vfio_user_container_disconnect(VFIOUserContainer *container)
1489fca2b7dSJohn Levon {
1499fca2b7dSJohn Levon     VFIOContainerBase *bcontainer = &container->bcontainer;
1509fca2b7dSJohn Levon     VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
151*52ce9c35SJohn Levon     VFIOAddressSpace *space = bcontainer->space;
152*52ce9c35SJohn Levon 
153*52ce9c35SJohn Levon     ram_block_uncoordinated_discard_disable(false);
1549fca2b7dSJohn Levon 
1559fca2b7dSJohn Levon     vfio_listener_unregister(bcontainer);
1569fca2b7dSJohn Levon     if (vioc->release) {
1579fca2b7dSJohn Levon         vioc->release(bcontainer);
1589fca2b7dSJohn Levon     }
1599fca2b7dSJohn Levon 
1609fca2b7dSJohn Levon     vfio_cpr_unregister_container(bcontainer);
1619fca2b7dSJohn Levon     object_unref(container);
1629fca2b7dSJohn Levon 
1639fca2b7dSJohn Levon     vfio_address_space_put(space);
1649fca2b7dSJohn Levon }
1659fca2b7dSJohn Levon 
1669fca2b7dSJohn Levon static bool vfio_user_device_get(VFIOUserContainer *container,
1679fca2b7dSJohn Levon                                  VFIODevice *vbasedev, Error **errp)
1689fca2b7dSJohn Levon {
1693bdb738bSJohn Levon     struct vfio_device_info info = { .argsz = sizeof(info) };
1703bdb738bSJohn Levon 
1713bdb738bSJohn Levon 
1723bdb738bSJohn Levon     if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) {
1733bdb738bSJohn Levon         return false;
1743bdb738bSJohn Levon     }
1759fca2b7dSJohn Levon 
1769fca2b7dSJohn Levon     vbasedev->fd = -1;
1779fca2b7dSJohn Levon 
1789fca2b7dSJohn Levon     vfio_device_prepare(vbasedev, &container->bcontainer, &info);
1799fca2b7dSJohn Levon 
1809fca2b7dSJohn Levon     return true;
1819fca2b7dSJohn Levon }
1829fca2b7dSJohn Levon 
1839fca2b7dSJohn Levon /*
1849fca2b7dSJohn Levon  * vfio_user_device_attach: attach a device to a new container.
1859fca2b7dSJohn Levon  */
1869fca2b7dSJohn Levon static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev,
1879fca2b7dSJohn Levon                                     AddressSpace *as, Error **errp)
1889fca2b7dSJohn Levon {
1899fca2b7dSJohn Levon     VFIOUserContainer *container;
1909fca2b7dSJohn Levon 
191*52ce9c35SJohn Levon     container = vfio_user_container_connect(as, vbasedev, errp);
1929fca2b7dSJohn Levon     if (container == NULL) {
1939fca2b7dSJohn Levon         error_prepend(errp, "failed to connect proxy");
1949fca2b7dSJohn Levon         return false;
1959fca2b7dSJohn Levon     }
1969fca2b7dSJohn Levon 
1979fca2b7dSJohn Levon     return vfio_user_device_get(container, vbasedev, errp);
1989fca2b7dSJohn Levon }
1999fca2b7dSJohn Levon 
2009fca2b7dSJohn Levon static void vfio_user_device_detach(VFIODevice *vbasedev)
2019fca2b7dSJohn Levon {
2029fca2b7dSJohn Levon     VFIOUserContainer *container = container_of(vbasedev->bcontainer,
2039fca2b7dSJohn Levon                                                 VFIOUserContainer, bcontainer);
2049fca2b7dSJohn Levon 
2059fca2b7dSJohn Levon     vfio_device_unprepare(vbasedev);
2069fca2b7dSJohn Levon 
2079fca2b7dSJohn Levon     vfio_user_container_disconnect(container);
2089fca2b7dSJohn Levon }
2099fca2b7dSJohn Levon 
2109fca2b7dSJohn Levon static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single)
2119fca2b7dSJohn Levon {
2129fca2b7dSJohn Levon     /* ->needs_reset is always false for vfio-user. */
2139fca2b7dSJohn Levon     return 0;
2149fca2b7dSJohn Levon }
2159fca2b7dSJohn Levon 
2169fca2b7dSJohn Levon static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data)
2179fca2b7dSJohn Levon {
2189fca2b7dSJohn Levon     VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
2199fca2b7dSJohn Levon 
2209fca2b7dSJohn Levon     vioc->setup = vfio_user_setup;
2219fca2b7dSJohn Levon     vioc->dma_map = vfio_user_dma_map;
2229fca2b7dSJohn Levon     vioc->dma_unmap = vfio_user_dma_unmap;
2239fca2b7dSJohn Levon     vioc->attach_device = vfio_user_device_attach;
2249fca2b7dSJohn Levon     vioc->detach_device = vfio_user_device_detach;
2259fca2b7dSJohn Levon     vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking;
2269fca2b7dSJohn Levon     vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap;
2279fca2b7dSJohn Levon     vioc->pci_hot_reset = vfio_user_pci_hot_reset;
2289fca2b7dSJohn Levon };
2299fca2b7dSJohn Levon 
2309fca2b7dSJohn Levon static const TypeInfo types[] = {
2319fca2b7dSJohn Levon     {
2329fca2b7dSJohn Levon         .name = TYPE_VFIO_IOMMU_USER,
2339fca2b7dSJohn Levon         .parent = TYPE_VFIO_IOMMU,
2349fca2b7dSJohn Levon         .instance_size = sizeof(VFIOUserContainer),
2359fca2b7dSJohn Levon         .class_init = vfio_iommu_user_class_init,
2369fca2b7dSJohn Levon     },
2379fca2b7dSJohn Levon };
2389fca2b7dSJohn Levon 
2399fca2b7dSJohn Levon DEFINE_TYPES(types)
240