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