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