xref: /qemu/hw/vfio-user/container.c (revision 52ce9c35f8e364e5823fc13f23929eb597bb69ac)
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     VFIOUserContainer *container = container_of(bcontainer, VFIOUserContainer,
53                                                 bcontainer);
54 
55     assert(container->proxy->dma_pgsizes != 0);
56     bcontainer->pgsizes = container->proxy->dma_pgsizes;
57     bcontainer->dma_max_mappings = container->proxy->max_dma;
58 
59     /* No live migration support yet. */
60     bcontainer->dirty_pages_supported = false;
61     bcontainer->max_dirty_bitmap_size = container->proxy->max_bitmap;
62     bcontainer->dirty_pgsizes = container->proxy->migr_pgsize;
63 
64     return true;
65 }
66 
67 static VFIOUserContainer *vfio_user_create_container(VFIODevice *vbasedev,
68                                                      Error **errp)
69 {
70     VFIOUserContainer *container;
71 
72     container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER));
73     container->proxy = vbasedev->proxy;
74     return container;
75 }
76 
77 /*
78  * Try to mirror vfio_container_connect() as much as possible.
79  */
80 static VFIOUserContainer *
81 vfio_user_container_connect(AddressSpace *as, VFIODevice *vbasedev,
82                             Error **errp)
83 {
84     VFIOContainerBase *bcontainer;
85     VFIOUserContainer *container;
86     VFIOAddressSpace *space;
87     VFIOIOMMUClass *vioc;
88     int ret;
89 
90     space = vfio_address_space_get(as);
91 
92     container = vfio_user_create_container(vbasedev, errp);
93     if (!container) {
94         goto put_space_exit;
95     }
96 
97     bcontainer = &container->bcontainer;
98 
99     if (!vfio_cpr_register_container(bcontainer, errp)) {
100         goto free_container_exit;
101     }
102 
103     ret = ram_block_uncoordinated_discard_disable(true);
104     if (ret) {
105         error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
106         goto unregister_container_exit;
107     }
108 
109     vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
110     assert(vioc->setup);
111 
112     if (!vioc->setup(bcontainer, errp)) {
113         goto enable_discards_exit;
114     }
115 
116     vfio_address_space_insert(space, bcontainer);
117 
118     if (!vfio_listener_register(bcontainer, errp)) {
119         goto listener_release_exit;
120     }
121 
122     bcontainer->initialized = true;
123 
124     return container;
125 
126 listener_release_exit:
127     vfio_listener_unregister(bcontainer);
128     if (vioc->release) {
129         vioc->release(bcontainer);
130     }
131 
132 enable_discards_exit:
133     ram_block_uncoordinated_discard_disable(false);
134 
135 unregister_container_exit:
136     vfio_cpr_unregister_container(bcontainer);
137 
138 free_container_exit:
139     object_unref(container);
140 
141 put_space_exit:
142     vfio_address_space_put(space);
143 
144     return NULL;
145 }
146 
147 static void vfio_user_container_disconnect(VFIOUserContainer *container)
148 {
149     VFIOContainerBase *bcontainer = &container->bcontainer;
150     VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
151     VFIOAddressSpace *space = bcontainer->space;
152 
153     ram_block_uncoordinated_discard_disable(false);
154 
155     vfio_listener_unregister(bcontainer);
156     if (vioc->release) {
157         vioc->release(bcontainer);
158     }
159 
160     vfio_cpr_unregister_container(bcontainer);
161     object_unref(container);
162 
163     vfio_address_space_put(space);
164 }
165 
166 static bool vfio_user_device_get(VFIOUserContainer *container,
167                                  VFIODevice *vbasedev, Error **errp)
168 {
169     struct vfio_device_info info = { .argsz = sizeof(info) };
170 
171 
172     if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) {
173         return false;
174     }
175 
176     vbasedev->fd = -1;
177 
178     vfio_device_prepare(vbasedev, &container->bcontainer, &info);
179 
180     return true;
181 }
182 
183 /*
184  * vfio_user_device_attach: attach a device to a new container.
185  */
186 static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev,
187                                     AddressSpace *as, Error **errp)
188 {
189     VFIOUserContainer *container;
190 
191     container = vfio_user_container_connect(as, vbasedev, errp);
192     if (container == NULL) {
193         error_prepend(errp, "failed to connect proxy");
194         return false;
195     }
196 
197     return vfio_user_device_get(container, vbasedev, errp);
198 }
199 
200 static void vfio_user_device_detach(VFIODevice *vbasedev)
201 {
202     VFIOUserContainer *container = container_of(vbasedev->bcontainer,
203                                                 VFIOUserContainer, bcontainer);
204 
205     vfio_device_unprepare(vbasedev);
206 
207     vfio_user_container_disconnect(container);
208 }
209 
210 static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single)
211 {
212     /* ->needs_reset is always false for vfio-user. */
213     return 0;
214 }
215 
216 static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data)
217 {
218     VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
219 
220     vioc->setup = vfio_user_setup;
221     vioc->dma_map = vfio_user_dma_map;
222     vioc->dma_unmap = vfio_user_dma_unmap;
223     vioc->attach_device = vfio_user_device_attach;
224     vioc->detach_device = vfio_user_device_detach;
225     vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking;
226     vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap;
227     vioc->pci_hot_reset = vfio_user_pci_hot_reset;
228 };
229 
230 static const TypeInfo types[] = {
231     {
232         .name = TYPE_VFIO_IOMMU_USER,
233         .parent = TYPE_VFIO_IOMMU,
234         .instance_size = sizeof(VFIOUserContainer),
235         .class_init = vfio_iommu_user_class_init,
236     },
237 };
238 
239 DEFINE_TYPES(types)
240