1*9fca2b7dSJohn Levon /* 2*9fca2b7dSJohn Levon * Container for vfio-user IOMMU type: rather than communicating with the kernel 3*9fca2b7dSJohn Levon * vfio driver, we communicate over a socket to a server using the vfio-user 4*9fca2b7dSJohn Levon * protocol. 5*9fca2b7dSJohn Levon * 6*9fca2b7dSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 7*9fca2b7dSJohn Levon */ 8*9fca2b7dSJohn Levon 9*9fca2b7dSJohn Levon #include <sys/ioctl.h> 10*9fca2b7dSJohn Levon #include <linux/vfio.h> 11*9fca2b7dSJohn Levon #include "qemu/osdep.h" 12*9fca2b7dSJohn Levon 13*9fca2b7dSJohn Levon #include "hw/vfio-user/container.h" 14*9fca2b7dSJohn Levon #include "hw/vfio/vfio-cpr.h" 15*9fca2b7dSJohn Levon #include "hw/vfio/vfio-device.h" 16*9fca2b7dSJohn Levon #include "hw/vfio/vfio-listener.h" 17*9fca2b7dSJohn Levon #include "qapi/error.h" 18*9fca2b7dSJohn Levon 19*9fca2b7dSJohn Levon static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer, 20*9fca2b7dSJohn Levon hwaddr iova, ram_addr_t size, 21*9fca2b7dSJohn Levon IOMMUTLBEntry *iotlb, bool unmap_all) 22*9fca2b7dSJohn Levon { 23*9fca2b7dSJohn Levon return -ENOTSUP; 24*9fca2b7dSJohn Levon } 25*9fca2b7dSJohn Levon 26*9fca2b7dSJohn Levon static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova, 27*9fca2b7dSJohn Levon ram_addr_t size, void *vaddr, bool readonly, 28*9fca2b7dSJohn Levon MemoryRegion *mrp) 29*9fca2b7dSJohn Levon { 30*9fca2b7dSJohn Levon return -ENOTSUP; 31*9fca2b7dSJohn Levon } 32*9fca2b7dSJohn Levon 33*9fca2b7dSJohn Levon static int 34*9fca2b7dSJohn Levon vfio_user_set_dirty_page_tracking(const VFIOContainerBase *bcontainer, 35*9fca2b7dSJohn Levon bool start, Error **errp) 36*9fca2b7dSJohn Levon { 37*9fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 38*9fca2b7dSJohn Levon return -ENOTSUP; 39*9fca2b7dSJohn Levon } 40*9fca2b7dSJohn Levon 41*9fca2b7dSJohn Levon static int vfio_user_query_dirty_bitmap(const VFIOContainerBase *bcontainer, 42*9fca2b7dSJohn Levon VFIOBitmap *vbmap, hwaddr iova, 43*9fca2b7dSJohn Levon hwaddr size, Error **errp) 44*9fca2b7dSJohn Levon { 45*9fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 46*9fca2b7dSJohn Levon return -ENOTSUP; 47*9fca2b7dSJohn Levon } 48*9fca2b7dSJohn Levon 49*9fca2b7dSJohn Levon static bool vfio_user_setup(VFIOContainerBase *bcontainer, Error **errp) 50*9fca2b7dSJohn Levon { 51*9fca2b7dSJohn Levon error_setg_errno(errp, ENOTSUP, "Not supported"); 52*9fca2b7dSJohn Levon return -ENOTSUP; 53*9fca2b7dSJohn Levon } 54*9fca2b7dSJohn Levon 55*9fca2b7dSJohn Levon static VFIOUserContainer *vfio_user_create_container(Error **errp) 56*9fca2b7dSJohn Levon { 57*9fca2b7dSJohn Levon VFIOUserContainer *container; 58*9fca2b7dSJohn Levon 59*9fca2b7dSJohn Levon container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER)); 60*9fca2b7dSJohn Levon return container; 61*9fca2b7dSJohn Levon } 62*9fca2b7dSJohn Levon 63*9fca2b7dSJohn Levon /* 64*9fca2b7dSJohn Levon * Try to mirror vfio_container_connect() as much as possible. 65*9fca2b7dSJohn Levon */ 66*9fca2b7dSJohn Levon static VFIOUserContainer * 67*9fca2b7dSJohn Levon vfio_user_container_connect(AddressSpace *as, Error **errp) 68*9fca2b7dSJohn Levon { 69*9fca2b7dSJohn Levon VFIOContainerBase *bcontainer; 70*9fca2b7dSJohn Levon VFIOUserContainer *container; 71*9fca2b7dSJohn Levon VFIOAddressSpace *space; 72*9fca2b7dSJohn Levon VFIOIOMMUClass *vioc; 73*9fca2b7dSJohn Levon 74*9fca2b7dSJohn Levon space = vfio_address_space_get(as); 75*9fca2b7dSJohn Levon 76*9fca2b7dSJohn Levon container = vfio_user_create_container(errp); 77*9fca2b7dSJohn Levon if (!container) { 78*9fca2b7dSJohn Levon goto put_space_exit; 79*9fca2b7dSJohn Levon } 80*9fca2b7dSJohn Levon 81*9fca2b7dSJohn Levon bcontainer = &container->bcontainer; 82*9fca2b7dSJohn Levon 83*9fca2b7dSJohn Levon if (!vfio_cpr_register_container(bcontainer, errp)) { 84*9fca2b7dSJohn Levon goto free_container_exit; 85*9fca2b7dSJohn Levon } 86*9fca2b7dSJohn Levon 87*9fca2b7dSJohn Levon vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 88*9fca2b7dSJohn Levon assert(vioc->setup); 89*9fca2b7dSJohn Levon 90*9fca2b7dSJohn Levon if (!vioc->setup(bcontainer, errp)) { 91*9fca2b7dSJohn Levon goto unregister_container_exit; 92*9fca2b7dSJohn Levon } 93*9fca2b7dSJohn Levon 94*9fca2b7dSJohn Levon vfio_address_space_insert(space, bcontainer); 95*9fca2b7dSJohn Levon 96*9fca2b7dSJohn Levon if (!vfio_listener_register(bcontainer, errp)) { 97*9fca2b7dSJohn Levon goto listener_release_exit; 98*9fca2b7dSJohn Levon } 99*9fca2b7dSJohn Levon 100*9fca2b7dSJohn Levon bcontainer->initialized = true; 101*9fca2b7dSJohn Levon 102*9fca2b7dSJohn Levon return container; 103*9fca2b7dSJohn Levon 104*9fca2b7dSJohn Levon listener_release_exit: 105*9fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 106*9fca2b7dSJohn Levon if (vioc->release) { 107*9fca2b7dSJohn Levon vioc->release(bcontainer); 108*9fca2b7dSJohn Levon } 109*9fca2b7dSJohn Levon 110*9fca2b7dSJohn Levon unregister_container_exit: 111*9fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 112*9fca2b7dSJohn Levon 113*9fca2b7dSJohn Levon free_container_exit: 114*9fca2b7dSJohn Levon object_unref(container); 115*9fca2b7dSJohn Levon 116*9fca2b7dSJohn Levon put_space_exit: 117*9fca2b7dSJohn Levon vfio_address_space_put(space); 118*9fca2b7dSJohn Levon 119*9fca2b7dSJohn Levon return NULL; 120*9fca2b7dSJohn Levon } 121*9fca2b7dSJohn Levon 122*9fca2b7dSJohn Levon static void vfio_user_container_disconnect(VFIOUserContainer *container) 123*9fca2b7dSJohn Levon { 124*9fca2b7dSJohn Levon VFIOContainerBase *bcontainer = &container->bcontainer; 125*9fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); 126*9fca2b7dSJohn Levon 127*9fca2b7dSJohn Levon vfio_listener_unregister(bcontainer); 128*9fca2b7dSJohn Levon if (vioc->release) { 129*9fca2b7dSJohn Levon vioc->release(bcontainer); 130*9fca2b7dSJohn Levon } 131*9fca2b7dSJohn Levon 132*9fca2b7dSJohn Levon VFIOAddressSpace *space = bcontainer->space; 133*9fca2b7dSJohn Levon 134*9fca2b7dSJohn Levon vfio_cpr_unregister_container(bcontainer); 135*9fca2b7dSJohn Levon object_unref(container); 136*9fca2b7dSJohn Levon 137*9fca2b7dSJohn Levon vfio_address_space_put(space); 138*9fca2b7dSJohn Levon } 139*9fca2b7dSJohn Levon 140*9fca2b7dSJohn Levon static bool vfio_user_device_get(VFIOUserContainer *container, 141*9fca2b7dSJohn Levon VFIODevice *vbasedev, Error **errp) 142*9fca2b7dSJohn Levon { 143*9fca2b7dSJohn Levon struct vfio_device_info info = { 0 }; 144*9fca2b7dSJohn Levon 145*9fca2b7dSJohn Levon vbasedev->fd = -1; 146*9fca2b7dSJohn Levon 147*9fca2b7dSJohn Levon vfio_device_prepare(vbasedev, &container->bcontainer, &info); 148*9fca2b7dSJohn Levon 149*9fca2b7dSJohn Levon return true; 150*9fca2b7dSJohn Levon } 151*9fca2b7dSJohn Levon 152*9fca2b7dSJohn Levon /* 153*9fca2b7dSJohn Levon * vfio_user_device_attach: attach a device to a new container. 154*9fca2b7dSJohn Levon */ 155*9fca2b7dSJohn Levon static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev, 156*9fca2b7dSJohn Levon AddressSpace *as, Error **errp) 157*9fca2b7dSJohn Levon { 158*9fca2b7dSJohn Levon VFIOUserContainer *container; 159*9fca2b7dSJohn Levon 160*9fca2b7dSJohn Levon container = vfio_user_container_connect(as, errp); 161*9fca2b7dSJohn Levon if (container == NULL) { 162*9fca2b7dSJohn Levon error_prepend(errp, "failed to connect proxy"); 163*9fca2b7dSJohn Levon return false; 164*9fca2b7dSJohn Levon } 165*9fca2b7dSJohn Levon 166*9fca2b7dSJohn Levon return vfio_user_device_get(container, vbasedev, errp); 167*9fca2b7dSJohn Levon } 168*9fca2b7dSJohn Levon 169*9fca2b7dSJohn Levon static void vfio_user_device_detach(VFIODevice *vbasedev) 170*9fca2b7dSJohn Levon { 171*9fca2b7dSJohn Levon VFIOUserContainer *container = container_of(vbasedev->bcontainer, 172*9fca2b7dSJohn Levon VFIOUserContainer, bcontainer); 173*9fca2b7dSJohn Levon 174*9fca2b7dSJohn Levon vfio_device_unprepare(vbasedev); 175*9fca2b7dSJohn Levon 176*9fca2b7dSJohn Levon vfio_user_container_disconnect(container); 177*9fca2b7dSJohn Levon } 178*9fca2b7dSJohn Levon 179*9fca2b7dSJohn Levon static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single) 180*9fca2b7dSJohn Levon { 181*9fca2b7dSJohn Levon /* ->needs_reset is always false for vfio-user. */ 182*9fca2b7dSJohn Levon return 0; 183*9fca2b7dSJohn Levon } 184*9fca2b7dSJohn Levon 185*9fca2b7dSJohn Levon static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data) 186*9fca2b7dSJohn Levon { 187*9fca2b7dSJohn Levon VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); 188*9fca2b7dSJohn Levon 189*9fca2b7dSJohn Levon vioc->setup = vfio_user_setup; 190*9fca2b7dSJohn Levon vioc->dma_map = vfio_user_dma_map; 191*9fca2b7dSJohn Levon vioc->dma_unmap = vfio_user_dma_unmap; 192*9fca2b7dSJohn Levon vioc->attach_device = vfio_user_device_attach; 193*9fca2b7dSJohn Levon vioc->detach_device = vfio_user_device_detach; 194*9fca2b7dSJohn Levon vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking; 195*9fca2b7dSJohn Levon vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap; 196*9fca2b7dSJohn Levon vioc->pci_hot_reset = vfio_user_pci_hot_reset; 197*9fca2b7dSJohn Levon }; 198*9fca2b7dSJohn Levon 199*9fca2b7dSJohn Levon static const TypeInfo types[] = { 200*9fca2b7dSJohn Levon { 201*9fca2b7dSJohn Levon .name = TYPE_VFIO_IOMMU_USER, 202*9fca2b7dSJohn Levon .parent = TYPE_VFIO_IOMMU, 203*9fca2b7dSJohn Levon .instance_size = sizeof(VFIOUserContainer), 204*9fca2b7dSJohn Levon .class_init = vfio_iommu_user_class_init, 205*9fca2b7dSJohn Levon }, 206*9fca2b7dSJohn Levon }; 207*9fca2b7dSJohn Levon 208*9fca2b7dSJohn Levon DEFINE_TYPES(types) 209