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