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