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" 14*3bdb738bSJohn 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 { 529fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 539fca2b7dSJohn Levon return -ENOTSUP; 549fca2b7dSJohn Levon } 559fca2b7dSJohn Levon 569fca2b7dSJohn Levon static VFIOUserContainer *vfio_user_create_container(Error **errp) 579fca2b7dSJohn Levon { 589fca2b7dSJohn Levon VFIOUserContainer *container; 599fca2b7dSJohn Levon 609fca2b7dSJohn Levon container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER)); 619fca2b7dSJohn Levon return container; 629fca2b7dSJohn Levon } 639fca2b7dSJohn Levon 649fca2b7dSJohn Levon /* 659fca2b7dSJohn Levon * Try to mirror vfio_container_connect() as much as possible. 669fca2b7dSJohn Levon */ 679fca2b7dSJohn Levon static VFIOUserContainer * 689fca2b7dSJohn Levon vfio_user_container_connect(AddressSpace *as, Error **errp) 699fca2b7dSJohn Levon { 709fca2b7dSJohn Levon VFIOContainerBase *bcontainer; 719fca2b7dSJohn Levon VFIOUserContainer *container; 729fca2b7dSJohn Levon VFIOAddressSpace *space; 739fca2b7dSJohn Levon VFIOIOMMUClass *vioc; 749fca2b7dSJohn Levon 759fca2b7dSJohn Levon space = vfio_address_space_get(as); 769fca2b7dSJohn Levon 779fca2b7dSJohn Levon container = vfio_user_create_container(errp); 789fca2b7dSJohn Levon if (!container) { 799fca2b7dSJohn Levon goto put_space_exit; 809fca2b7dSJohn Levon } 819fca2b7dSJohn Levon 829fca2b7dSJohn Levon bcontainer = &container->bcontainer; 839fca2b7dSJohn Levon 849fca2b7dSJohn Levon if (!vfio_cpr_register_container(bcontainer, errp)) { 859fca2b7dSJohn Levon goto free_container_exit; 869fca2b7dSJohn Levon } 879fca2b7dSJohn Levon 889fca2b7dSJohn Levon vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 899fca2b7dSJohn Levon assert(vioc->setup); 909fca2b7dSJohn Levon 919fca2b7dSJohn Levon if (!vioc->setup(bcontainer, errp)) { 929fca2b7dSJohn Levon goto unregister_container_exit; 939fca2b7dSJohn Levon } 949fca2b7dSJohn Levon 959fca2b7dSJohn Levon vfio_address_space_insert(space, bcontainer); 969fca2b7dSJohn Levon 979fca2b7dSJohn Levon if (!vfio_listener_register(bcontainer, errp)) { 989fca2b7dSJohn Levon goto listener_release_exit; 999fca2b7dSJohn Levon } 1009fca2b7dSJohn Levon 1019fca2b7dSJohn Levon bcontainer->initialized = true; 1029fca2b7dSJohn Levon 1039fca2b7dSJohn Levon return container; 1049fca2b7dSJohn Levon 1059fca2b7dSJohn Levon listener_release_exit: 1069fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 1079fca2b7dSJohn Levon if (vioc->release) { 1089fca2b7dSJohn Levon vioc->release(bcontainer); 1099fca2b7dSJohn Levon } 1109fca2b7dSJohn Levon 1119fca2b7dSJohn Levon unregister_container_exit: 1129fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 1139fca2b7dSJohn Levon 1149fca2b7dSJohn Levon free_container_exit: 1159fca2b7dSJohn Levon object_unref(container); 1169fca2b7dSJohn Levon 1179fca2b7dSJohn Levon put_space_exit: 1189fca2b7dSJohn Levon vfio_address_space_put(space); 1199fca2b7dSJohn Levon 1209fca2b7dSJohn Levon return NULL; 1219fca2b7dSJohn Levon } 1229fca2b7dSJohn Levon 1239fca2b7dSJohn Levon static void vfio_user_container_disconnect(VFIOUserContainer *container) 1249fca2b7dSJohn Levon { 1259fca2b7dSJohn Levon VFIOContainerBase *bcontainer = &container->bcontainer; 1269fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 1279fca2b7dSJohn Levon 1289fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 1299fca2b7dSJohn Levon if (vioc->release) { 1309fca2b7dSJohn Levon vioc->release(bcontainer); 1319fca2b7dSJohn Levon } 1329fca2b7dSJohn Levon 1339fca2b7dSJohn Levon VFIOAddressSpace *space = bcontainer->space; 1349fca2b7dSJohn Levon 1359fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 1369fca2b7dSJohn Levon object_unref(container); 1379fca2b7dSJohn Levon 1389fca2b7dSJohn Levon vfio_address_space_put(space); 1399fca2b7dSJohn Levon } 1409fca2b7dSJohn Levon 1419fca2b7dSJohn Levon static bool vfio_user_device_get(VFIOUserContainer *container, 1429fca2b7dSJohn Levon VFIODevice *vbasedev, Error **errp) 1439fca2b7dSJohn Levon { 144*3bdb738bSJohn Levon struct vfio_device_info info = { .argsz = sizeof(info) }; 145*3bdb738bSJohn Levon 146*3bdb738bSJohn Levon 147*3bdb738bSJohn Levon if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) { 148*3bdb738bSJohn Levon return false; 149*3bdb738bSJohn Levon } 1509fca2b7dSJohn Levon 1519fca2b7dSJohn Levon vbasedev->fd = -1; 1529fca2b7dSJohn Levon 1539fca2b7dSJohn Levon vfio_device_prepare(vbasedev, &container->bcontainer, &info); 1549fca2b7dSJohn Levon 1559fca2b7dSJohn Levon return true; 1569fca2b7dSJohn Levon } 1579fca2b7dSJohn Levon 1589fca2b7dSJohn Levon /* 1599fca2b7dSJohn Levon * vfio_user_device_attach: attach a device to a new container. 1609fca2b7dSJohn Levon */ 1619fca2b7dSJohn Levon static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev, 1629fca2b7dSJohn Levon AddressSpace *as, Error **errp) 1639fca2b7dSJohn Levon { 1649fca2b7dSJohn Levon VFIOUserContainer *container; 1659fca2b7dSJohn Levon 1669fca2b7dSJohn Levon container = vfio_user_container_connect(as, errp); 1679fca2b7dSJohn Levon if (container == NULL) { 1689fca2b7dSJohn Levon error_prepend(errp, "failed to connect proxy"); 1699fca2b7dSJohn Levon return false; 1709fca2b7dSJohn Levon } 1719fca2b7dSJohn Levon 1729fca2b7dSJohn Levon return vfio_user_device_get(container, vbasedev, errp); 1739fca2b7dSJohn Levon } 1749fca2b7dSJohn Levon 1759fca2b7dSJohn Levon static void vfio_user_device_detach(VFIODevice *vbasedev) 1769fca2b7dSJohn Levon { 1779fca2b7dSJohn Levon VFIOUserContainer *container = container_of(vbasedev->bcontainer, 1789fca2b7dSJohn Levon VFIOUserContainer, bcontainer); 1799fca2b7dSJohn Levon 1809fca2b7dSJohn Levon vfio_device_unprepare(vbasedev); 1819fca2b7dSJohn Levon 1829fca2b7dSJohn Levon vfio_user_container_disconnect(container); 1839fca2b7dSJohn Levon } 1849fca2b7dSJohn Levon 1859fca2b7dSJohn Levon static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single) 1869fca2b7dSJohn Levon { 1879fca2b7dSJohn Levon /* ->needs_reset is always false for vfio-user. */ 1889fca2b7dSJohn Levon return 0; 1899fca2b7dSJohn Levon } 1909fca2b7dSJohn Levon 1919fca2b7dSJohn Levon static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data) 1929fca2b7dSJohn Levon { 1939fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); 1949fca2b7dSJohn Levon 1959fca2b7dSJohn Levon vioc->setup = vfio_user_setup; 1969fca2b7dSJohn Levon vioc->dma_map = vfio_user_dma_map; 1979fca2b7dSJohn Levon vioc->dma_unmap = vfio_user_dma_unmap; 1989fca2b7dSJohn Levon vioc->attach_device = vfio_user_device_attach; 1999fca2b7dSJohn Levon vioc->detach_device = vfio_user_device_detach; 2009fca2b7dSJohn Levon vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking; 2019fca2b7dSJohn Levon vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap; 2029fca2b7dSJohn Levon vioc->pci_hot_reset = vfio_user_pci_hot_reset; 2039fca2b7dSJohn Levon }; 2049fca2b7dSJohn Levon 2059fca2b7dSJohn Levon static const TypeInfo types[] = { 2069fca2b7dSJohn Levon { 2079fca2b7dSJohn Levon .name = TYPE_VFIO_IOMMU_USER, 2089fca2b7dSJohn Levon .parent = TYPE_VFIO_IOMMU, 2099fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserContainer), 2109fca2b7dSJohn Levon .class_init = vfio_iommu_user_class_init, 2119fca2b7dSJohn Levon }, 2129fca2b7dSJohn Levon }; 2139fca2b7dSJohn Levon 2149fca2b7dSJohn Levon DEFINE_TYPES(types) 215