master
c 360 lines 10 KB
Raw
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 "qemu/osdep.h"
10 #include <sys/ioctl.h>
11 #include <linux/vfio.h>
12
13 #include "hw/vfio-user/container.h"
14 #include "hw/vfio-user/device.h"
15 #include "hw/vfio-user/trace.h"
16 #include "hw/vfio/vfio-device.h"
17 #include "hw/vfio/vfio-listener.h"
18 #include "system/ramblock.h"
19 #include "qapi/error.h"
20
21 /*
22 * When DMA space is the physical address space, the region add/del listeners
23 * will fire during memory update transactions. These depend on BQL being held,
24 * so do any resulting map/demap ops async while keeping BQL.
25 */
26 static void vfio_user_listener_begin(VFIOContainer *bcontainer)
27 {
28 VFIOUserContainer *container = VFIO_IOMMU_USER(bcontainer);
29
30 container->proxy->async_ops = true;
31 }
32
33 static void vfio_user_listener_commit(VFIOContainer *bcontainer)
34 {
35 VFIOUserContainer *container = VFIO_IOMMU_USER(bcontainer);
36
37 /* wait here for any async requests sent during the transaction */
38 container->proxy->async_ops = false;
39 vfio_user_wait_reqs(container->proxy);
40 }
41
42 static int vfio_user_dma_unmap(const VFIOContainer *bcontainer,
43 hwaddr iova, uint64_t size,
44 IOMMUTLBEntry *iotlb, bool unmap_all)
45 {
46 VFIOUserContainer *container = VFIO_IOMMU_USER(bcontainer);
47
48 Error *local_err = NULL;
49 int ret = 0;
50
51 VFIOUserDMAUnmap *msgp = g_malloc(sizeof(*msgp));
52
53 vfio_user_request_msg(&msgp->hdr, VFIO_USER_DMA_UNMAP, sizeof(*msgp), 0);
54 msgp->argsz = sizeof(struct vfio_iommu_type1_dma_unmap);
55 msgp->flags = unmap_all ? VFIO_DMA_UNMAP_FLAG_ALL : 0;
56 msgp->iova = iova;
57 msgp->size = size;
58 trace_vfio_user_dma_unmap(msgp->iova, msgp->size, msgp->flags,
59 container->proxy->async_ops);
60
61 if (container->proxy->async_ops) {
62 if (!vfio_user_send_nowait(container->proxy, &msgp->hdr, NULL,
63 0, &local_err)) {
64 error_report_err(local_err);
65 ret = -EFAULT;
66 }
67 } else {
68 if (!vfio_user_send_wait(container->proxy, &msgp->hdr, NULL,
69 0, &local_err)) {
70 error_report_err(local_err);
71 ret = -EFAULT;
72 }
73
74 if (msgp->hdr.flags & VFIO_USER_ERROR) {
75 ret = -msgp->hdr.error_reply;
76 }
77
78 g_free(msgp);
79 }
80
81 return ret;
82 }
83
84 static int vfio_user_dma_map(const VFIOContainer *bcontainer, hwaddr iova,
85 uint64_t size, void *vaddr, bool readonly,
86 MemoryRegion *mrp)
87 {
88 VFIOUserContainer *container = VFIO_IOMMU_USER(bcontainer);
89
90 int fd = memory_region_get_fd(mrp);
91 Error *local_err = NULL;
92 int ret = 0;
93
94 VFIOUserFDs *fds = NULL;
95 VFIOUserDMAMap *msgp = g_malloc0(sizeof(*msgp));
96
97 vfio_user_request_msg(&msgp->hdr, VFIO_USER_DMA_MAP, sizeof(*msgp), 0);
98 msgp->argsz = sizeof(struct vfio_iommu_type1_dma_map);
99 msgp->flags = VFIO_DMA_MAP_FLAG_READ;
100 msgp->offset = 0;
101 msgp->iova = iova;
102 msgp->size = size;
103
104 /*
105 * vaddr enters as a QEMU process address; make it either a file offset
106 * for mapped areas or leave as 0.
107 */
108 if (fd != -1) {
109 msgp->offset = qemu_ram_block_host_offset(mrp->ram_block, vaddr);
110 }
111
112 if (!readonly) {
113 msgp->flags |= VFIO_DMA_MAP_FLAG_WRITE;
114 }
115
116 trace_vfio_user_dma_map(msgp->iova, msgp->size, msgp->offset, msgp->flags,
117 container->proxy->async_ops);
118
119 /*
120 * The async_ops case sends without blocking. They're later waited for in
121 * vfio_send_wait_reqs.
122 */
123 if (container->proxy->async_ops) {
124 /* can't use auto variable since we don't block */
125 if (fd != -1) {
126 fds = vfio_user_getfds(1);
127 fds->send_fds = 1;
128 fds->fds[0] = fd;
129 }
130
131 if (!vfio_user_send_nowait(container->proxy, &msgp->hdr, fds,
132 0, &local_err)) {
133 error_report_err(local_err);
134 ret = -EFAULT;
135 }
136 } else {
137 VFIOUserFDs local_fds = { 1, 0, &fd };
138
139 fds = fd != -1 ? &local_fds : NULL;
140
141 if (!vfio_user_send_wait(container->proxy, &msgp->hdr, fds,
142 0, &local_err)) {
143 error_report_err(local_err);
144 ret = -EFAULT;
145 }
146
147 if (msgp->hdr.flags & VFIO_USER_ERROR) {
148 ret = -msgp->hdr.error_reply;
149 }
150
151 g_free(msgp);
152 }
153
154 return ret;
155 }
156
157 static int
158 vfio_user_set_dirty_page_tracking(const VFIOContainer *bcontainer,
159 bool start, Error **errp)
160 {
161 error_setg_errno(errp, ENOTSUP, "Not supported");
162 return -ENOTSUP;
163 }
164
165 static int vfio_user_query_dirty_bitmap(const VFIOContainer *bcontainer,
166 VFIOBitmap *vbmap, hwaddr iova,
167 hwaddr size, uint64_t backend_flag,
168 Error **errp)
169 {
170 error_setg_errno(errp, ENOTSUP, "Not supported");
171 return -ENOTSUP;
172 }
173
174 static bool vfio_user_setup(VFIOContainer *bcontainer, Error **errp)
175 {
176 VFIOUserContainer *container = VFIO_IOMMU_USER(bcontainer);
177
178 assert(container->proxy->dma_pgsizes != 0);
179 bcontainer->pgsizes = container->proxy->dma_pgsizes;
180 bcontainer->dma_max_mappings = container->proxy->max_dma;
181
182 /* No live migration support yet. */
183 bcontainer->dirty_pages_supported = false;
184 bcontainer->max_dirty_bitmap_size = container->proxy->max_bitmap;
185 bcontainer->dirty_pgsizes = container->proxy->migr_pgsize;
186
187 return true;
188 }
189
190 static VFIOUserContainer *vfio_user_create_container(VFIODevice *vbasedev,
191 Error **errp)
192 {
193 VFIOUserContainer *container;
194
195 container = VFIO_IOMMU_USER(object_new(TYPE_VFIO_IOMMU_USER));
196 container->proxy = vbasedev->proxy;
197 return container;
198 }
199
200 /*
201 * Try to mirror vfio_container_connect() as much as possible.
202 */
203 static VFIOUserContainer *
204 vfio_user_container_connect(AddressSpace *as, VFIODevice *vbasedev,
205 Error **errp)
206 {
207 VFIOContainer *bcontainer;
208 VFIOUserContainer *container;
209 VFIOAddressSpace *space;
210 VFIOIOMMUClass *vioc;
211 int ret;
212
213 space = vfio_address_space_get(as);
214
215 container = vfio_user_create_container(vbasedev, errp);
216 if (!container) {
217 goto put_space_exit;
218 }
219
220 bcontainer = VFIO_IOMMU(container);
221
222 ret = ram_block_uncoordinated_discard_disable(true);
223 if (ret) {
224 error_setg_errno(errp, -ret, "Cannot set discarding of RAM broken");
225 goto free_container_exit;
226 }
227
228 vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
229 assert(vioc->setup);
230
231 if (!vioc->setup(bcontainer, errp)) {
232 goto enable_discards_exit;
233 }
234
235 vfio_address_space_insert(space, bcontainer);
236
237 if (!vfio_listener_register(bcontainer, errp)) {
238 goto listener_release_exit;
239 }
240
241 bcontainer->initialized = true;
242
243 return container;
244
245 listener_release_exit:
246 vfio_listener_unregister(bcontainer);
247 if (vioc->release) {
248 vioc->release(bcontainer);
249 }
250
251 enable_discards_exit:
252 ram_block_uncoordinated_discard_disable(false);
253
254 free_container_exit:
255 object_unref(container);
256
257 put_space_exit:
258 vfio_address_space_put(space);
259
260 return NULL;
261 }
262
263 static void vfio_user_container_disconnect(VFIOUserContainer *container)
264 {
265 VFIOContainer *bcontainer = VFIO_IOMMU(container);
266 VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer);
267 VFIOAddressSpace *space = bcontainer->space;
268
269 ram_block_uncoordinated_discard_disable(false);
270
271 vfio_listener_unregister(bcontainer);
272 if (vioc->release) {
273 vioc->release(bcontainer);
274 }
275
276 object_unref(container);
277
278 vfio_address_space_put(space);
279 }
280
281 static bool vfio_user_device_get(VFIOUserContainer *container,
282 VFIODevice *vbasedev, Error **errp)
283 {
284 struct vfio_device_info info = { .argsz = sizeof(info) };
285
286
287 if (!vfio_user_get_device_info(vbasedev->proxy, &info, errp)) {
288 return false;
289 }
290
291 vbasedev->fd = -1;
292
293 vfio_device_prepare(vbasedev, VFIO_IOMMU(container), &info);
294
295 return true;
296 }
297
298 /*
299 * vfio_user_device_attach: attach a device to a new container.
300 */
301 static bool vfio_user_device_attach(const char *name, VFIODevice *vbasedev,
302 AddressSpace *as, Error **errp)
303 {
304 VFIOUserContainer *container;
305
306 container = vfio_user_container_connect(as, vbasedev, errp);
307 if (container == NULL) {
308 error_prepend(errp, "failed to connect proxy");
309 return false;
310 }
311
312 if (!vfio_user_device_get(container, vbasedev, errp)) {
313 vfio_user_container_disconnect(container);
314 return false;
315 }
316
317 return true;
318 }
319
320 static void vfio_user_device_detach(VFIODevice *vbasedev)
321 {
322 VFIOUserContainer *container = VFIO_IOMMU_USER(vbasedev->bcontainer);
323
324 vfio_device_unprepare(vbasedev);
325
326 vfio_user_container_disconnect(container);
327 }
328
329 static int vfio_user_pci_hot_reset(VFIODevice *vbasedev, bool single)
330 {
331 /* ->needs_reset is always false for vfio-user. */
332 return 0;
333 }
334
335 static void vfio_iommu_user_class_init(ObjectClass *klass, const void *data)
336 {
337 VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass);
338
339 vioc->setup = vfio_user_setup;
340 vioc->listener_begin = vfio_user_listener_begin,
341 vioc->listener_commit = vfio_user_listener_commit,
342 vioc->dma_map = vfio_user_dma_map;
343 vioc->dma_unmap = vfio_user_dma_unmap;
344 vioc->attach_device = vfio_user_device_attach;
345 vioc->detach_device = vfio_user_device_detach;
346 vioc->set_dirty_page_tracking = vfio_user_set_dirty_page_tracking;
347 vioc->query_dirty_bitmap = vfio_user_query_dirty_bitmap;
348 vioc->pci_hot_reset = vfio_user_pci_hot_reset;
349 };
350
351 static const TypeInfo types[] = {
352 {
353 .name = TYPE_VFIO_IOMMU_USER,
354 .parent = TYPE_VFIO_IOMMU,
355 .instance_size = sizeof(VFIOUserContainer),
356 .class_init = vfio_iommu_user_class_init,
357 },
358 };
359
360 DEFINE_TYPES(types)