xref: /qemu/hw/remote/vfio-user-obj.c (revision a6e8d6d98e61a270bcbd1e611f2e1d71a80d86c5)
1 /**
2  * QEMU vfio-user-server server object
3  *
4  * Copyright © 2022 Oracle and/or its affiliates.
5  *
6  * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
7  *
8  * See the COPYING file in the top-level directory.
9  *
10  */
11 
12 /**
13  * Usage: add options:
14  *     -machine x-remote,vfio-user=on,auto-shutdown=on
15  *     -device <PCI-device>,id=<pci-dev-id>
16  *     -object x-vfio-user-server,id=<id>,type=unix,path=<socket-path>,
17  *             device=<pci-dev-id>
18  *
19  * Note that x-vfio-user-server object must be used with x-remote machine only.
20  * This server could only support PCI devices for now.
21  *
22  * type - SocketAddress type - presently "unix" alone is supported. Required
23  *        option
24  *
25  * path - named unix socket, it will be created by the server. It is
26  *        a required option
27  *
28  * device - id of a device on the server, a required option. PCI devices
29  *          alone are supported presently.
30  */
31 
32 #include "qemu/osdep.h"
33 
34 #include "qom/object.h"
35 #include "qom/object_interfaces.h"
36 #include "qemu/error-report.h"
37 #include "trace.h"
38 #include "sysemu/runstate.h"
39 #include "hw/boards.h"
40 #include "hw/remote/machine.h"
41 #include "qapi/error.h"
42 #include "qapi/qapi-visit-sockets.h"
43 #include "qemu/notify.h"
44 #include "sysemu/sysemu.h"
45 #include "libvfio-user.h"
46 #include "hw/qdev-core.h"
47 #include "hw/pci/pci.h"
48 
49 #define TYPE_VFU_OBJECT "x-vfio-user-server"
50 OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT)
51 
52 /**
53  * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown
54  * is set, it aborts the machine on error. Otherwise, it logs an
55  * error message without aborting.
56  */
57 #define VFU_OBJECT_ERROR(o, fmt, ...)                                     \
58     {                                                                     \
59         if (vfu_object_auto_shutdown()) {                                 \
60             error_setg(&error_abort, (fmt), ## __VA_ARGS__);              \
61         } else {                                                          \
62             error_report((fmt), ## __VA_ARGS__);                          \
63         }                                                                 \
64     }                                                                     \
65 
66 struct VfuObjectClass {
67     ObjectClass parent_class;
68 
69     unsigned int nr_devs;
70 };
71 
72 struct VfuObject {
73     /* private */
74     Object parent;
75 
76     SocketAddress *socket;
77 
78     char *device;
79 
80     Error *err;
81 
82     Notifier machine_done;
83 
84     vfu_ctx_t *vfu_ctx;
85 
86     PCIDevice *pci_dev;
87 
88     Error *unplug_blocker;
89 };
90 
91 static void vfu_object_init_ctx(VfuObject *o, Error **errp);
92 
93 static bool vfu_object_auto_shutdown(void)
94 {
95     bool auto_shutdown = true;
96     Error *local_err = NULL;
97 
98     if (!current_machine) {
99         return auto_shutdown;
100     }
101 
102     auto_shutdown = object_property_get_bool(OBJECT(current_machine),
103                                              "auto-shutdown",
104                                              &local_err);
105 
106     /*
107      * local_err would be set if no such property exists - safe to ignore.
108      * Unlikely scenario as auto-shutdown is always defined for
109      * TYPE_REMOTE_MACHINE, and  TYPE_VFU_OBJECT only works with
110      * TYPE_REMOTE_MACHINE
111      */
112     if (local_err) {
113         auto_shutdown = true;
114         error_free(local_err);
115     }
116 
117     return auto_shutdown;
118 }
119 
120 static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name,
121                                   void *opaque, Error **errp)
122 {
123     VfuObject *o = VFU_OBJECT(obj);
124 
125     if (o->vfu_ctx) {
126         error_setg(errp, "vfu: Unable to set socket property - server busy");
127         return;
128     }
129 
130     qapi_free_SocketAddress(o->socket);
131 
132     o->socket = NULL;
133 
134     visit_type_SocketAddress(v, name, &o->socket, errp);
135 
136     if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
137         error_setg(errp, "vfu: Unsupported socket type - %s",
138                    SocketAddressType_str(o->socket->type));
139         qapi_free_SocketAddress(o->socket);
140         o->socket = NULL;
141         return;
142     }
143 
144     trace_vfu_prop("socket", o->socket->u.q_unix.path);
145 
146     vfu_object_init_ctx(o, errp);
147 }
148 
149 static void vfu_object_set_device(Object *obj, const char *str, Error **errp)
150 {
151     VfuObject *o = VFU_OBJECT(obj);
152 
153     if (o->vfu_ctx) {
154         error_setg(errp, "vfu: Unable to set device property - server busy");
155         return;
156     }
157 
158     g_free(o->device);
159 
160     o->device = g_strdup(str);
161 
162     trace_vfu_prop("device", str);
163 
164     vfu_object_init_ctx(o, errp);
165 }
166 
167 /*
168  * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device'
169  * properties. It also depends on devices instantiated in QEMU. These
170  * dependencies are not available during the instance_init phase of this
171  * object's life-cycle. As such, the server is initialized after the
172  * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT
173  * when the machine is setup, and the dependencies are available.
174  */
175 static void vfu_object_machine_done(Notifier *notifier, void *data)
176 {
177     VfuObject *o = container_of(notifier, VfuObject, machine_done);
178     Error *err = NULL;
179 
180     vfu_object_init_ctx(o, &err);
181 
182     if (err) {
183         error_propagate(&error_abort, err);
184     }
185 }
186 
187 static void vfu_object_init_ctx(VfuObject *o, Error **errp)
188 {
189     ERRP_GUARD();
190     DeviceState *dev = NULL;
191     vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL;
192     int ret;
193 
194     if (o->vfu_ctx || !o->socket || !o->device ||
195             !phase_check(PHASE_MACHINE_READY)) {
196         return;
197     }
198 
199     if (o->err) {
200         error_propagate(errp, o->err);
201         o->err = NULL;
202         return;
203     }
204 
205     o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, 0,
206                                 o, VFU_DEV_TYPE_PCI);
207     if (o->vfu_ctx == NULL) {
208         error_setg(errp, "vfu: Failed to create context - %s", strerror(errno));
209         return;
210     }
211 
212     dev = qdev_find_recursive(sysbus_get_default(), o->device);
213     if (dev == NULL) {
214         error_setg(errp, "vfu: Device %s not found", o->device);
215         goto fail;
216     }
217 
218     if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
219         error_setg(errp, "vfu: %s not a PCI device", o->device);
220         goto fail;
221     }
222 
223     o->pci_dev = PCI_DEVICE(dev);
224 
225     object_ref(OBJECT(o->pci_dev));
226 
227     if (pci_is_express(o->pci_dev)) {
228         pci_type = VFU_PCI_TYPE_EXPRESS;
229     }
230 
231     ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0);
232     if (ret < 0) {
233         error_setg(errp,
234                    "vfu: Failed to attach PCI device %s to context - %s",
235                    o->device, strerror(errno));
236         goto fail;
237     }
238 
239     error_setg(&o->unplug_blocker,
240                "vfu: %s for %s must be deleted before unplugging",
241                TYPE_VFU_OBJECT, o->device);
242     qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
243 
244     return;
245 
246 fail:
247     vfu_destroy_ctx(o->vfu_ctx);
248     if (o->unplug_blocker && o->pci_dev) {
249         qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
250         error_free(o->unplug_blocker);
251         o->unplug_blocker = NULL;
252     }
253     if (o->pci_dev) {
254         object_unref(OBJECT(o->pci_dev));
255         o->pci_dev = NULL;
256     }
257     o->vfu_ctx = NULL;
258 }
259 
260 static void vfu_object_init(Object *obj)
261 {
262     VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
263     VfuObject *o = VFU_OBJECT(obj);
264 
265     k->nr_devs++;
266 
267     if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) {
268         error_setg(&o->err, "vfu: %s only compatible with %s machine",
269                    TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE);
270         return;
271     }
272 
273     if (!phase_check(PHASE_MACHINE_READY)) {
274         o->machine_done.notify = vfu_object_machine_done;
275         qemu_add_machine_init_done_notifier(&o->machine_done);
276     }
277 
278 }
279 
280 static void vfu_object_finalize(Object *obj)
281 {
282     VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
283     VfuObject *o = VFU_OBJECT(obj);
284 
285     k->nr_devs--;
286 
287     qapi_free_SocketAddress(o->socket);
288 
289     o->socket = NULL;
290 
291     if (o->vfu_ctx) {
292         vfu_destroy_ctx(o->vfu_ctx);
293         o->vfu_ctx = NULL;
294     }
295 
296     g_free(o->device);
297 
298     o->device = NULL;
299 
300     if (o->unplug_blocker && o->pci_dev) {
301         qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
302         error_free(o->unplug_blocker);
303         o->unplug_blocker = NULL;
304     }
305 
306     if (o->pci_dev) {
307         object_unref(OBJECT(o->pci_dev));
308         o->pci_dev = NULL;
309     }
310 
311     if (!k->nr_devs && vfu_object_auto_shutdown()) {
312         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
313     }
314 
315     if (o->machine_done.notify) {
316         qemu_remove_machine_init_done_notifier(&o->machine_done);
317         o->machine_done.notify = NULL;
318     }
319 }
320 
321 static void vfu_object_class_init(ObjectClass *klass, void *data)
322 {
323     VfuObjectClass *k = VFU_OBJECT_CLASS(klass);
324 
325     k->nr_devs = 0;
326 
327     object_class_property_add(klass, "socket", "SocketAddress", NULL,
328                               vfu_object_set_socket, NULL, NULL);
329     object_class_property_set_description(klass, "socket",
330                                           "SocketAddress "
331                                           "(ex: type=unix,path=/tmp/sock). "
332                                           "Only UNIX is presently supported");
333     object_class_property_add_str(klass, "device", NULL,
334                                   vfu_object_set_device);
335     object_class_property_set_description(klass, "device",
336                                           "device ID - only PCI devices "
337                                           "are presently supported");
338 }
339 
340 static const TypeInfo vfu_object_info = {
341     .name = TYPE_VFU_OBJECT,
342     .parent = TYPE_OBJECT,
343     .instance_size = sizeof(VfuObject),
344     .instance_init = vfu_object_init,
345     .instance_finalize = vfu_object_finalize,
346     .class_size = sizeof(VfuObjectClass),
347     .class_init = vfu_object_class_init,
348     .interfaces = (InterfaceInfo[]) {
349         { TYPE_USER_CREATABLE },
350         { }
351     }
352 };
353 
354 static void vfu_register_types(void)
355 {
356     type_register_static(&vfu_object_info);
357 }
358 
359 type_init(vfu_register_types);
360