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