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" 4990072f29SJagannathan 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 24890072f29SJagannathan Raman static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf, 24990072f29SJagannathan Raman size_t count, loff_t offset, 25090072f29SJagannathan Raman const bool is_write) 25190072f29SJagannathan Raman { 25290072f29SJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 25390072f29SJagannathan Raman uint32_t pci_access_width = sizeof(uint32_t); 25490072f29SJagannathan Raman size_t bytes = count; 25590072f29SJagannathan Raman uint32_t val = 0; 25690072f29SJagannathan Raman char *ptr = buf; 25790072f29SJagannathan Raman int len; 25890072f29SJagannathan Raman 25990072f29SJagannathan Raman /* 26090072f29SJagannathan Raman * Writes to the BAR registers would trigger an update to the 26190072f29SJagannathan Raman * global Memory and IO AddressSpaces. But the remote device 26290072f29SJagannathan Raman * never uses the global AddressSpaces, therefore overlapping 26390072f29SJagannathan Raman * memory regions are not a problem 26490072f29SJagannathan Raman */ 26590072f29SJagannathan Raman while (bytes > 0) { 26690072f29SJagannathan Raman len = (bytes > pci_access_width) ? pci_access_width : bytes; 26790072f29SJagannathan Raman if (is_write) { 26890072f29SJagannathan Raman memcpy(&val, ptr, len); 26990072f29SJagannathan Raman pci_host_config_write_common(o->pci_dev, offset, 27090072f29SJagannathan Raman pci_config_size(o->pci_dev), 27190072f29SJagannathan Raman val, len); 27290072f29SJagannathan Raman trace_vfu_cfg_write(offset, val); 27390072f29SJagannathan Raman } else { 27490072f29SJagannathan Raman val = pci_host_config_read_common(o->pci_dev, offset, 27590072f29SJagannathan Raman pci_config_size(o->pci_dev), len); 27690072f29SJagannathan Raman memcpy(ptr, &val, len); 27790072f29SJagannathan Raman trace_vfu_cfg_read(offset, val); 27890072f29SJagannathan Raman } 27990072f29SJagannathan Raman offset += len; 28090072f29SJagannathan Raman ptr += len; 28190072f29SJagannathan Raman bytes -= len; 28290072f29SJagannathan Raman } 28390072f29SJagannathan Raman 28490072f29SJagannathan Raman return count; 28590072f29SJagannathan Raman } 28690072f29SJagannathan Raman 287*15ccf9beSJagannathan Raman static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) 288*15ccf9beSJagannathan Raman { 289*15ccf9beSJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 290*15ccf9beSJagannathan Raman AddressSpace *dma_as = NULL; 291*15ccf9beSJagannathan Raman MemoryRegion *subregion = NULL; 292*15ccf9beSJagannathan Raman g_autofree char *name = NULL; 293*15ccf9beSJagannathan Raman struct iovec *iov = &info->iova; 294*15ccf9beSJagannathan Raman 295*15ccf9beSJagannathan Raman if (!info->vaddr) { 296*15ccf9beSJagannathan Raman return; 297*15ccf9beSJagannathan Raman } 298*15ccf9beSJagannathan Raman 299*15ccf9beSJagannathan Raman name = g_strdup_printf("mem-%s-%"PRIx64"", o->device, 300*15ccf9beSJagannathan Raman (uint64_t)info->vaddr); 301*15ccf9beSJagannathan Raman 302*15ccf9beSJagannathan Raman subregion = g_new0(MemoryRegion, 1); 303*15ccf9beSJagannathan Raman 304*15ccf9beSJagannathan Raman memory_region_init_ram_ptr(subregion, NULL, name, 305*15ccf9beSJagannathan Raman iov->iov_len, info->vaddr); 306*15ccf9beSJagannathan Raman 307*15ccf9beSJagannathan Raman dma_as = pci_device_iommu_address_space(o->pci_dev); 308*15ccf9beSJagannathan Raman 309*15ccf9beSJagannathan Raman memory_region_add_subregion(dma_as->root, (hwaddr)iov->iov_base, subregion); 310*15ccf9beSJagannathan Raman 311*15ccf9beSJagannathan Raman trace_vfu_dma_register((uint64_t)iov->iov_base, iov->iov_len); 312*15ccf9beSJagannathan Raman } 313*15ccf9beSJagannathan Raman 314*15ccf9beSJagannathan Raman static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) 315*15ccf9beSJagannathan Raman { 316*15ccf9beSJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 317*15ccf9beSJagannathan Raman AddressSpace *dma_as = NULL; 318*15ccf9beSJagannathan Raman MemoryRegion *mr = NULL; 319*15ccf9beSJagannathan Raman ram_addr_t offset; 320*15ccf9beSJagannathan Raman 321*15ccf9beSJagannathan Raman mr = memory_region_from_host(info->vaddr, &offset); 322*15ccf9beSJagannathan Raman if (!mr) { 323*15ccf9beSJagannathan Raman return; 324*15ccf9beSJagannathan Raman } 325*15ccf9beSJagannathan Raman 326*15ccf9beSJagannathan Raman dma_as = pci_device_iommu_address_space(o->pci_dev); 327*15ccf9beSJagannathan Raman 328*15ccf9beSJagannathan Raman memory_region_del_subregion(dma_as->root, mr); 329*15ccf9beSJagannathan Raman 330*15ccf9beSJagannathan Raman object_unparent((OBJECT(mr))); 331*15ccf9beSJagannathan Raman 332*15ccf9beSJagannathan Raman trace_vfu_dma_unregister((uint64_t)info->iova.iov_base); 333*15ccf9beSJagannathan Raman } 334*15ccf9beSJagannathan Raman 33587f7249fSJagannathan Raman /* 33687f7249fSJagannathan Raman * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device' 33787f7249fSJagannathan Raman * properties. It also depends on devices instantiated in QEMU. These 33887f7249fSJagannathan Raman * dependencies are not available during the instance_init phase of this 33987f7249fSJagannathan Raman * object's life-cycle. As such, the server is initialized after the 34087f7249fSJagannathan Raman * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT 34187f7249fSJagannathan Raman * when the machine is setup, and the dependencies are available. 34287f7249fSJagannathan Raman */ 34387f7249fSJagannathan Raman static void vfu_object_machine_done(Notifier *notifier, void *data) 34487f7249fSJagannathan Raman { 34587f7249fSJagannathan Raman VfuObject *o = container_of(notifier, VfuObject, machine_done); 34687f7249fSJagannathan Raman Error *err = NULL; 34787f7249fSJagannathan Raman 34887f7249fSJagannathan Raman vfu_object_init_ctx(o, &err); 34987f7249fSJagannathan Raman 35087f7249fSJagannathan Raman if (err) { 35187f7249fSJagannathan Raman error_propagate(&error_abort, err); 35287f7249fSJagannathan Raman } 35387f7249fSJagannathan Raman } 35487f7249fSJagannathan Raman 3559fb3fba1SJagannathan Raman /** 3569fb3fba1SJagannathan Raman * vfu_object_init_ctx: Create and initialize libvfio-user context. Add 3579fb3fba1SJagannathan Raman * an unplug blocker for the associated PCI device. Setup a FD handler 3589fb3fba1SJagannathan Raman * to process incoming messages in the context's socket. 3599fb3fba1SJagannathan Raman * 3609fb3fba1SJagannathan Raman * The socket and device properties are mandatory, and this function 3619fb3fba1SJagannathan Raman * will not create the context without them - the setters for these 3629fb3fba1SJagannathan Raman * properties should call this function when the property is set. The 3639fb3fba1SJagannathan Raman * machine should also be ready when this function is invoked - it is 3649fb3fba1SJagannathan Raman * because QEMU objects are initialized before devices, and the 3659fb3fba1SJagannathan Raman * associated PCI device wouldn't be available at the object 3669fb3fba1SJagannathan Raman * initialization time. Until these conditions are satisfied, this 3679fb3fba1SJagannathan Raman * function would return early without performing any task. 3689fb3fba1SJagannathan Raman */ 36987f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp) 37087f7249fSJagannathan Raman { 37187f7249fSJagannathan Raman ERRP_GUARD(); 372a6e8d6d9SJagannathan Raman DeviceState *dev = NULL; 373a6e8d6d9SJagannathan Raman vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL; 374a6e8d6d9SJagannathan Raman int ret; 37587f7249fSJagannathan Raman 37687f7249fSJagannathan Raman if (o->vfu_ctx || !o->socket || !o->device || 37787f7249fSJagannathan Raman !phase_check(PHASE_MACHINE_READY)) { 37887f7249fSJagannathan Raman return; 37987f7249fSJagannathan Raman } 38087f7249fSJagannathan Raman 38187f7249fSJagannathan Raman if (o->err) { 38287f7249fSJagannathan Raman error_propagate(errp, o->err); 38387f7249fSJagannathan Raman o->err = NULL; 38487f7249fSJagannathan Raman return; 38587f7249fSJagannathan Raman } 38687f7249fSJagannathan Raman 3879fb3fba1SJagannathan Raman o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, 3889fb3fba1SJagannathan Raman LIBVFIO_USER_FLAG_ATTACH_NB, 38987f7249fSJagannathan Raman o, VFU_DEV_TYPE_PCI); 39087f7249fSJagannathan Raman if (o->vfu_ctx == NULL) { 39187f7249fSJagannathan Raman error_setg(errp, "vfu: Failed to create context - %s", strerror(errno)); 39287f7249fSJagannathan Raman return; 39387f7249fSJagannathan Raman } 394a6e8d6d9SJagannathan Raman 395a6e8d6d9SJagannathan Raman dev = qdev_find_recursive(sysbus_get_default(), o->device); 396a6e8d6d9SJagannathan Raman if (dev == NULL) { 397a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: Device %s not found", o->device); 398a6e8d6d9SJagannathan Raman goto fail; 399a6e8d6d9SJagannathan Raman } 400a6e8d6d9SJagannathan Raman 401a6e8d6d9SJagannathan Raman if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 402a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: %s not a PCI device", o->device); 403a6e8d6d9SJagannathan Raman goto fail; 404a6e8d6d9SJagannathan Raman } 405a6e8d6d9SJagannathan Raman 406a6e8d6d9SJagannathan Raman o->pci_dev = PCI_DEVICE(dev); 407a6e8d6d9SJagannathan Raman 408a6e8d6d9SJagannathan Raman object_ref(OBJECT(o->pci_dev)); 409a6e8d6d9SJagannathan Raman 410a6e8d6d9SJagannathan Raman if (pci_is_express(o->pci_dev)) { 411a6e8d6d9SJagannathan Raman pci_type = VFU_PCI_TYPE_EXPRESS; 412a6e8d6d9SJagannathan Raman } 413a6e8d6d9SJagannathan Raman 414a6e8d6d9SJagannathan Raman ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0); 415a6e8d6d9SJagannathan Raman if (ret < 0) { 416a6e8d6d9SJagannathan Raman error_setg(errp, 417a6e8d6d9SJagannathan Raman "vfu: Failed to attach PCI device %s to context - %s", 418a6e8d6d9SJagannathan Raman o->device, strerror(errno)); 419a6e8d6d9SJagannathan Raman goto fail; 420a6e8d6d9SJagannathan Raman } 421a6e8d6d9SJagannathan Raman 422a6e8d6d9SJagannathan Raman error_setg(&o->unplug_blocker, 423a6e8d6d9SJagannathan Raman "vfu: %s for %s must be deleted before unplugging", 424a6e8d6d9SJagannathan Raman TYPE_VFU_OBJECT, o->device); 425a6e8d6d9SJagannathan Raman qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 426a6e8d6d9SJagannathan Raman 42790072f29SJagannathan Raman ret = vfu_setup_region(o->vfu_ctx, VFU_PCI_DEV_CFG_REGION_IDX, 42890072f29SJagannathan Raman pci_config_size(o->pci_dev), &vfu_object_cfg_access, 42990072f29SJagannathan Raman VFU_REGION_FLAG_RW | VFU_REGION_FLAG_ALWAYS_CB, 43090072f29SJagannathan Raman NULL, 0, -1, 0); 43190072f29SJagannathan Raman if (ret < 0) { 43290072f29SJagannathan Raman error_setg(errp, 43390072f29SJagannathan Raman "vfu: Failed to setup config space handlers for %s- %s", 43490072f29SJagannathan Raman o->device, strerror(errno)); 43590072f29SJagannathan Raman goto fail; 43690072f29SJagannathan Raman } 43790072f29SJagannathan Raman 438*15ccf9beSJagannathan Raman ret = vfu_setup_device_dma(o->vfu_ctx, &dma_register, &dma_unregister); 439*15ccf9beSJagannathan Raman if (ret < 0) { 440*15ccf9beSJagannathan Raman error_setg(errp, "vfu: Failed to setup DMA handlers for %s", 441*15ccf9beSJagannathan Raman o->device); 442*15ccf9beSJagannathan Raman goto fail; 443*15ccf9beSJagannathan Raman } 444*15ccf9beSJagannathan Raman 4459fb3fba1SJagannathan Raman ret = vfu_realize_ctx(o->vfu_ctx); 4469fb3fba1SJagannathan Raman if (ret < 0) { 4479fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to realize device %s- %s", 4489fb3fba1SJagannathan Raman o->device, strerror(errno)); 4499fb3fba1SJagannathan Raman goto fail; 4509fb3fba1SJagannathan Raman } 4519fb3fba1SJagannathan Raman 4529fb3fba1SJagannathan Raman o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); 4539fb3fba1SJagannathan Raman if (o->vfu_poll_fd < 0) { 4549fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to get poll fd %s", o->device); 4559fb3fba1SJagannathan Raman goto fail; 4569fb3fba1SJagannathan Raman } 4579fb3fba1SJagannathan Raman 4589fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o); 4599fb3fba1SJagannathan Raman 460a6e8d6d9SJagannathan Raman return; 461a6e8d6d9SJagannathan Raman 462a6e8d6d9SJagannathan Raman fail: 463a6e8d6d9SJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 464a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 465a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 466a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 467a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 468a6e8d6d9SJagannathan Raman } 469a6e8d6d9SJagannathan Raman if (o->pci_dev) { 470a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 471a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 472a6e8d6d9SJagannathan Raman } 473a6e8d6d9SJagannathan Raman o->vfu_ctx = NULL; 4748f9a9259SJagannathan Raman } 4758f9a9259SJagannathan Raman 4768f9a9259SJagannathan Raman static void vfu_object_init(Object *obj) 4778f9a9259SJagannathan Raman { 4788f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 4798f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 4808f9a9259SJagannathan Raman 4818f9a9259SJagannathan Raman k->nr_devs++; 4828f9a9259SJagannathan Raman 4838f9a9259SJagannathan Raman if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 4848f9a9259SJagannathan Raman error_setg(&o->err, "vfu: %s only compatible with %s machine", 4858f9a9259SJagannathan Raman TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 4868f9a9259SJagannathan Raman return; 4878f9a9259SJagannathan Raman } 48887f7249fSJagannathan Raman 48987f7249fSJagannathan Raman if (!phase_check(PHASE_MACHINE_READY)) { 49087f7249fSJagannathan Raman o->machine_done.notify = vfu_object_machine_done; 49187f7249fSJagannathan Raman qemu_add_machine_init_done_notifier(&o->machine_done); 49287f7249fSJagannathan Raman } 49387f7249fSJagannathan Raman 4949fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 4958f9a9259SJagannathan Raman } 4968f9a9259SJagannathan Raman 4978f9a9259SJagannathan Raman static void vfu_object_finalize(Object *obj) 4988f9a9259SJagannathan Raman { 4998f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 5008f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 5018f9a9259SJagannathan Raman 5028f9a9259SJagannathan Raman k->nr_devs--; 5038f9a9259SJagannathan Raman 5048f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 5058f9a9259SJagannathan Raman 5068f9a9259SJagannathan Raman o->socket = NULL; 5078f9a9259SJagannathan Raman 5089fb3fba1SJagannathan Raman if (o->vfu_poll_fd != -1) { 5099fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 5109fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 5119fb3fba1SJagannathan Raman } 5129fb3fba1SJagannathan Raman 51387f7249fSJagannathan Raman if (o->vfu_ctx) { 51487f7249fSJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 51587f7249fSJagannathan Raman o->vfu_ctx = NULL; 51687f7249fSJagannathan Raman } 51787f7249fSJagannathan Raman 5188f9a9259SJagannathan Raman g_free(o->device); 5198f9a9259SJagannathan Raman 5208f9a9259SJagannathan Raman o->device = NULL; 5218f9a9259SJagannathan Raman 522a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 523a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 524a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 525a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 526a6e8d6d9SJagannathan Raman } 527a6e8d6d9SJagannathan Raman 528a6e8d6d9SJagannathan Raman if (o->pci_dev) { 529a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 530a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 531a6e8d6d9SJagannathan Raman } 532a6e8d6d9SJagannathan Raman 5338f9a9259SJagannathan Raman if (!k->nr_devs && vfu_object_auto_shutdown()) { 5348f9a9259SJagannathan Raman qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 5358f9a9259SJagannathan Raman } 53687f7249fSJagannathan Raman 53787f7249fSJagannathan Raman if (o->machine_done.notify) { 53887f7249fSJagannathan Raman qemu_remove_machine_init_done_notifier(&o->machine_done); 53987f7249fSJagannathan Raman o->machine_done.notify = NULL; 54087f7249fSJagannathan Raman } 5418f9a9259SJagannathan Raman } 5428f9a9259SJagannathan Raman 5438f9a9259SJagannathan Raman static void vfu_object_class_init(ObjectClass *klass, void *data) 5448f9a9259SJagannathan Raman { 5458f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 5468f9a9259SJagannathan Raman 5478f9a9259SJagannathan Raman k->nr_devs = 0; 5488f9a9259SJagannathan Raman 5498f9a9259SJagannathan Raman object_class_property_add(klass, "socket", "SocketAddress", NULL, 5508f9a9259SJagannathan Raman vfu_object_set_socket, NULL, NULL); 5518f9a9259SJagannathan Raman object_class_property_set_description(klass, "socket", 5528f9a9259SJagannathan Raman "SocketAddress " 5538f9a9259SJagannathan Raman "(ex: type=unix,path=/tmp/sock). " 5548f9a9259SJagannathan Raman "Only UNIX is presently supported"); 5558f9a9259SJagannathan Raman object_class_property_add_str(klass, "device", NULL, 5568f9a9259SJagannathan Raman vfu_object_set_device); 5578f9a9259SJagannathan Raman object_class_property_set_description(klass, "device", 5588f9a9259SJagannathan Raman "device ID - only PCI devices " 5598f9a9259SJagannathan Raman "are presently supported"); 5608f9a9259SJagannathan Raman } 5618f9a9259SJagannathan Raman 5628f9a9259SJagannathan Raman static const TypeInfo vfu_object_info = { 5638f9a9259SJagannathan Raman .name = TYPE_VFU_OBJECT, 5648f9a9259SJagannathan Raman .parent = TYPE_OBJECT, 5658f9a9259SJagannathan Raman .instance_size = sizeof(VfuObject), 5668f9a9259SJagannathan Raman .instance_init = vfu_object_init, 5678f9a9259SJagannathan Raman .instance_finalize = vfu_object_finalize, 5688f9a9259SJagannathan Raman .class_size = sizeof(VfuObjectClass), 5698f9a9259SJagannathan Raman .class_init = vfu_object_class_init, 5708f9a9259SJagannathan Raman .interfaces = (InterfaceInfo[]) { 5718f9a9259SJagannathan Raman { TYPE_USER_CREATABLE }, 5728f9a9259SJagannathan Raman { } 5738f9a9259SJagannathan Raman } 5748f9a9259SJagannathan Raman }; 5758f9a9259SJagannathan Raman 5768f9a9259SJagannathan Raman static void vfu_register_types(void) 5778f9a9259SJagannathan Raman { 5788f9a9259SJagannathan Raman type_register_static(&vfu_object_info); 5798f9a9259SJagannathan Raman } 5808f9a9259SJagannathan Raman 5818f9a9259SJagannathan Raman type_init(vfu_register_types); 582