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. 309fb3fba1SJagannathan Raman * 319fb3fba1SJagannathan Raman * notes - x-vfio-user-server could block IO and monitor during the 329fb3fba1SJagannathan 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" 469fb3fba1SJagannathan Raman #include "qapi/qapi-events-misc.h" 4787f7249fSJagannathan Raman #include "qemu/notify.h" 489fb3fba1SJagannathan Raman #include "qemu/thread.h" 49*90072f29SJagannathan Raman #include "qemu/main-loop.h" 5087f7249fSJagannathan Raman #include "sysemu/sysemu.h" 5187f7249fSJagannathan Raman #include "libvfio-user.h" 52a6e8d6d9SJagannathan Raman #include "hw/qdev-core.h" 53a6e8d6d9SJagannathan Raman #include "hw/pci/pci.h" 549fb3fba1SJagannathan Raman #include "qemu/timer.h" 558f9a9259SJagannathan Raman 568f9a9259SJagannathan Raman #define TYPE_VFU_OBJECT "x-vfio-user-server" 578f9a9259SJagannathan Raman OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) 588f9a9259SJagannathan Raman 598f9a9259SJagannathan Raman /** 608f9a9259SJagannathan Raman * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown 618f9a9259SJagannathan Raman * is set, it aborts the machine on error. Otherwise, it logs an 628f9a9259SJagannathan Raman * error message without aborting. 638f9a9259SJagannathan Raman */ 648f9a9259SJagannathan Raman #define VFU_OBJECT_ERROR(o, fmt, ...) \ 658f9a9259SJagannathan Raman { \ 668f9a9259SJagannathan Raman if (vfu_object_auto_shutdown()) { \ 678f9a9259SJagannathan Raman error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ 688f9a9259SJagannathan Raman } else { \ 698f9a9259SJagannathan Raman error_report((fmt), ## __VA_ARGS__); \ 708f9a9259SJagannathan Raman } \ 718f9a9259SJagannathan Raman } \ 728f9a9259SJagannathan Raman 738f9a9259SJagannathan Raman struct VfuObjectClass { 748f9a9259SJagannathan Raman ObjectClass parent_class; 758f9a9259SJagannathan Raman 768f9a9259SJagannathan Raman unsigned int nr_devs; 778f9a9259SJagannathan Raman }; 788f9a9259SJagannathan Raman 798f9a9259SJagannathan Raman struct VfuObject { 808f9a9259SJagannathan Raman /* private */ 818f9a9259SJagannathan Raman Object parent; 828f9a9259SJagannathan Raman 838f9a9259SJagannathan Raman SocketAddress *socket; 848f9a9259SJagannathan Raman 858f9a9259SJagannathan Raman char *device; 868f9a9259SJagannathan Raman 878f9a9259SJagannathan Raman Error *err; 8887f7249fSJagannathan Raman 8987f7249fSJagannathan Raman Notifier machine_done; 9087f7249fSJagannathan Raman 9187f7249fSJagannathan Raman vfu_ctx_t *vfu_ctx; 92a6e8d6d9SJagannathan Raman 93a6e8d6d9SJagannathan Raman PCIDevice *pci_dev; 94a6e8d6d9SJagannathan Raman 95a6e8d6d9SJagannathan Raman Error *unplug_blocker; 969fb3fba1SJagannathan Raman 979fb3fba1SJagannathan Raman int vfu_poll_fd; 988f9a9259SJagannathan Raman }; 998f9a9259SJagannathan Raman 10087f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp); 10187f7249fSJagannathan Raman 1028f9a9259SJagannathan Raman static bool vfu_object_auto_shutdown(void) 1038f9a9259SJagannathan Raman { 1048f9a9259SJagannathan Raman bool auto_shutdown = true; 1058f9a9259SJagannathan Raman Error *local_err = NULL; 1068f9a9259SJagannathan Raman 1078f9a9259SJagannathan Raman if (!current_machine) { 1088f9a9259SJagannathan Raman return auto_shutdown; 1098f9a9259SJagannathan Raman } 1108f9a9259SJagannathan Raman 1118f9a9259SJagannathan Raman auto_shutdown = object_property_get_bool(OBJECT(current_machine), 1128f9a9259SJagannathan Raman "auto-shutdown", 1138f9a9259SJagannathan Raman &local_err); 1148f9a9259SJagannathan Raman 1158f9a9259SJagannathan Raman /* 1168f9a9259SJagannathan Raman * local_err would be set if no such property exists - safe to ignore. 1178f9a9259SJagannathan Raman * Unlikely scenario as auto-shutdown is always defined for 1188f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with 1198f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE 1208f9a9259SJagannathan Raman */ 1218f9a9259SJagannathan Raman if (local_err) { 1228f9a9259SJagannathan Raman auto_shutdown = true; 1238f9a9259SJagannathan Raman error_free(local_err); 1248f9a9259SJagannathan Raman } 1258f9a9259SJagannathan Raman 1268f9a9259SJagannathan Raman return auto_shutdown; 1278f9a9259SJagannathan Raman } 1288f9a9259SJagannathan Raman 1298f9a9259SJagannathan Raman static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, 1308f9a9259SJagannathan Raman void *opaque, Error **errp) 1318f9a9259SJagannathan Raman { 1328f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 1338f9a9259SJagannathan Raman 13487f7249fSJagannathan Raman if (o->vfu_ctx) { 13587f7249fSJagannathan Raman error_setg(errp, "vfu: Unable to set socket property - server busy"); 13687f7249fSJagannathan Raman return; 13787f7249fSJagannathan Raman } 13887f7249fSJagannathan Raman 1398f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 1408f9a9259SJagannathan Raman 1418f9a9259SJagannathan Raman o->socket = NULL; 1428f9a9259SJagannathan Raman 1438f9a9259SJagannathan Raman visit_type_SocketAddress(v, name, &o->socket, errp); 1448f9a9259SJagannathan Raman 1458f9a9259SJagannathan Raman if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 1468f9a9259SJagannathan Raman error_setg(errp, "vfu: Unsupported socket type - %s", 1478f9a9259SJagannathan Raman SocketAddressType_str(o->socket->type)); 1488f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 1498f9a9259SJagannathan Raman o->socket = NULL; 1508f9a9259SJagannathan Raman return; 1518f9a9259SJagannathan Raman } 1528f9a9259SJagannathan Raman 1538f9a9259SJagannathan Raman trace_vfu_prop("socket", o->socket->u.q_unix.path); 15487f7249fSJagannathan Raman 15587f7249fSJagannathan Raman vfu_object_init_ctx(o, errp); 1568f9a9259SJagannathan Raman } 1578f9a9259SJagannathan Raman 1588f9a9259SJagannathan Raman static void vfu_object_set_device(Object *obj, const char *str, Error **errp) 1598f9a9259SJagannathan Raman { 1608f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 1618f9a9259SJagannathan Raman 16287f7249fSJagannathan Raman if (o->vfu_ctx) { 16387f7249fSJagannathan Raman error_setg(errp, "vfu: Unable to set device property - server busy"); 16487f7249fSJagannathan Raman return; 16587f7249fSJagannathan Raman } 16687f7249fSJagannathan Raman 1678f9a9259SJagannathan Raman g_free(o->device); 1688f9a9259SJagannathan Raman 1698f9a9259SJagannathan Raman o->device = g_strdup(str); 1708f9a9259SJagannathan Raman 1718f9a9259SJagannathan Raman trace_vfu_prop("device", str); 17287f7249fSJagannathan Raman 17387f7249fSJagannathan Raman vfu_object_init_ctx(o, errp); 17487f7249fSJagannathan Raman } 17587f7249fSJagannathan Raman 1769fb3fba1SJagannathan Raman static void vfu_object_ctx_run(void *opaque) 1779fb3fba1SJagannathan Raman { 1789fb3fba1SJagannathan Raman VfuObject *o = opaque; 1799fb3fba1SJagannathan Raman const char *vfu_id; 1809fb3fba1SJagannathan Raman char *vfu_path, *pci_dev_path; 1819fb3fba1SJagannathan Raman int ret = -1; 1829fb3fba1SJagannathan Raman 1839fb3fba1SJagannathan Raman while (ret != 0) { 1849fb3fba1SJagannathan Raman ret = vfu_run_ctx(o->vfu_ctx); 1859fb3fba1SJagannathan Raman if (ret < 0) { 1869fb3fba1SJagannathan Raman if (errno == EINTR) { 1879fb3fba1SJagannathan Raman continue; 1889fb3fba1SJagannathan Raman } else if (errno == ENOTCONN) { 1899fb3fba1SJagannathan Raman vfu_id = object_get_canonical_path_component(OBJECT(o)); 1909fb3fba1SJagannathan Raman vfu_path = object_get_canonical_path(OBJECT(o)); 1919fb3fba1SJagannathan Raman g_assert(o->pci_dev); 1929fb3fba1SJagannathan Raman pci_dev_path = object_get_canonical_path(OBJECT(o->pci_dev)); 1939fb3fba1SJagannathan Raman /* o->device is a required property and is non-NULL here */ 1949fb3fba1SJagannathan Raman g_assert(o->device); 1959fb3fba1SJagannathan Raman qapi_event_send_vfu_client_hangup(vfu_id, vfu_path, 1969fb3fba1SJagannathan Raman o->device, pci_dev_path); 1979fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 1989fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 1999fb3fba1SJagannathan Raman object_unparent(OBJECT(o)); 2009fb3fba1SJagannathan Raman g_free(vfu_path); 2019fb3fba1SJagannathan Raman g_free(pci_dev_path); 2029fb3fba1SJagannathan Raman break; 2039fb3fba1SJagannathan Raman } else { 2049fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to run device %s - %s", 2059fb3fba1SJagannathan Raman o->device, strerror(errno)); 2069fb3fba1SJagannathan Raman break; 2079fb3fba1SJagannathan Raman } 2089fb3fba1SJagannathan Raman } 2099fb3fba1SJagannathan Raman } 2109fb3fba1SJagannathan Raman } 2119fb3fba1SJagannathan Raman 2129fb3fba1SJagannathan Raman static void vfu_object_attach_ctx(void *opaque) 2139fb3fba1SJagannathan Raman { 2149fb3fba1SJagannathan Raman VfuObject *o = opaque; 2159fb3fba1SJagannathan Raman GPollFD pfds[1]; 2169fb3fba1SJagannathan Raman int ret; 2179fb3fba1SJagannathan Raman 2189fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 2199fb3fba1SJagannathan Raman 2209fb3fba1SJagannathan Raman pfds[0].fd = o->vfu_poll_fd; 2219fb3fba1SJagannathan Raman pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; 2229fb3fba1SJagannathan Raman 2239fb3fba1SJagannathan Raman retry_attach: 2249fb3fba1SJagannathan Raman ret = vfu_attach_ctx(o->vfu_ctx); 2259fb3fba1SJagannathan Raman if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 2269fb3fba1SJagannathan Raman /** 2279fb3fba1SJagannathan Raman * vfu_object_attach_ctx can block QEMU's main loop 2289fb3fba1SJagannathan Raman * during attach - the monitor and other IO 2299fb3fba1SJagannathan Raman * could be unresponsive during this time. 2309fb3fba1SJagannathan Raman */ 2319fb3fba1SJagannathan Raman (void)qemu_poll_ns(pfds, 1, 500 * (int64_t)SCALE_MS); 2329fb3fba1SJagannathan Raman goto retry_attach; 2339fb3fba1SJagannathan Raman } else if (ret < 0) { 2349fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to attach device %s to context - %s", 2359fb3fba1SJagannathan Raman o->device, strerror(errno)); 2369fb3fba1SJagannathan Raman return; 2379fb3fba1SJagannathan Raman } 2389fb3fba1SJagannathan Raman 2399fb3fba1SJagannathan Raman o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); 2409fb3fba1SJagannathan Raman if (o->vfu_poll_fd < 0) { 2419fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to get poll fd %s", o->device); 2429fb3fba1SJagannathan Raman return; 2439fb3fba1SJagannathan Raman } 2449fb3fba1SJagannathan Raman 2459fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_ctx_run, NULL, o); 2469fb3fba1SJagannathan Raman } 2479fb3fba1SJagannathan Raman 248*90072f29SJagannathan Raman static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf, 249*90072f29SJagannathan Raman size_t count, loff_t offset, 250*90072f29SJagannathan Raman const bool is_write) 251*90072f29SJagannathan Raman { 252*90072f29SJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 253*90072f29SJagannathan Raman uint32_t pci_access_width = sizeof(uint32_t); 254*90072f29SJagannathan Raman size_t bytes = count; 255*90072f29SJagannathan Raman uint32_t val = 0; 256*90072f29SJagannathan Raman char *ptr = buf; 257*90072f29SJagannathan Raman int len; 258*90072f29SJagannathan Raman 259*90072f29SJagannathan Raman /* 260*90072f29SJagannathan Raman * Writes to the BAR registers would trigger an update to the 261*90072f29SJagannathan Raman * global Memory and IO AddressSpaces. But the remote device 262*90072f29SJagannathan Raman * never uses the global AddressSpaces, therefore overlapping 263*90072f29SJagannathan Raman * memory regions are not a problem 264*90072f29SJagannathan Raman */ 265*90072f29SJagannathan Raman while (bytes > 0) { 266*90072f29SJagannathan Raman len = (bytes > pci_access_width) ? pci_access_width : bytes; 267*90072f29SJagannathan Raman if (is_write) { 268*90072f29SJagannathan Raman memcpy(&val, ptr, len); 269*90072f29SJagannathan Raman pci_host_config_write_common(o->pci_dev, offset, 270*90072f29SJagannathan Raman pci_config_size(o->pci_dev), 271*90072f29SJagannathan Raman val, len); 272*90072f29SJagannathan Raman trace_vfu_cfg_write(offset, val); 273*90072f29SJagannathan Raman } else { 274*90072f29SJagannathan Raman val = pci_host_config_read_common(o->pci_dev, offset, 275*90072f29SJagannathan Raman pci_config_size(o->pci_dev), len); 276*90072f29SJagannathan Raman memcpy(ptr, &val, len); 277*90072f29SJagannathan Raman trace_vfu_cfg_read(offset, val); 278*90072f29SJagannathan Raman } 279*90072f29SJagannathan Raman offset += len; 280*90072f29SJagannathan Raman ptr += len; 281*90072f29SJagannathan Raman bytes -= len; 282*90072f29SJagannathan Raman } 283*90072f29SJagannathan Raman 284*90072f29SJagannathan Raman return count; 285*90072f29SJagannathan Raman } 286*90072f29SJagannathan Raman 28787f7249fSJagannathan Raman /* 28887f7249fSJagannathan Raman * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device' 28987f7249fSJagannathan Raman * properties. It also depends on devices instantiated in QEMU. These 29087f7249fSJagannathan Raman * dependencies are not available during the instance_init phase of this 29187f7249fSJagannathan Raman * object's life-cycle. As such, the server is initialized after the 29287f7249fSJagannathan Raman * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT 29387f7249fSJagannathan Raman * when the machine is setup, and the dependencies are available. 29487f7249fSJagannathan Raman */ 29587f7249fSJagannathan Raman static void vfu_object_machine_done(Notifier *notifier, void *data) 29687f7249fSJagannathan Raman { 29787f7249fSJagannathan Raman VfuObject *o = container_of(notifier, VfuObject, machine_done); 29887f7249fSJagannathan Raman Error *err = NULL; 29987f7249fSJagannathan Raman 30087f7249fSJagannathan Raman vfu_object_init_ctx(o, &err); 30187f7249fSJagannathan Raman 30287f7249fSJagannathan Raman if (err) { 30387f7249fSJagannathan Raman error_propagate(&error_abort, err); 30487f7249fSJagannathan Raman } 30587f7249fSJagannathan Raman } 30687f7249fSJagannathan Raman 3079fb3fba1SJagannathan Raman /** 3089fb3fba1SJagannathan Raman * vfu_object_init_ctx: Create and initialize libvfio-user context. Add 3099fb3fba1SJagannathan Raman * an unplug blocker for the associated PCI device. Setup a FD handler 3109fb3fba1SJagannathan Raman * to process incoming messages in the context's socket. 3119fb3fba1SJagannathan Raman * 3129fb3fba1SJagannathan Raman * The socket and device properties are mandatory, and this function 3139fb3fba1SJagannathan Raman * will not create the context without them - the setters for these 3149fb3fba1SJagannathan Raman * properties should call this function when the property is set. The 3159fb3fba1SJagannathan Raman * machine should also be ready when this function is invoked - it is 3169fb3fba1SJagannathan Raman * because QEMU objects are initialized before devices, and the 3179fb3fba1SJagannathan Raman * associated PCI device wouldn't be available at the object 3189fb3fba1SJagannathan Raman * initialization time. Until these conditions are satisfied, this 3199fb3fba1SJagannathan Raman * function would return early without performing any task. 3209fb3fba1SJagannathan Raman */ 32187f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp) 32287f7249fSJagannathan Raman { 32387f7249fSJagannathan Raman ERRP_GUARD(); 324a6e8d6d9SJagannathan Raman DeviceState *dev = NULL; 325a6e8d6d9SJagannathan Raman vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL; 326a6e8d6d9SJagannathan Raman int ret; 32787f7249fSJagannathan Raman 32887f7249fSJagannathan Raman if (o->vfu_ctx || !o->socket || !o->device || 32987f7249fSJagannathan Raman !phase_check(PHASE_MACHINE_READY)) { 33087f7249fSJagannathan Raman return; 33187f7249fSJagannathan Raman } 33287f7249fSJagannathan Raman 33387f7249fSJagannathan Raman if (o->err) { 33487f7249fSJagannathan Raman error_propagate(errp, o->err); 33587f7249fSJagannathan Raman o->err = NULL; 33687f7249fSJagannathan Raman return; 33787f7249fSJagannathan Raman } 33887f7249fSJagannathan Raman 3399fb3fba1SJagannathan Raman o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, 3409fb3fba1SJagannathan Raman LIBVFIO_USER_FLAG_ATTACH_NB, 34187f7249fSJagannathan Raman o, VFU_DEV_TYPE_PCI); 34287f7249fSJagannathan Raman if (o->vfu_ctx == NULL) { 34387f7249fSJagannathan Raman error_setg(errp, "vfu: Failed to create context - %s", strerror(errno)); 34487f7249fSJagannathan Raman return; 34587f7249fSJagannathan Raman } 346a6e8d6d9SJagannathan Raman 347a6e8d6d9SJagannathan Raman dev = qdev_find_recursive(sysbus_get_default(), o->device); 348a6e8d6d9SJagannathan Raman if (dev == NULL) { 349a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: Device %s not found", o->device); 350a6e8d6d9SJagannathan Raman goto fail; 351a6e8d6d9SJagannathan Raman } 352a6e8d6d9SJagannathan Raman 353a6e8d6d9SJagannathan Raman if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 354a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: %s not a PCI device", o->device); 355a6e8d6d9SJagannathan Raman goto fail; 356a6e8d6d9SJagannathan Raman } 357a6e8d6d9SJagannathan Raman 358a6e8d6d9SJagannathan Raman o->pci_dev = PCI_DEVICE(dev); 359a6e8d6d9SJagannathan Raman 360a6e8d6d9SJagannathan Raman object_ref(OBJECT(o->pci_dev)); 361a6e8d6d9SJagannathan Raman 362a6e8d6d9SJagannathan Raman if (pci_is_express(o->pci_dev)) { 363a6e8d6d9SJagannathan Raman pci_type = VFU_PCI_TYPE_EXPRESS; 364a6e8d6d9SJagannathan Raman } 365a6e8d6d9SJagannathan Raman 366a6e8d6d9SJagannathan Raman ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0); 367a6e8d6d9SJagannathan Raman if (ret < 0) { 368a6e8d6d9SJagannathan Raman error_setg(errp, 369a6e8d6d9SJagannathan Raman "vfu: Failed to attach PCI device %s to context - %s", 370a6e8d6d9SJagannathan Raman o->device, strerror(errno)); 371a6e8d6d9SJagannathan Raman goto fail; 372a6e8d6d9SJagannathan Raman } 373a6e8d6d9SJagannathan Raman 374a6e8d6d9SJagannathan Raman error_setg(&o->unplug_blocker, 375a6e8d6d9SJagannathan Raman "vfu: %s for %s must be deleted before unplugging", 376a6e8d6d9SJagannathan Raman TYPE_VFU_OBJECT, o->device); 377a6e8d6d9SJagannathan Raman qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 378a6e8d6d9SJagannathan Raman 379*90072f29SJagannathan Raman ret = vfu_setup_region(o->vfu_ctx, VFU_PCI_DEV_CFG_REGION_IDX, 380*90072f29SJagannathan Raman pci_config_size(o->pci_dev), &vfu_object_cfg_access, 381*90072f29SJagannathan Raman VFU_REGION_FLAG_RW | VFU_REGION_FLAG_ALWAYS_CB, 382*90072f29SJagannathan Raman NULL, 0, -1, 0); 383*90072f29SJagannathan Raman if (ret < 0) { 384*90072f29SJagannathan Raman error_setg(errp, 385*90072f29SJagannathan Raman "vfu: Failed to setup config space handlers for %s- %s", 386*90072f29SJagannathan Raman o->device, strerror(errno)); 387*90072f29SJagannathan Raman goto fail; 388*90072f29SJagannathan Raman } 389*90072f29SJagannathan Raman 3909fb3fba1SJagannathan Raman ret = vfu_realize_ctx(o->vfu_ctx); 3919fb3fba1SJagannathan Raman if (ret < 0) { 3929fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to realize device %s- %s", 3939fb3fba1SJagannathan Raman o->device, strerror(errno)); 3949fb3fba1SJagannathan Raman goto fail; 3959fb3fba1SJagannathan Raman } 3969fb3fba1SJagannathan Raman 3979fb3fba1SJagannathan Raman o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); 3989fb3fba1SJagannathan Raman if (o->vfu_poll_fd < 0) { 3999fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to get poll fd %s", o->device); 4009fb3fba1SJagannathan Raman goto fail; 4019fb3fba1SJagannathan Raman } 4029fb3fba1SJagannathan Raman 4039fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o); 4049fb3fba1SJagannathan Raman 405a6e8d6d9SJagannathan Raman return; 406a6e8d6d9SJagannathan Raman 407a6e8d6d9SJagannathan Raman fail: 408a6e8d6d9SJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 409a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 410a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 411a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 412a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 413a6e8d6d9SJagannathan Raman } 414a6e8d6d9SJagannathan Raman if (o->pci_dev) { 415a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 416a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 417a6e8d6d9SJagannathan Raman } 418a6e8d6d9SJagannathan Raman o->vfu_ctx = NULL; 4198f9a9259SJagannathan Raman } 4208f9a9259SJagannathan Raman 4218f9a9259SJagannathan Raman static void vfu_object_init(Object *obj) 4228f9a9259SJagannathan Raman { 4238f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 4248f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 4258f9a9259SJagannathan Raman 4268f9a9259SJagannathan Raman k->nr_devs++; 4278f9a9259SJagannathan Raman 4288f9a9259SJagannathan Raman if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 4298f9a9259SJagannathan Raman error_setg(&o->err, "vfu: %s only compatible with %s machine", 4308f9a9259SJagannathan Raman TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 4318f9a9259SJagannathan Raman return; 4328f9a9259SJagannathan Raman } 43387f7249fSJagannathan Raman 43487f7249fSJagannathan Raman if (!phase_check(PHASE_MACHINE_READY)) { 43587f7249fSJagannathan Raman o->machine_done.notify = vfu_object_machine_done; 43687f7249fSJagannathan Raman qemu_add_machine_init_done_notifier(&o->machine_done); 43787f7249fSJagannathan Raman } 43887f7249fSJagannathan Raman 4399fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 4408f9a9259SJagannathan Raman } 4418f9a9259SJagannathan Raman 4428f9a9259SJagannathan Raman static void vfu_object_finalize(Object *obj) 4438f9a9259SJagannathan Raman { 4448f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 4458f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 4468f9a9259SJagannathan Raman 4478f9a9259SJagannathan Raman k->nr_devs--; 4488f9a9259SJagannathan Raman 4498f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 4508f9a9259SJagannathan Raman 4518f9a9259SJagannathan Raman o->socket = NULL; 4528f9a9259SJagannathan Raman 4539fb3fba1SJagannathan Raman if (o->vfu_poll_fd != -1) { 4549fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 4559fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 4569fb3fba1SJagannathan Raman } 4579fb3fba1SJagannathan Raman 45887f7249fSJagannathan Raman if (o->vfu_ctx) { 45987f7249fSJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 46087f7249fSJagannathan Raman o->vfu_ctx = NULL; 46187f7249fSJagannathan Raman } 46287f7249fSJagannathan Raman 4638f9a9259SJagannathan Raman g_free(o->device); 4648f9a9259SJagannathan Raman 4658f9a9259SJagannathan Raman o->device = NULL; 4668f9a9259SJagannathan Raman 467a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 468a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 469a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 470a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 471a6e8d6d9SJagannathan Raman } 472a6e8d6d9SJagannathan Raman 473a6e8d6d9SJagannathan Raman if (o->pci_dev) { 474a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 475a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 476a6e8d6d9SJagannathan Raman } 477a6e8d6d9SJagannathan Raman 4788f9a9259SJagannathan Raman if (!k->nr_devs && vfu_object_auto_shutdown()) { 4798f9a9259SJagannathan Raman qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 4808f9a9259SJagannathan Raman } 48187f7249fSJagannathan Raman 48287f7249fSJagannathan Raman if (o->machine_done.notify) { 48387f7249fSJagannathan Raman qemu_remove_machine_init_done_notifier(&o->machine_done); 48487f7249fSJagannathan Raman o->machine_done.notify = NULL; 48587f7249fSJagannathan Raman } 4868f9a9259SJagannathan Raman } 4878f9a9259SJagannathan Raman 4888f9a9259SJagannathan Raman static void vfu_object_class_init(ObjectClass *klass, void *data) 4898f9a9259SJagannathan Raman { 4908f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 4918f9a9259SJagannathan Raman 4928f9a9259SJagannathan Raman k->nr_devs = 0; 4938f9a9259SJagannathan Raman 4948f9a9259SJagannathan Raman object_class_property_add(klass, "socket", "SocketAddress", NULL, 4958f9a9259SJagannathan Raman vfu_object_set_socket, NULL, NULL); 4968f9a9259SJagannathan Raman object_class_property_set_description(klass, "socket", 4978f9a9259SJagannathan Raman "SocketAddress " 4988f9a9259SJagannathan Raman "(ex: type=unix,path=/tmp/sock). " 4998f9a9259SJagannathan Raman "Only UNIX is presently supported"); 5008f9a9259SJagannathan Raman object_class_property_add_str(klass, "device", NULL, 5018f9a9259SJagannathan Raman vfu_object_set_device); 5028f9a9259SJagannathan Raman object_class_property_set_description(klass, "device", 5038f9a9259SJagannathan Raman "device ID - only PCI devices " 5048f9a9259SJagannathan Raman "are presently supported"); 5058f9a9259SJagannathan Raman } 5068f9a9259SJagannathan Raman 5078f9a9259SJagannathan Raman static const TypeInfo vfu_object_info = { 5088f9a9259SJagannathan Raman .name = TYPE_VFU_OBJECT, 5098f9a9259SJagannathan Raman .parent = TYPE_OBJECT, 5108f9a9259SJagannathan Raman .instance_size = sizeof(VfuObject), 5118f9a9259SJagannathan Raman .instance_init = vfu_object_init, 5128f9a9259SJagannathan Raman .instance_finalize = vfu_object_finalize, 5138f9a9259SJagannathan Raman .class_size = sizeof(VfuObjectClass), 5148f9a9259SJagannathan Raman .class_init = vfu_object_class_init, 5158f9a9259SJagannathan Raman .interfaces = (InterfaceInfo[]) { 5168f9a9259SJagannathan Raman { TYPE_USER_CREATABLE }, 5178f9a9259SJagannathan Raman { } 5188f9a9259SJagannathan Raman } 5198f9a9259SJagannathan Raman }; 5208f9a9259SJagannathan Raman 5218f9a9259SJagannathan Raman static void vfu_register_types(void) 5228f9a9259SJagannathan Raman { 5238f9a9259SJagannathan Raman type_register_static(&vfu_object_info); 5248f9a9259SJagannathan Raman } 5258f9a9259SJagannathan Raman 5268f9a9259SJagannathan Raman type_init(vfu_register_types); 527