xref: /qemu/hw/remote/vfio-user-obj.c (revision 9fb3fba14953958944aea18f7a5720456b7fac8f)
18f9a9259SJagannathan Raman /**
28f9a9259SJagannathan Raman  * QEMU vfio-user-server server object
38f9a9259SJagannathan Raman  *
48f9a9259SJagannathan Raman  * Copyright © 2022 Oracle and/or its affiliates.
58f9a9259SJagannathan Raman  *
68f9a9259SJagannathan Raman  * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
78f9a9259SJagannathan Raman  *
88f9a9259SJagannathan Raman  * See the COPYING file in the top-level directory.
98f9a9259SJagannathan Raman  *
108f9a9259SJagannathan Raman  */
118f9a9259SJagannathan Raman 
128f9a9259SJagannathan Raman /**
138f9a9259SJagannathan Raman  * Usage: add options:
148f9a9259SJagannathan Raman  *     -machine x-remote,vfio-user=on,auto-shutdown=on
158f9a9259SJagannathan Raman  *     -device <PCI-device>,id=<pci-dev-id>
168f9a9259SJagannathan Raman  *     -object x-vfio-user-server,id=<id>,type=unix,path=<socket-path>,
178f9a9259SJagannathan Raman  *             device=<pci-dev-id>
188f9a9259SJagannathan Raman  *
198f9a9259SJagannathan Raman  * Note that x-vfio-user-server object must be used with x-remote machine only.
208f9a9259SJagannathan Raman  * This server could only support PCI devices for now.
218f9a9259SJagannathan Raman  *
228f9a9259SJagannathan Raman  * type - SocketAddress type - presently "unix" alone is supported. Required
238f9a9259SJagannathan Raman  *        option
248f9a9259SJagannathan Raman  *
258f9a9259SJagannathan Raman  * path - named unix socket, it will be created by the server. It is
268f9a9259SJagannathan Raman  *        a required option
278f9a9259SJagannathan Raman  *
288f9a9259SJagannathan Raman  * device - id of a device on the server, a required option. PCI devices
298f9a9259SJagannathan Raman  *          alone are supported presently.
30*9fb3fba1SJagannathan Raman  *
31*9fb3fba1SJagannathan Raman  * notes - x-vfio-user-server could block IO and monitor during the
32*9fb3fba1SJagannathan Raman  *         initialization phase.
338f9a9259SJagannathan Raman  */
348f9a9259SJagannathan Raman 
358f9a9259SJagannathan Raman #include "qemu/osdep.h"
368f9a9259SJagannathan Raman 
378f9a9259SJagannathan Raman #include "qom/object.h"
388f9a9259SJagannathan Raman #include "qom/object_interfaces.h"
398f9a9259SJagannathan Raman #include "qemu/error-report.h"
408f9a9259SJagannathan Raman #include "trace.h"
418f9a9259SJagannathan Raman #include "sysemu/runstate.h"
428f9a9259SJagannathan Raman #include "hw/boards.h"
438f9a9259SJagannathan Raman #include "hw/remote/machine.h"
448f9a9259SJagannathan Raman #include "qapi/error.h"
458f9a9259SJagannathan Raman #include "qapi/qapi-visit-sockets.h"
46*9fb3fba1SJagannathan Raman #include "qapi/qapi-events-misc.h"
4787f7249fSJagannathan Raman #include "qemu/notify.h"
48*9fb3fba1SJagannathan Raman #include "qemu/thread.h"
4987f7249fSJagannathan Raman #include "sysemu/sysemu.h"
5087f7249fSJagannathan Raman #include "libvfio-user.h"
51a6e8d6d9SJagannathan Raman #include "hw/qdev-core.h"
52a6e8d6d9SJagannathan Raman #include "hw/pci/pci.h"
53*9fb3fba1SJagannathan Raman #include "qemu/timer.h"
548f9a9259SJagannathan Raman 
558f9a9259SJagannathan Raman #define TYPE_VFU_OBJECT "x-vfio-user-server"
568f9a9259SJagannathan Raman OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT)
578f9a9259SJagannathan Raman 
588f9a9259SJagannathan Raman /**
598f9a9259SJagannathan Raman  * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown
608f9a9259SJagannathan Raman  * is set, it aborts the machine on error. Otherwise, it logs an
618f9a9259SJagannathan Raman  * error message without aborting.
628f9a9259SJagannathan Raman  */
638f9a9259SJagannathan Raman #define VFU_OBJECT_ERROR(o, fmt, ...)                                     \
648f9a9259SJagannathan Raman     {                                                                     \
658f9a9259SJagannathan Raman         if (vfu_object_auto_shutdown()) {                                 \
668f9a9259SJagannathan Raman             error_setg(&error_abort, (fmt), ## __VA_ARGS__);              \
678f9a9259SJagannathan Raman         } else {                                                          \
688f9a9259SJagannathan Raman             error_report((fmt), ## __VA_ARGS__);                          \
698f9a9259SJagannathan Raman         }                                                                 \
708f9a9259SJagannathan Raman     }                                                                     \
718f9a9259SJagannathan Raman 
728f9a9259SJagannathan Raman struct VfuObjectClass {
738f9a9259SJagannathan Raman     ObjectClass parent_class;
748f9a9259SJagannathan Raman 
758f9a9259SJagannathan Raman     unsigned int nr_devs;
768f9a9259SJagannathan Raman };
778f9a9259SJagannathan Raman 
788f9a9259SJagannathan Raman struct VfuObject {
798f9a9259SJagannathan Raman     /* private */
808f9a9259SJagannathan Raman     Object parent;
818f9a9259SJagannathan Raman 
828f9a9259SJagannathan Raman     SocketAddress *socket;
838f9a9259SJagannathan Raman 
848f9a9259SJagannathan Raman     char *device;
858f9a9259SJagannathan Raman 
868f9a9259SJagannathan Raman     Error *err;
8787f7249fSJagannathan Raman 
8887f7249fSJagannathan Raman     Notifier machine_done;
8987f7249fSJagannathan Raman 
9087f7249fSJagannathan Raman     vfu_ctx_t *vfu_ctx;
91a6e8d6d9SJagannathan Raman 
92a6e8d6d9SJagannathan Raman     PCIDevice *pci_dev;
93a6e8d6d9SJagannathan Raman 
94a6e8d6d9SJagannathan Raman     Error *unplug_blocker;
95*9fb3fba1SJagannathan Raman 
96*9fb3fba1SJagannathan Raman     int vfu_poll_fd;
978f9a9259SJagannathan Raman };
988f9a9259SJagannathan Raman 
9987f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp);
10087f7249fSJagannathan Raman 
1018f9a9259SJagannathan Raman static bool vfu_object_auto_shutdown(void)
1028f9a9259SJagannathan Raman {
1038f9a9259SJagannathan Raman     bool auto_shutdown = true;
1048f9a9259SJagannathan Raman     Error *local_err = NULL;
1058f9a9259SJagannathan Raman 
1068f9a9259SJagannathan Raman     if (!current_machine) {
1078f9a9259SJagannathan Raman         return auto_shutdown;
1088f9a9259SJagannathan Raman     }
1098f9a9259SJagannathan Raman 
1108f9a9259SJagannathan Raman     auto_shutdown = object_property_get_bool(OBJECT(current_machine),
1118f9a9259SJagannathan Raman                                              "auto-shutdown",
1128f9a9259SJagannathan Raman                                              &local_err);
1138f9a9259SJagannathan Raman 
1148f9a9259SJagannathan Raman     /*
1158f9a9259SJagannathan Raman      * local_err would be set if no such property exists - safe to ignore.
1168f9a9259SJagannathan Raman      * Unlikely scenario as auto-shutdown is always defined for
1178f9a9259SJagannathan Raman      * TYPE_REMOTE_MACHINE, and  TYPE_VFU_OBJECT only works with
1188f9a9259SJagannathan Raman      * TYPE_REMOTE_MACHINE
1198f9a9259SJagannathan Raman      */
1208f9a9259SJagannathan Raman     if (local_err) {
1218f9a9259SJagannathan Raman         auto_shutdown = true;
1228f9a9259SJagannathan Raman         error_free(local_err);
1238f9a9259SJagannathan Raman     }
1248f9a9259SJagannathan Raman 
1258f9a9259SJagannathan Raman     return auto_shutdown;
1268f9a9259SJagannathan Raman }
1278f9a9259SJagannathan Raman 
1288f9a9259SJagannathan Raman static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name,
1298f9a9259SJagannathan Raman                                   void *opaque, Error **errp)
1308f9a9259SJagannathan Raman {
1318f9a9259SJagannathan Raman     VfuObject *o = VFU_OBJECT(obj);
1328f9a9259SJagannathan Raman 
13387f7249fSJagannathan Raman     if (o->vfu_ctx) {
13487f7249fSJagannathan Raman         error_setg(errp, "vfu: Unable to set socket property - server busy");
13587f7249fSJagannathan Raman         return;
13687f7249fSJagannathan Raman     }
13787f7249fSJagannathan Raman 
1388f9a9259SJagannathan Raman     qapi_free_SocketAddress(o->socket);
1398f9a9259SJagannathan Raman 
1408f9a9259SJagannathan Raman     o->socket = NULL;
1418f9a9259SJagannathan Raman 
1428f9a9259SJagannathan Raman     visit_type_SocketAddress(v, name, &o->socket, errp);
1438f9a9259SJagannathan Raman 
1448f9a9259SJagannathan Raman     if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) {
1458f9a9259SJagannathan Raman         error_setg(errp, "vfu: Unsupported socket type - %s",
1468f9a9259SJagannathan Raman                    SocketAddressType_str(o->socket->type));
1478f9a9259SJagannathan Raman         qapi_free_SocketAddress(o->socket);
1488f9a9259SJagannathan Raman         o->socket = NULL;
1498f9a9259SJagannathan Raman         return;
1508f9a9259SJagannathan Raman     }
1518f9a9259SJagannathan Raman 
1528f9a9259SJagannathan Raman     trace_vfu_prop("socket", o->socket->u.q_unix.path);
15387f7249fSJagannathan Raman 
15487f7249fSJagannathan Raman     vfu_object_init_ctx(o, errp);
1558f9a9259SJagannathan Raman }
1568f9a9259SJagannathan Raman 
1578f9a9259SJagannathan Raman static void vfu_object_set_device(Object *obj, const char *str, Error **errp)
1588f9a9259SJagannathan Raman {
1598f9a9259SJagannathan Raman     VfuObject *o = VFU_OBJECT(obj);
1608f9a9259SJagannathan Raman 
16187f7249fSJagannathan Raman     if (o->vfu_ctx) {
16287f7249fSJagannathan Raman         error_setg(errp, "vfu: Unable to set device property - server busy");
16387f7249fSJagannathan Raman         return;
16487f7249fSJagannathan Raman     }
16587f7249fSJagannathan Raman 
1668f9a9259SJagannathan Raman     g_free(o->device);
1678f9a9259SJagannathan Raman 
1688f9a9259SJagannathan Raman     o->device = g_strdup(str);
1698f9a9259SJagannathan Raman 
1708f9a9259SJagannathan Raman     trace_vfu_prop("device", str);
17187f7249fSJagannathan Raman 
17287f7249fSJagannathan Raman     vfu_object_init_ctx(o, errp);
17387f7249fSJagannathan Raman }
17487f7249fSJagannathan Raman 
175*9fb3fba1SJagannathan Raman static void vfu_object_ctx_run(void *opaque)
176*9fb3fba1SJagannathan Raman {
177*9fb3fba1SJagannathan Raman     VfuObject *o = opaque;
178*9fb3fba1SJagannathan Raman     const char *vfu_id;
179*9fb3fba1SJagannathan Raman     char *vfu_path, *pci_dev_path;
180*9fb3fba1SJagannathan Raman     int ret = -1;
181*9fb3fba1SJagannathan Raman 
182*9fb3fba1SJagannathan Raman     while (ret != 0) {
183*9fb3fba1SJagannathan Raman         ret = vfu_run_ctx(o->vfu_ctx);
184*9fb3fba1SJagannathan Raman         if (ret < 0) {
185*9fb3fba1SJagannathan Raman             if (errno == EINTR) {
186*9fb3fba1SJagannathan Raman                 continue;
187*9fb3fba1SJagannathan Raman             } else if (errno == ENOTCONN) {
188*9fb3fba1SJagannathan Raman                 vfu_id = object_get_canonical_path_component(OBJECT(o));
189*9fb3fba1SJagannathan Raman                 vfu_path = object_get_canonical_path(OBJECT(o));
190*9fb3fba1SJagannathan Raman                 g_assert(o->pci_dev);
191*9fb3fba1SJagannathan Raman                 pci_dev_path = object_get_canonical_path(OBJECT(o->pci_dev));
192*9fb3fba1SJagannathan Raman                  /* o->device is a required property and is non-NULL here */
193*9fb3fba1SJagannathan Raman                 g_assert(o->device);
194*9fb3fba1SJagannathan Raman                 qapi_event_send_vfu_client_hangup(vfu_id, vfu_path,
195*9fb3fba1SJagannathan Raman                                                   o->device, pci_dev_path);
196*9fb3fba1SJagannathan Raman                 qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
197*9fb3fba1SJagannathan Raman                 o->vfu_poll_fd = -1;
198*9fb3fba1SJagannathan Raman                 object_unparent(OBJECT(o));
199*9fb3fba1SJagannathan Raman                 g_free(vfu_path);
200*9fb3fba1SJagannathan Raman                 g_free(pci_dev_path);
201*9fb3fba1SJagannathan Raman                 break;
202*9fb3fba1SJagannathan Raman             } else {
203*9fb3fba1SJagannathan Raman                 VFU_OBJECT_ERROR(o, "vfu: Failed to run device %s - %s",
204*9fb3fba1SJagannathan Raman                                  o->device, strerror(errno));
205*9fb3fba1SJagannathan Raman                 break;
206*9fb3fba1SJagannathan Raman             }
207*9fb3fba1SJagannathan Raman         }
208*9fb3fba1SJagannathan Raman     }
209*9fb3fba1SJagannathan Raman }
210*9fb3fba1SJagannathan Raman 
211*9fb3fba1SJagannathan Raman static void vfu_object_attach_ctx(void *opaque)
212*9fb3fba1SJagannathan Raman {
213*9fb3fba1SJagannathan Raman     VfuObject *o = opaque;
214*9fb3fba1SJagannathan Raman     GPollFD pfds[1];
215*9fb3fba1SJagannathan Raman     int ret;
216*9fb3fba1SJagannathan Raman 
217*9fb3fba1SJagannathan Raman     qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
218*9fb3fba1SJagannathan Raman 
219*9fb3fba1SJagannathan Raman     pfds[0].fd = o->vfu_poll_fd;
220*9fb3fba1SJagannathan Raman     pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR;
221*9fb3fba1SJagannathan Raman 
222*9fb3fba1SJagannathan Raman retry_attach:
223*9fb3fba1SJagannathan Raman     ret = vfu_attach_ctx(o->vfu_ctx);
224*9fb3fba1SJagannathan Raman     if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
225*9fb3fba1SJagannathan Raman         /**
226*9fb3fba1SJagannathan Raman          * vfu_object_attach_ctx can block QEMU's main loop
227*9fb3fba1SJagannathan Raman          * during attach - the monitor and other IO
228*9fb3fba1SJagannathan Raman          * could be unresponsive during this time.
229*9fb3fba1SJagannathan Raman          */
230*9fb3fba1SJagannathan Raman         (void)qemu_poll_ns(pfds, 1, 500 * (int64_t)SCALE_MS);
231*9fb3fba1SJagannathan Raman         goto retry_attach;
232*9fb3fba1SJagannathan Raman     } else if (ret < 0) {
233*9fb3fba1SJagannathan Raman         VFU_OBJECT_ERROR(o, "vfu: Failed to attach device %s to context - %s",
234*9fb3fba1SJagannathan Raman                          o->device, strerror(errno));
235*9fb3fba1SJagannathan Raman         return;
236*9fb3fba1SJagannathan Raman     }
237*9fb3fba1SJagannathan Raman 
238*9fb3fba1SJagannathan Raman     o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx);
239*9fb3fba1SJagannathan Raman     if (o->vfu_poll_fd < 0) {
240*9fb3fba1SJagannathan Raman         VFU_OBJECT_ERROR(o, "vfu: Failed to get poll fd %s", o->device);
241*9fb3fba1SJagannathan Raman         return;
242*9fb3fba1SJagannathan Raman     }
243*9fb3fba1SJagannathan Raman 
244*9fb3fba1SJagannathan Raman     qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_ctx_run, NULL, o);
245*9fb3fba1SJagannathan Raman }
246*9fb3fba1SJagannathan Raman 
24787f7249fSJagannathan Raman /*
24887f7249fSJagannathan Raman  * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device'
24987f7249fSJagannathan Raman  * properties. It also depends on devices instantiated in QEMU. These
25087f7249fSJagannathan Raman  * dependencies are not available during the instance_init phase of this
25187f7249fSJagannathan Raman  * object's life-cycle. As such, the server is initialized after the
25287f7249fSJagannathan Raman  * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT
25387f7249fSJagannathan Raman  * when the machine is setup, and the dependencies are available.
25487f7249fSJagannathan Raman  */
25587f7249fSJagannathan Raman static void vfu_object_machine_done(Notifier *notifier, void *data)
25687f7249fSJagannathan Raman {
25787f7249fSJagannathan Raman     VfuObject *o = container_of(notifier, VfuObject, machine_done);
25887f7249fSJagannathan Raman     Error *err = NULL;
25987f7249fSJagannathan Raman 
26087f7249fSJagannathan Raman     vfu_object_init_ctx(o, &err);
26187f7249fSJagannathan Raman 
26287f7249fSJagannathan Raman     if (err) {
26387f7249fSJagannathan Raman         error_propagate(&error_abort, err);
26487f7249fSJagannathan Raman     }
26587f7249fSJagannathan Raman }
26687f7249fSJagannathan Raman 
267*9fb3fba1SJagannathan Raman /**
268*9fb3fba1SJagannathan Raman  * vfu_object_init_ctx: Create and initialize libvfio-user context. Add
269*9fb3fba1SJagannathan Raman  *     an unplug blocker for the associated PCI device. Setup a FD handler
270*9fb3fba1SJagannathan Raman  *     to process incoming messages in the context's socket.
271*9fb3fba1SJagannathan Raman  *
272*9fb3fba1SJagannathan Raman  *     The socket and device properties are mandatory, and this function
273*9fb3fba1SJagannathan Raman  *     will not create the context without them - the setters for these
274*9fb3fba1SJagannathan Raman  *     properties should call this function when the property is set. The
275*9fb3fba1SJagannathan Raman  *     machine should also be ready when this function is invoked - it is
276*9fb3fba1SJagannathan Raman  *     because QEMU objects are initialized before devices, and the
277*9fb3fba1SJagannathan Raman  *     associated PCI device wouldn't be available at the object
278*9fb3fba1SJagannathan Raman  *     initialization time. Until these conditions are satisfied, this
279*9fb3fba1SJagannathan Raman  *     function would return early without performing any task.
280*9fb3fba1SJagannathan Raman  */
28187f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp)
28287f7249fSJagannathan Raman {
28387f7249fSJagannathan Raman     ERRP_GUARD();
284a6e8d6d9SJagannathan Raman     DeviceState *dev = NULL;
285a6e8d6d9SJagannathan Raman     vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL;
286a6e8d6d9SJagannathan Raman     int ret;
28787f7249fSJagannathan Raman 
28887f7249fSJagannathan Raman     if (o->vfu_ctx || !o->socket || !o->device ||
28987f7249fSJagannathan Raman             !phase_check(PHASE_MACHINE_READY)) {
29087f7249fSJagannathan Raman         return;
29187f7249fSJagannathan Raman     }
29287f7249fSJagannathan Raman 
29387f7249fSJagannathan Raman     if (o->err) {
29487f7249fSJagannathan Raman         error_propagate(errp, o->err);
29587f7249fSJagannathan Raman         o->err = NULL;
29687f7249fSJagannathan Raman         return;
29787f7249fSJagannathan Raman     }
29887f7249fSJagannathan Raman 
299*9fb3fba1SJagannathan Raman     o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path,
300*9fb3fba1SJagannathan Raman                                 LIBVFIO_USER_FLAG_ATTACH_NB,
30187f7249fSJagannathan Raman                                 o, VFU_DEV_TYPE_PCI);
30287f7249fSJagannathan Raman     if (o->vfu_ctx == NULL) {
30387f7249fSJagannathan Raman         error_setg(errp, "vfu: Failed to create context - %s", strerror(errno));
30487f7249fSJagannathan Raman         return;
30587f7249fSJagannathan Raman     }
306a6e8d6d9SJagannathan Raman 
307a6e8d6d9SJagannathan Raman     dev = qdev_find_recursive(sysbus_get_default(), o->device);
308a6e8d6d9SJagannathan Raman     if (dev == NULL) {
309a6e8d6d9SJagannathan Raman         error_setg(errp, "vfu: Device %s not found", o->device);
310a6e8d6d9SJagannathan Raman         goto fail;
311a6e8d6d9SJagannathan Raman     }
312a6e8d6d9SJagannathan Raman 
313a6e8d6d9SJagannathan Raman     if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
314a6e8d6d9SJagannathan Raman         error_setg(errp, "vfu: %s not a PCI device", o->device);
315a6e8d6d9SJagannathan Raman         goto fail;
316a6e8d6d9SJagannathan Raman     }
317a6e8d6d9SJagannathan Raman 
318a6e8d6d9SJagannathan Raman     o->pci_dev = PCI_DEVICE(dev);
319a6e8d6d9SJagannathan Raman 
320a6e8d6d9SJagannathan Raman     object_ref(OBJECT(o->pci_dev));
321a6e8d6d9SJagannathan Raman 
322a6e8d6d9SJagannathan Raman     if (pci_is_express(o->pci_dev)) {
323a6e8d6d9SJagannathan Raman         pci_type = VFU_PCI_TYPE_EXPRESS;
324a6e8d6d9SJagannathan Raman     }
325a6e8d6d9SJagannathan Raman 
326a6e8d6d9SJagannathan Raman     ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0);
327a6e8d6d9SJagannathan Raman     if (ret < 0) {
328a6e8d6d9SJagannathan Raman         error_setg(errp,
329a6e8d6d9SJagannathan Raman                    "vfu: Failed to attach PCI device %s to context - %s",
330a6e8d6d9SJagannathan Raman                    o->device, strerror(errno));
331a6e8d6d9SJagannathan Raman         goto fail;
332a6e8d6d9SJagannathan Raman     }
333a6e8d6d9SJagannathan Raman 
334a6e8d6d9SJagannathan Raman     error_setg(&o->unplug_blocker,
335a6e8d6d9SJagannathan Raman                "vfu: %s for %s must be deleted before unplugging",
336a6e8d6d9SJagannathan Raman                TYPE_VFU_OBJECT, o->device);
337a6e8d6d9SJagannathan Raman     qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
338a6e8d6d9SJagannathan Raman 
339*9fb3fba1SJagannathan Raman     ret = vfu_realize_ctx(o->vfu_ctx);
340*9fb3fba1SJagannathan Raman     if (ret < 0) {
341*9fb3fba1SJagannathan Raman         error_setg(errp, "vfu: Failed to realize device %s- %s",
342*9fb3fba1SJagannathan Raman                    o->device, strerror(errno));
343*9fb3fba1SJagannathan Raman         goto fail;
344*9fb3fba1SJagannathan Raman     }
345*9fb3fba1SJagannathan Raman 
346*9fb3fba1SJagannathan Raman     o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx);
347*9fb3fba1SJagannathan Raman     if (o->vfu_poll_fd < 0) {
348*9fb3fba1SJagannathan Raman         error_setg(errp, "vfu: Failed to get poll fd %s", o->device);
349*9fb3fba1SJagannathan Raman         goto fail;
350*9fb3fba1SJagannathan Raman     }
351*9fb3fba1SJagannathan Raman 
352*9fb3fba1SJagannathan Raman     qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o);
353*9fb3fba1SJagannathan Raman 
354a6e8d6d9SJagannathan Raman     return;
355a6e8d6d9SJagannathan Raman 
356a6e8d6d9SJagannathan Raman fail:
357a6e8d6d9SJagannathan Raman     vfu_destroy_ctx(o->vfu_ctx);
358a6e8d6d9SJagannathan Raman     if (o->unplug_blocker && o->pci_dev) {
359a6e8d6d9SJagannathan Raman         qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
360a6e8d6d9SJagannathan Raman         error_free(o->unplug_blocker);
361a6e8d6d9SJagannathan Raman         o->unplug_blocker = NULL;
362a6e8d6d9SJagannathan Raman     }
363a6e8d6d9SJagannathan Raman     if (o->pci_dev) {
364a6e8d6d9SJagannathan Raman         object_unref(OBJECT(o->pci_dev));
365a6e8d6d9SJagannathan Raman         o->pci_dev = NULL;
366a6e8d6d9SJagannathan Raman     }
367a6e8d6d9SJagannathan Raman     o->vfu_ctx = NULL;
3688f9a9259SJagannathan Raman }
3698f9a9259SJagannathan Raman 
3708f9a9259SJagannathan Raman static void vfu_object_init(Object *obj)
3718f9a9259SJagannathan Raman {
3728f9a9259SJagannathan Raman     VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
3738f9a9259SJagannathan Raman     VfuObject *o = VFU_OBJECT(obj);
3748f9a9259SJagannathan Raman 
3758f9a9259SJagannathan Raman     k->nr_devs++;
3768f9a9259SJagannathan Raman 
3778f9a9259SJagannathan Raman     if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) {
3788f9a9259SJagannathan Raman         error_setg(&o->err, "vfu: %s only compatible with %s machine",
3798f9a9259SJagannathan Raman                    TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE);
3808f9a9259SJagannathan Raman         return;
3818f9a9259SJagannathan Raman     }
38287f7249fSJagannathan Raman 
38387f7249fSJagannathan Raman     if (!phase_check(PHASE_MACHINE_READY)) {
38487f7249fSJagannathan Raman         o->machine_done.notify = vfu_object_machine_done;
38587f7249fSJagannathan Raman         qemu_add_machine_init_done_notifier(&o->machine_done);
38687f7249fSJagannathan Raman     }
38787f7249fSJagannathan Raman 
388*9fb3fba1SJagannathan Raman     o->vfu_poll_fd = -1;
3898f9a9259SJagannathan Raman }
3908f9a9259SJagannathan Raman 
3918f9a9259SJagannathan Raman static void vfu_object_finalize(Object *obj)
3928f9a9259SJagannathan Raman {
3938f9a9259SJagannathan Raman     VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj);
3948f9a9259SJagannathan Raman     VfuObject *o = VFU_OBJECT(obj);
3958f9a9259SJagannathan Raman 
3968f9a9259SJagannathan Raman     k->nr_devs--;
3978f9a9259SJagannathan Raman 
3988f9a9259SJagannathan Raman     qapi_free_SocketAddress(o->socket);
3998f9a9259SJagannathan Raman 
4008f9a9259SJagannathan Raman     o->socket = NULL;
4018f9a9259SJagannathan Raman 
402*9fb3fba1SJagannathan Raman     if (o->vfu_poll_fd != -1) {
403*9fb3fba1SJagannathan Raman         qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL);
404*9fb3fba1SJagannathan Raman         o->vfu_poll_fd = -1;
405*9fb3fba1SJagannathan Raman     }
406*9fb3fba1SJagannathan Raman 
40787f7249fSJagannathan Raman     if (o->vfu_ctx) {
40887f7249fSJagannathan Raman         vfu_destroy_ctx(o->vfu_ctx);
40987f7249fSJagannathan Raman         o->vfu_ctx = NULL;
41087f7249fSJagannathan Raman     }
41187f7249fSJagannathan Raman 
4128f9a9259SJagannathan Raman     g_free(o->device);
4138f9a9259SJagannathan Raman 
4148f9a9259SJagannathan Raman     o->device = NULL;
4158f9a9259SJagannathan Raman 
416a6e8d6d9SJagannathan Raman     if (o->unplug_blocker && o->pci_dev) {
417a6e8d6d9SJagannathan Raman         qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker);
418a6e8d6d9SJagannathan Raman         error_free(o->unplug_blocker);
419a6e8d6d9SJagannathan Raman         o->unplug_blocker = NULL;
420a6e8d6d9SJagannathan Raman     }
421a6e8d6d9SJagannathan Raman 
422a6e8d6d9SJagannathan Raman     if (o->pci_dev) {
423a6e8d6d9SJagannathan Raman         object_unref(OBJECT(o->pci_dev));
424a6e8d6d9SJagannathan Raman         o->pci_dev = NULL;
425a6e8d6d9SJagannathan Raman     }
426a6e8d6d9SJagannathan Raman 
4278f9a9259SJagannathan Raman     if (!k->nr_devs && vfu_object_auto_shutdown()) {
4288f9a9259SJagannathan Raman         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
4298f9a9259SJagannathan Raman     }
43087f7249fSJagannathan Raman 
43187f7249fSJagannathan Raman     if (o->machine_done.notify) {
43287f7249fSJagannathan Raman         qemu_remove_machine_init_done_notifier(&o->machine_done);
43387f7249fSJagannathan Raman         o->machine_done.notify = NULL;
43487f7249fSJagannathan Raman     }
4358f9a9259SJagannathan Raman }
4368f9a9259SJagannathan Raman 
4378f9a9259SJagannathan Raman static void vfu_object_class_init(ObjectClass *klass, void *data)
4388f9a9259SJagannathan Raman {
4398f9a9259SJagannathan Raman     VfuObjectClass *k = VFU_OBJECT_CLASS(klass);
4408f9a9259SJagannathan Raman 
4418f9a9259SJagannathan Raman     k->nr_devs = 0;
4428f9a9259SJagannathan Raman 
4438f9a9259SJagannathan Raman     object_class_property_add(klass, "socket", "SocketAddress", NULL,
4448f9a9259SJagannathan Raman                               vfu_object_set_socket, NULL, NULL);
4458f9a9259SJagannathan Raman     object_class_property_set_description(klass, "socket",
4468f9a9259SJagannathan Raman                                           "SocketAddress "
4478f9a9259SJagannathan Raman                                           "(ex: type=unix,path=/tmp/sock). "
4488f9a9259SJagannathan Raman                                           "Only UNIX is presently supported");
4498f9a9259SJagannathan Raman     object_class_property_add_str(klass, "device", NULL,
4508f9a9259SJagannathan Raman                                   vfu_object_set_device);
4518f9a9259SJagannathan Raman     object_class_property_set_description(klass, "device",
4528f9a9259SJagannathan Raman                                           "device ID - only PCI devices "
4538f9a9259SJagannathan Raman                                           "are presently supported");
4548f9a9259SJagannathan Raman }
4558f9a9259SJagannathan Raman 
4568f9a9259SJagannathan Raman static const TypeInfo vfu_object_info = {
4578f9a9259SJagannathan Raman     .name = TYPE_VFU_OBJECT,
4588f9a9259SJagannathan Raman     .parent = TYPE_OBJECT,
4598f9a9259SJagannathan Raman     .instance_size = sizeof(VfuObject),
4608f9a9259SJagannathan Raman     .instance_init = vfu_object_init,
4618f9a9259SJagannathan Raman     .instance_finalize = vfu_object_finalize,
4628f9a9259SJagannathan Raman     .class_size = sizeof(VfuObjectClass),
4638f9a9259SJagannathan Raman     .class_init = vfu_object_class_init,
4648f9a9259SJagannathan Raman     .interfaces = (InterfaceInfo[]) {
4658f9a9259SJagannathan Raman         { TYPE_USER_CREATABLE },
4668f9a9259SJagannathan Raman         { }
4678f9a9259SJagannathan Raman     }
4688f9a9259SJagannathan Raman };
4698f9a9259SJagannathan Raman 
4708f9a9259SJagannathan Raman static void vfu_register_types(void)
4718f9a9259SJagannathan Raman {
4728f9a9259SJagannathan Raman     type_register_static(&vfu_object_info);
4738f9a9259SJagannathan Raman }
4748f9a9259SJagannathan Raman 
4758f9a9259SJagannathan Raman type_init(vfu_register_types);
476