xref: /qemu/hw/vfio-user/container.c (revision 3bdb738b734c77f93f93f8119c8f6ba8a9c5947c)
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