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" 55*3123f93dSJagannathan Raman #include "exec/memory.h" 568f9a9259SJagannathan Raman 578f9a9259SJagannathan Raman #define TYPE_VFU_OBJECT "x-vfio-user-server" 588f9a9259SJagannathan Raman OBJECT_DECLARE_TYPE(VfuObject, VfuObjectClass, VFU_OBJECT) 598f9a9259SJagannathan Raman 608f9a9259SJagannathan Raman /** 618f9a9259SJagannathan Raman * VFU_OBJECT_ERROR - reports an error message. If auto_shutdown 628f9a9259SJagannathan Raman * is set, it aborts the machine on error. Otherwise, it logs an 638f9a9259SJagannathan Raman * error message without aborting. 648f9a9259SJagannathan Raman */ 658f9a9259SJagannathan Raman #define VFU_OBJECT_ERROR(o, fmt, ...) \ 668f9a9259SJagannathan Raman { \ 678f9a9259SJagannathan Raman if (vfu_object_auto_shutdown()) { \ 688f9a9259SJagannathan Raman error_setg(&error_abort, (fmt), ## __VA_ARGS__); \ 698f9a9259SJagannathan Raman } else { \ 708f9a9259SJagannathan Raman error_report((fmt), ## __VA_ARGS__); \ 718f9a9259SJagannathan Raman } \ 728f9a9259SJagannathan Raman } \ 738f9a9259SJagannathan Raman 748f9a9259SJagannathan Raman struct VfuObjectClass { 758f9a9259SJagannathan Raman ObjectClass parent_class; 768f9a9259SJagannathan Raman 778f9a9259SJagannathan Raman unsigned int nr_devs; 788f9a9259SJagannathan Raman }; 798f9a9259SJagannathan Raman 808f9a9259SJagannathan Raman struct VfuObject { 818f9a9259SJagannathan Raman /* private */ 828f9a9259SJagannathan Raman Object parent; 838f9a9259SJagannathan Raman 848f9a9259SJagannathan Raman SocketAddress *socket; 858f9a9259SJagannathan Raman 868f9a9259SJagannathan Raman char *device; 878f9a9259SJagannathan Raman 888f9a9259SJagannathan Raman Error *err; 8987f7249fSJagannathan Raman 9087f7249fSJagannathan Raman Notifier machine_done; 9187f7249fSJagannathan Raman 9287f7249fSJagannathan Raman vfu_ctx_t *vfu_ctx; 93a6e8d6d9SJagannathan Raman 94a6e8d6d9SJagannathan Raman PCIDevice *pci_dev; 95a6e8d6d9SJagannathan Raman 96a6e8d6d9SJagannathan Raman Error *unplug_blocker; 979fb3fba1SJagannathan Raman 989fb3fba1SJagannathan Raman int vfu_poll_fd; 998f9a9259SJagannathan Raman }; 1008f9a9259SJagannathan Raman 10187f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp); 10287f7249fSJagannathan Raman 1038f9a9259SJagannathan Raman static bool vfu_object_auto_shutdown(void) 1048f9a9259SJagannathan Raman { 1058f9a9259SJagannathan Raman bool auto_shutdown = true; 1068f9a9259SJagannathan Raman Error *local_err = NULL; 1078f9a9259SJagannathan Raman 1088f9a9259SJagannathan Raman if (!current_machine) { 1098f9a9259SJagannathan Raman return auto_shutdown; 1108f9a9259SJagannathan Raman } 1118f9a9259SJagannathan Raman 1128f9a9259SJagannathan Raman auto_shutdown = object_property_get_bool(OBJECT(current_machine), 1138f9a9259SJagannathan Raman "auto-shutdown", 1148f9a9259SJagannathan Raman &local_err); 1158f9a9259SJagannathan Raman 1168f9a9259SJagannathan Raman /* 1178f9a9259SJagannathan Raman * local_err would be set if no such property exists - safe to ignore. 1188f9a9259SJagannathan Raman * Unlikely scenario as auto-shutdown is always defined for 1198f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE, and TYPE_VFU_OBJECT only works with 1208f9a9259SJagannathan Raman * TYPE_REMOTE_MACHINE 1218f9a9259SJagannathan Raman */ 1228f9a9259SJagannathan Raman if (local_err) { 1238f9a9259SJagannathan Raman auto_shutdown = true; 1248f9a9259SJagannathan Raman error_free(local_err); 1258f9a9259SJagannathan Raman } 1268f9a9259SJagannathan Raman 1278f9a9259SJagannathan Raman return auto_shutdown; 1288f9a9259SJagannathan Raman } 1298f9a9259SJagannathan Raman 1308f9a9259SJagannathan Raman static void vfu_object_set_socket(Object *obj, Visitor *v, const char *name, 1318f9a9259SJagannathan Raman void *opaque, Error **errp) 1328f9a9259SJagannathan Raman { 1338f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 1348f9a9259SJagannathan Raman 13587f7249fSJagannathan Raman if (o->vfu_ctx) { 13687f7249fSJagannathan Raman error_setg(errp, "vfu: Unable to set socket property - server busy"); 13787f7249fSJagannathan Raman return; 13887f7249fSJagannathan Raman } 13987f7249fSJagannathan Raman 1408f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 1418f9a9259SJagannathan Raman 1428f9a9259SJagannathan Raman o->socket = NULL; 1438f9a9259SJagannathan Raman 1448f9a9259SJagannathan Raman visit_type_SocketAddress(v, name, &o->socket, errp); 1458f9a9259SJagannathan Raman 1468f9a9259SJagannathan Raman if (o->socket->type != SOCKET_ADDRESS_TYPE_UNIX) { 1478f9a9259SJagannathan Raman error_setg(errp, "vfu: Unsupported socket type - %s", 1488f9a9259SJagannathan Raman SocketAddressType_str(o->socket->type)); 1498f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 1508f9a9259SJagannathan Raman o->socket = NULL; 1518f9a9259SJagannathan Raman return; 1528f9a9259SJagannathan Raman } 1538f9a9259SJagannathan Raman 1548f9a9259SJagannathan Raman trace_vfu_prop("socket", o->socket->u.q_unix.path); 15587f7249fSJagannathan Raman 15687f7249fSJagannathan Raman vfu_object_init_ctx(o, errp); 1578f9a9259SJagannathan Raman } 1588f9a9259SJagannathan Raman 1598f9a9259SJagannathan Raman static void vfu_object_set_device(Object *obj, const char *str, Error **errp) 1608f9a9259SJagannathan Raman { 1618f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 1628f9a9259SJagannathan Raman 16387f7249fSJagannathan Raman if (o->vfu_ctx) { 16487f7249fSJagannathan Raman error_setg(errp, "vfu: Unable to set device property - server busy"); 16587f7249fSJagannathan Raman return; 16687f7249fSJagannathan Raman } 16787f7249fSJagannathan Raman 1688f9a9259SJagannathan Raman g_free(o->device); 1698f9a9259SJagannathan Raman 1708f9a9259SJagannathan Raman o->device = g_strdup(str); 1718f9a9259SJagannathan Raman 1728f9a9259SJagannathan Raman trace_vfu_prop("device", str); 17387f7249fSJagannathan Raman 17487f7249fSJagannathan Raman vfu_object_init_ctx(o, errp); 17587f7249fSJagannathan Raman } 17687f7249fSJagannathan Raman 1779fb3fba1SJagannathan Raman static void vfu_object_ctx_run(void *opaque) 1789fb3fba1SJagannathan Raman { 1799fb3fba1SJagannathan Raman VfuObject *o = opaque; 1809fb3fba1SJagannathan Raman const char *vfu_id; 1819fb3fba1SJagannathan Raman char *vfu_path, *pci_dev_path; 1829fb3fba1SJagannathan Raman int ret = -1; 1839fb3fba1SJagannathan Raman 1849fb3fba1SJagannathan Raman while (ret != 0) { 1859fb3fba1SJagannathan Raman ret = vfu_run_ctx(o->vfu_ctx); 1869fb3fba1SJagannathan Raman if (ret < 0) { 1879fb3fba1SJagannathan Raman if (errno == EINTR) { 1889fb3fba1SJagannathan Raman continue; 1899fb3fba1SJagannathan Raman } else if (errno == ENOTCONN) { 1909fb3fba1SJagannathan Raman vfu_id = object_get_canonical_path_component(OBJECT(o)); 1919fb3fba1SJagannathan Raman vfu_path = object_get_canonical_path(OBJECT(o)); 1929fb3fba1SJagannathan Raman g_assert(o->pci_dev); 1939fb3fba1SJagannathan Raman pci_dev_path = object_get_canonical_path(OBJECT(o->pci_dev)); 1949fb3fba1SJagannathan Raman /* o->device is a required property and is non-NULL here */ 1959fb3fba1SJagannathan Raman g_assert(o->device); 1969fb3fba1SJagannathan Raman qapi_event_send_vfu_client_hangup(vfu_id, vfu_path, 1979fb3fba1SJagannathan Raman o->device, pci_dev_path); 1989fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 1999fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 2009fb3fba1SJagannathan Raman object_unparent(OBJECT(o)); 2019fb3fba1SJagannathan Raman g_free(vfu_path); 2029fb3fba1SJagannathan Raman g_free(pci_dev_path); 2039fb3fba1SJagannathan Raman break; 2049fb3fba1SJagannathan Raman } else { 2059fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to run device %s - %s", 2069fb3fba1SJagannathan Raman o->device, strerror(errno)); 2079fb3fba1SJagannathan Raman break; 2089fb3fba1SJagannathan Raman } 2099fb3fba1SJagannathan Raman } 2109fb3fba1SJagannathan Raman } 2119fb3fba1SJagannathan Raman } 2129fb3fba1SJagannathan Raman 2139fb3fba1SJagannathan Raman static void vfu_object_attach_ctx(void *opaque) 2149fb3fba1SJagannathan Raman { 2159fb3fba1SJagannathan Raman VfuObject *o = opaque; 2169fb3fba1SJagannathan Raman GPollFD pfds[1]; 2179fb3fba1SJagannathan Raman int ret; 2189fb3fba1SJagannathan Raman 2199fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 2209fb3fba1SJagannathan Raman 2219fb3fba1SJagannathan Raman pfds[0].fd = o->vfu_poll_fd; 2229fb3fba1SJagannathan Raman pfds[0].events = G_IO_IN | G_IO_HUP | G_IO_ERR; 2239fb3fba1SJagannathan Raman 2249fb3fba1SJagannathan Raman retry_attach: 2259fb3fba1SJagannathan Raman ret = vfu_attach_ctx(o->vfu_ctx); 2269fb3fba1SJagannathan Raman if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 2279fb3fba1SJagannathan Raman /** 2289fb3fba1SJagannathan Raman * vfu_object_attach_ctx can block QEMU's main loop 2299fb3fba1SJagannathan Raman * during attach - the monitor and other IO 2309fb3fba1SJagannathan Raman * could be unresponsive during this time. 2319fb3fba1SJagannathan Raman */ 2329fb3fba1SJagannathan Raman (void)qemu_poll_ns(pfds, 1, 500 * (int64_t)SCALE_MS); 2339fb3fba1SJagannathan Raman goto retry_attach; 2349fb3fba1SJagannathan Raman } else if (ret < 0) { 2359fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to attach device %s to context - %s", 2369fb3fba1SJagannathan Raman o->device, strerror(errno)); 2379fb3fba1SJagannathan Raman return; 2389fb3fba1SJagannathan Raman } 2399fb3fba1SJagannathan Raman 2409fb3fba1SJagannathan Raman o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); 2419fb3fba1SJagannathan Raman if (o->vfu_poll_fd < 0) { 2429fb3fba1SJagannathan Raman VFU_OBJECT_ERROR(o, "vfu: Failed to get poll fd %s", o->device); 2439fb3fba1SJagannathan Raman return; 2449fb3fba1SJagannathan Raman } 2459fb3fba1SJagannathan Raman 2469fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_ctx_run, NULL, o); 2479fb3fba1SJagannathan Raman } 2489fb3fba1SJagannathan Raman 24990072f29SJagannathan Raman static ssize_t vfu_object_cfg_access(vfu_ctx_t *vfu_ctx, char * const buf, 25090072f29SJagannathan Raman size_t count, loff_t offset, 25190072f29SJagannathan Raman const bool is_write) 25290072f29SJagannathan Raman { 25390072f29SJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 25490072f29SJagannathan Raman uint32_t pci_access_width = sizeof(uint32_t); 25590072f29SJagannathan Raman size_t bytes = count; 25690072f29SJagannathan Raman uint32_t val = 0; 25790072f29SJagannathan Raman char *ptr = buf; 25890072f29SJagannathan Raman int len; 25990072f29SJagannathan Raman 26090072f29SJagannathan Raman /* 26190072f29SJagannathan Raman * Writes to the BAR registers would trigger an update to the 26290072f29SJagannathan Raman * global Memory and IO AddressSpaces. But the remote device 26390072f29SJagannathan Raman * never uses the global AddressSpaces, therefore overlapping 26490072f29SJagannathan Raman * memory regions are not a problem 26590072f29SJagannathan Raman */ 26690072f29SJagannathan Raman while (bytes > 0) { 26790072f29SJagannathan Raman len = (bytes > pci_access_width) ? pci_access_width : bytes; 26890072f29SJagannathan Raman if (is_write) { 26990072f29SJagannathan Raman memcpy(&val, ptr, len); 27090072f29SJagannathan Raman pci_host_config_write_common(o->pci_dev, offset, 27190072f29SJagannathan Raman pci_config_size(o->pci_dev), 27290072f29SJagannathan Raman val, len); 27390072f29SJagannathan Raman trace_vfu_cfg_write(offset, val); 27490072f29SJagannathan Raman } else { 27590072f29SJagannathan Raman val = pci_host_config_read_common(o->pci_dev, offset, 27690072f29SJagannathan Raman pci_config_size(o->pci_dev), len); 27790072f29SJagannathan Raman memcpy(ptr, &val, len); 27890072f29SJagannathan Raman trace_vfu_cfg_read(offset, val); 27990072f29SJagannathan Raman } 28090072f29SJagannathan Raman offset += len; 28190072f29SJagannathan Raman ptr += len; 28290072f29SJagannathan Raman bytes -= len; 28390072f29SJagannathan Raman } 28490072f29SJagannathan Raman 28590072f29SJagannathan Raman return count; 28690072f29SJagannathan Raman } 28790072f29SJagannathan Raman 28815ccf9beSJagannathan Raman static void dma_register(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) 28915ccf9beSJagannathan Raman { 29015ccf9beSJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 29115ccf9beSJagannathan Raman AddressSpace *dma_as = NULL; 29215ccf9beSJagannathan Raman MemoryRegion *subregion = NULL; 29315ccf9beSJagannathan Raman g_autofree char *name = NULL; 29415ccf9beSJagannathan Raman struct iovec *iov = &info->iova; 29515ccf9beSJagannathan Raman 29615ccf9beSJagannathan Raman if (!info->vaddr) { 29715ccf9beSJagannathan Raman return; 29815ccf9beSJagannathan Raman } 29915ccf9beSJagannathan Raman 30015ccf9beSJagannathan Raman name = g_strdup_printf("mem-%s-%"PRIx64"", o->device, 30115ccf9beSJagannathan Raman (uint64_t)info->vaddr); 30215ccf9beSJagannathan Raman 30315ccf9beSJagannathan Raman subregion = g_new0(MemoryRegion, 1); 30415ccf9beSJagannathan Raman 30515ccf9beSJagannathan Raman memory_region_init_ram_ptr(subregion, NULL, name, 30615ccf9beSJagannathan Raman iov->iov_len, info->vaddr); 30715ccf9beSJagannathan Raman 30815ccf9beSJagannathan Raman dma_as = pci_device_iommu_address_space(o->pci_dev); 30915ccf9beSJagannathan Raman 31015ccf9beSJagannathan Raman memory_region_add_subregion(dma_as->root, (hwaddr)iov->iov_base, subregion); 31115ccf9beSJagannathan Raman 31215ccf9beSJagannathan Raman trace_vfu_dma_register((uint64_t)iov->iov_base, iov->iov_len); 31315ccf9beSJagannathan Raman } 31415ccf9beSJagannathan Raman 31515ccf9beSJagannathan Raman static void dma_unregister(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info) 31615ccf9beSJagannathan Raman { 31715ccf9beSJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); 31815ccf9beSJagannathan Raman AddressSpace *dma_as = NULL; 31915ccf9beSJagannathan Raman MemoryRegion *mr = NULL; 32015ccf9beSJagannathan Raman ram_addr_t offset; 32115ccf9beSJagannathan Raman 32215ccf9beSJagannathan Raman mr = memory_region_from_host(info->vaddr, &offset); 32315ccf9beSJagannathan Raman if (!mr) { 32415ccf9beSJagannathan Raman return; 32515ccf9beSJagannathan Raman } 32615ccf9beSJagannathan Raman 32715ccf9beSJagannathan Raman dma_as = pci_device_iommu_address_space(o->pci_dev); 32815ccf9beSJagannathan Raman 32915ccf9beSJagannathan Raman memory_region_del_subregion(dma_as->root, mr); 33015ccf9beSJagannathan Raman 33115ccf9beSJagannathan Raman object_unparent((OBJECT(mr))); 33215ccf9beSJagannathan Raman 33315ccf9beSJagannathan Raman trace_vfu_dma_unregister((uint64_t)info->iova.iov_base); 33415ccf9beSJagannathan Raman } 33515ccf9beSJagannathan Raman 336*3123f93dSJagannathan Raman static int vfu_object_mr_rw(MemoryRegion *mr, uint8_t *buf, hwaddr offset, 337*3123f93dSJagannathan Raman hwaddr size, const bool is_write) 338*3123f93dSJagannathan Raman { 339*3123f93dSJagannathan Raman uint8_t *ptr = buf; 340*3123f93dSJagannathan Raman bool release_lock = false; 341*3123f93dSJagannathan Raman uint8_t *ram_ptr = NULL; 342*3123f93dSJagannathan Raman MemTxResult result; 343*3123f93dSJagannathan Raman int access_size; 344*3123f93dSJagannathan Raman uint64_t val; 345*3123f93dSJagannathan Raman 346*3123f93dSJagannathan Raman if (memory_access_is_direct(mr, is_write)) { 347*3123f93dSJagannathan Raman /** 348*3123f93dSJagannathan Raman * Some devices expose a PCI expansion ROM, which could be buffer 349*3123f93dSJagannathan Raman * based as compared to other regions which are primarily based on 350*3123f93dSJagannathan Raman * MemoryRegionOps. memory_region_find() would already check 351*3123f93dSJagannathan Raman * for buffer overflow, we don't need to repeat it here. 352*3123f93dSJagannathan Raman */ 353*3123f93dSJagannathan Raman ram_ptr = memory_region_get_ram_ptr(mr); 354*3123f93dSJagannathan Raman 355*3123f93dSJagannathan Raman if (is_write) { 356*3123f93dSJagannathan Raman memcpy((ram_ptr + offset), buf, size); 357*3123f93dSJagannathan Raman } else { 358*3123f93dSJagannathan Raman memcpy(buf, (ram_ptr + offset), size); 359*3123f93dSJagannathan Raman } 360*3123f93dSJagannathan Raman 361*3123f93dSJagannathan Raman return 0; 362*3123f93dSJagannathan Raman } 363*3123f93dSJagannathan Raman 364*3123f93dSJagannathan Raman while (size) { 365*3123f93dSJagannathan Raman /** 366*3123f93dSJagannathan Raman * The read/write logic used below is similar to the ones in 367*3123f93dSJagannathan Raman * flatview_read/write_continue() 368*3123f93dSJagannathan Raman */ 369*3123f93dSJagannathan Raman release_lock = prepare_mmio_access(mr); 370*3123f93dSJagannathan Raman 371*3123f93dSJagannathan Raman access_size = memory_access_size(mr, size, offset); 372*3123f93dSJagannathan Raman 373*3123f93dSJagannathan Raman if (is_write) { 374*3123f93dSJagannathan Raman val = ldn_he_p(ptr, access_size); 375*3123f93dSJagannathan Raman 376*3123f93dSJagannathan Raman result = memory_region_dispatch_write(mr, offset, val, 377*3123f93dSJagannathan Raman size_memop(access_size), 378*3123f93dSJagannathan Raman MEMTXATTRS_UNSPECIFIED); 379*3123f93dSJagannathan Raman } else { 380*3123f93dSJagannathan Raman result = memory_region_dispatch_read(mr, offset, &val, 381*3123f93dSJagannathan Raman size_memop(access_size), 382*3123f93dSJagannathan Raman MEMTXATTRS_UNSPECIFIED); 383*3123f93dSJagannathan Raman 384*3123f93dSJagannathan Raman stn_he_p(ptr, access_size, val); 385*3123f93dSJagannathan Raman } 386*3123f93dSJagannathan Raman 387*3123f93dSJagannathan Raman if (release_lock) { 388*3123f93dSJagannathan Raman qemu_mutex_unlock_iothread(); 389*3123f93dSJagannathan Raman release_lock = false; 390*3123f93dSJagannathan Raman } 391*3123f93dSJagannathan Raman 392*3123f93dSJagannathan Raman if (result != MEMTX_OK) { 393*3123f93dSJagannathan Raman return -1; 394*3123f93dSJagannathan Raman } 395*3123f93dSJagannathan Raman 396*3123f93dSJagannathan Raman size -= access_size; 397*3123f93dSJagannathan Raman ptr += access_size; 398*3123f93dSJagannathan Raman offset += access_size; 399*3123f93dSJagannathan Raman } 400*3123f93dSJagannathan Raman 401*3123f93dSJagannathan Raman return 0; 402*3123f93dSJagannathan Raman } 403*3123f93dSJagannathan Raman 404*3123f93dSJagannathan Raman static size_t vfu_object_bar_rw(PCIDevice *pci_dev, int pci_bar, 405*3123f93dSJagannathan Raman hwaddr bar_offset, char * const buf, 406*3123f93dSJagannathan Raman hwaddr len, const bool is_write) 407*3123f93dSJagannathan Raman { 408*3123f93dSJagannathan Raman MemoryRegionSection section = { 0 }; 409*3123f93dSJagannathan Raman uint8_t *ptr = (uint8_t *)buf; 410*3123f93dSJagannathan Raman MemoryRegion *section_mr = NULL; 411*3123f93dSJagannathan Raman uint64_t section_size; 412*3123f93dSJagannathan Raman hwaddr section_offset; 413*3123f93dSJagannathan Raman hwaddr size = 0; 414*3123f93dSJagannathan Raman 415*3123f93dSJagannathan Raman while (len) { 416*3123f93dSJagannathan Raman section = memory_region_find(pci_dev->io_regions[pci_bar].memory, 417*3123f93dSJagannathan Raman bar_offset, len); 418*3123f93dSJagannathan Raman 419*3123f93dSJagannathan Raman if (!section.mr) { 420*3123f93dSJagannathan Raman warn_report("vfu: invalid address 0x%"PRIx64"", bar_offset); 421*3123f93dSJagannathan Raman return size; 422*3123f93dSJagannathan Raman } 423*3123f93dSJagannathan Raman 424*3123f93dSJagannathan Raman section_mr = section.mr; 425*3123f93dSJagannathan Raman section_offset = section.offset_within_region; 426*3123f93dSJagannathan Raman section_size = int128_get64(section.size); 427*3123f93dSJagannathan Raman 428*3123f93dSJagannathan Raman if (is_write && section_mr->readonly) { 429*3123f93dSJagannathan Raman warn_report("vfu: attempting to write to readonly region in " 430*3123f93dSJagannathan Raman "bar %d - [0x%"PRIx64" - 0x%"PRIx64"]", 431*3123f93dSJagannathan Raman pci_bar, bar_offset, 432*3123f93dSJagannathan Raman (bar_offset + section_size)); 433*3123f93dSJagannathan Raman memory_region_unref(section_mr); 434*3123f93dSJagannathan Raman return size; 435*3123f93dSJagannathan Raman } 436*3123f93dSJagannathan Raman 437*3123f93dSJagannathan Raman if (vfu_object_mr_rw(section_mr, ptr, section_offset, 438*3123f93dSJagannathan Raman section_size, is_write)) { 439*3123f93dSJagannathan Raman warn_report("vfu: failed to %s " 440*3123f93dSJagannathan Raman "[0x%"PRIx64" - 0x%"PRIx64"] in bar %d", 441*3123f93dSJagannathan Raman is_write ? "write to" : "read from", bar_offset, 442*3123f93dSJagannathan Raman (bar_offset + section_size), pci_bar); 443*3123f93dSJagannathan Raman memory_region_unref(section_mr); 444*3123f93dSJagannathan Raman return size; 445*3123f93dSJagannathan Raman } 446*3123f93dSJagannathan Raman 447*3123f93dSJagannathan Raman size += section_size; 448*3123f93dSJagannathan Raman bar_offset += section_size; 449*3123f93dSJagannathan Raman ptr += section_size; 450*3123f93dSJagannathan Raman len -= section_size; 451*3123f93dSJagannathan Raman 452*3123f93dSJagannathan Raman memory_region_unref(section_mr); 453*3123f93dSJagannathan Raman } 454*3123f93dSJagannathan Raman 455*3123f93dSJagannathan Raman return size; 456*3123f93dSJagannathan Raman } 457*3123f93dSJagannathan Raman 458*3123f93dSJagannathan Raman /** 459*3123f93dSJagannathan Raman * VFU_OBJECT_BAR_HANDLER - macro for defining handlers for PCI BARs. 460*3123f93dSJagannathan Raman * 461*3123f93dSJagannathan Raman * To create handler for BAR number 2, VFU_OBJECT_BAR_HANDLER(2) would 462*3123f93dSJagannathan Raman * define vfu_object_bar2_handler 463*3123f93dSJagannathan Raman */ 464*3123f93dSJagannathan Raman #define VFU_OBJECT_BAR_HANDLER(BAR_NO) \ 465*3123f93dSJagannathan Raman static ssize_t vfu_object_bar##BAR_NO##_handler(vfu_ctx_t *vfu_ctx, \ 466*3123f93dSJagannathan Raman char * const buf, size_t count, \ 467*3123f93dSJagannathan Raman loff_t offset, const bool is_write) \ 468*3123f93dSJagannathan Raman { \ 469*3123f93dSJagannathan Raman VfuObject *o = vfu_get_private(vfu_ctx); \ 470*3123f93dSJagannathan Raman PCIDevice *pci_dev = o->pci_dev; \ 471*3123f93dSJagannathan Raman \ 472*3123f93dSJagannathan Raman return vfu_object_bar_rw(pci_dev, BAR_NO, offset, \ 473*3123f93dSJagannathan Raman buf, count, is_write); \ 474*3123f93dSJagannathan Raman } \ 475*3123f93dSJagannathan Raman 476*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(0) 477*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(1) 478*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(2) 479*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(3) 480*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(4) 481*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(5) 482*3123f93dSJagannathan Raman VFU_OBJECT_BAR_HANDLER(6) 483*3123f93dSJagannathan Raman 484*3123f93dSJagannathan Raman static vfu_region_access_cb_t *vfu_object_bar_handlers[PCI_NUM_REGIONS] = { 485*3123f93dSJagannathan Raman &vfu_object_bar0_handler, 486*3123f93dSJagannathan Raman &vfu_object_bar1_handler, 487*3123f93dSJagannathan Raman &vfu_object_bar2_handler, 488*3123f93dSJagannathan Raman &vfu_object_bar3_handler, 489*3123f93dSJagannathan Raman &vfu_object_bar4_handler, 490*3123f93dSJagannathan Raman &vfu_object_bar5_handler, 491*3123f93dSJagannathan Raman &vfu_object_bar6_handler, 492*3123f93dSJagannathan Raman }; 493*3123f93dSJagannathan Raman 494*3123f93dSJagannathan Raman /** 495*3123f93dSJagannathan Raman * vfu_object_register_bars - Identify active BAR regions of pdev and setup 496*3123f93dSJagannathan Raman * callbacks to handle read/write accesses 497*3123f93dSJagannathan Raman */ 498*3123f93dSJagannathan Raman static void vfu_object_register_bars(vfu_ctx_t *vfu_ctx, PCIDevice *pdev) 499*3123f93dSJagannathan Raman { 500*3123f93dSJagannathan Raman int flags = VFU_REGION_FLAG_RW; 501*3123f93dSJagannathan Raman int i; 502*3123f93dSJagannathan Raman 503*3123f93dSJagannathan Raman for (i = 0; i < PCI_NUM_REGIONS; i++) { 504*3123f93dSJagannathan Raman if (!pdev->io_regions[i].size) { 505*3123f93dSJagannathan Raman continue; 506*3123f93dSJagannathan Raman } 507*3123f93dSJagannathan Raman 508*3123f93dSJagannathan Raman if ((i == VFU_PCI_DEV_ROM_REGION_IDX) || 509*3123f93dSJagannathan Raman pdev->io_regions[i].memory->readonly) { 510*3123f93dSJagannathan Raman flags &= ~VFU_REGION_FLAG_WRITE; 511*3123f93dSJagannathan Raman } 512*3123f93dSJagannathan Raman 513*3123f93dSJagannathan Raman vfu_setup_region(vfu_ctx, VFU_PCI_DEV_BAR0_REGION_IDX + i, 514*3123f93dSJagannathan Raman (size_t)pdev->io_regions[i].size, 515*3123f93dSJagannathan Raman vfu_object_bar_handlers[i], 516*3123f93dSJagannathan Raman flags, NULL, 0, -1, 0); 517*3123f93dSJagannathan Raman 518*3123f93dSJagannathan Raman trace_vfu_bar_register(i, pdev->io_regions[i].addr, 519*3123f93dSJagannathan Raman pdev->io_regions[i].size); 520*3123f93dSJagannathan Raman } 521*3123f93dSJagannathan Raman } 522*3123f93dSJagannathan Raman 52387f7249fSJagannathan Raman /* 52487f7249fSJagannathan Raman * TYPE_VFU_OBJECT depends on the availability of the 'socket' and 'device' 52587f7249fSJagannathan Raman * properties. It also depends on devices instantiated in QEMU. These 52687f7249fSJagannathan Raman * dependencies are not available during the instance_init phase of this 52787f7249fSJagannathan Raman * object's life-cycle. As such, the server is initialized after the 52887f7249fSJagannathan Raman * machine is setup. machine_init_done_notifier notifies TYPE_VFU_OBJECT 52987f7249fSJagannathan Raman * when the machine is setup, and the dependencies are available. 53087f7249fSJagannathan Raman */ 53187f7249fSJagannathan Raman static void vfu_object_machine_done(Notifier *notifier, void *data) 53287f7249fSJagannathan Raman { 53387f7249fSJagannathan Raman VfuObject *o = container_of(notifier, VfuObject, machine_done); 53487f7249fSJagannathan Raman Error *err = NULL; 53587f7249fSJagannathan Raman 53687f7249fSJagannathan Raman vfu_object_init_ctx(o, &err); 53787f7249fSJagannathan Raman 53887f7249fSJagannathan Raman if (err) { 53987f7249fSJagannathan Raman error_propagate(&error_abort, err); 54087f7249fSJagannathan Raman } 54187f7249fSJagannathan Raman } 54287f7249fSJagannathan Raman 5439fb3fba1SJagannathan Raman /** 5449fb3fba1SJagannathan Raman * vfu_object_init_ctx: Create and initialize libvfio-user context. Add 5459fb3fba1SJagannathan Raman * an unplug blocker for the associated PCI device. Setup a FD handler 5469fb3fba1SJagannathan Raman * to process incoming messages in the context's socket. 5479fb3fba1SJagannathan Raman * 5489fb3fba1SJagannathan Raman * The socket and device properties are mandatory, and this function 5499fb3fba1SJagannathan Raman * will not create the context without them - the setters for these 5509fb3fba1SJagannathan Raman * properties should call this function when the property is set. The 5519fb3fba1SJagannathan Raman * machine should also be ready when this function is invoked - it is 5529fb3fba1SJagannathan Raman * because QEMU objects are initialized before devices, and the 5539fb3fba1SJagannathan Raman * associated PCI device wouldn't be available at the object 5549fb3fba1SJagannathan Raman * initialization time. Until these conditions are satisfied, this 5559fb3fba1SJagannathan Raman * function would return early without performing any task. 5569fb3fba1SJagannathan Raman */ 55787f7249fSJagannathan Raman static void vfu_object_init_ctx(VfuObject *o, Error **errp) 55887f7249fSJagannathan Raman { 55987f7249fSJagannathan Raman ERRP_GUARD(); 560a6e8d6d9SJagannathan Raman DeviceState *dev = NULL; 561a6e8d6d9SJagannathan Raman vfu_pci_type_t pci_type = VFU_PCI_TYPE_CONVENTIONAL; 562a6e8d6d9SJagannathan Raman int ret; 56387f7249fSJagannathan Raman 56487f7249fSJagannathan Raman if (o->vfu_ctx || !o->socket || !o->device || 56587f7249fSJagannathan Raman !phase_check(PHASE_MACHINE_READY)) { 56687f7249fSJagannathan Raman return; 56787f7249fSJagannathan Raman } 56887f7249fSJagannathan Raman 56987f7249fSJagannathan Raman if (o->err) { 57087f7249fSJagannathan Raman error_propagate(errp, o->err); 57187f7249fSJagannathan Raman o->err = NULL; 57287f7249fSJagannathan Raman return; 57387f7249fSJagannathan Raman } 57487f7249fSJagannathan Raman 5759fb3fba1SJagannathan Raman o->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, o->socket->u.q_unix.path, 5769fb3fba1SJagannathan Raman LIBVFIO_USER_FLAG_ATTACH_NB, 57787f7249fSJagannathan Raman o, VFU_DEV_TYPE_PCI); 57887f7249fSJagannathan Raman if (o->vfu_ctx == NULL) { 57987f7249fSJagannathan Raman error_setg(errp, "vfu: Failed to create context - %s", strerror(errno)); 58087f7249fSJagannathan Raman return; 58187f7249fSJagannathan Raman } 582a6e8d6d9SJagannathan Raman 583a6e8d6d9SJagannathan Raman dev = qdev_find_recursive(sysbus_get_default(), o->device); 584a6e8d6d9SJagannathan Raman if (dev == NULL) { 585a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: Device %s not found", o->device); 586a6e8d6d9SJagannathan Raman goto fail; 587a6e8d6d9SJagannathan Raman } 588a6e8d6d9SJagannathan Raman 589a6e8d6d9SJagannathan Raman if (!object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 590a6e8d6d9SJagannathan Raman error_setg(errp, "vfu: %s not a PCI device", o->device); 591a6e8d6d9SJagannathan Raman goto fail; 592a6e8d6d9SJagannathan Raman } 593a6e8d6d9SJagannathan Raman 594a6e8d6d9SJagannathan Raman o->pci_dev = PCI_DEVICE(dev); 595a6e8d6d9SJagannathan Raman 596a6e8d6d9SJagannathan Raman object_ref(OBJECT(o->pci_dev)); 597a6e8d6d9SJagannathan Raman 598a6e8d6d9SJagannathan Raman if (pci_is_express(o->pci_dev)) { 599a6e8d6d9SJagannathan Raman pci_type = VFU_PCI_TYPE_EXPRESS; 600a6e8d6d9SJagannathan Raman } 601a6e8d6d9SJagannathan Raman 602a6e8d6d9SJagannathan Raman ret = vfu_pci_init(o->vfu_ctx, pci_type, PCI_HEADER_TYPE_NORMAL, 0); 603a6e8d6d9SJagannathan Raman if (ret < 0) { 604a6e8d6d9SJagannathan Raman error_setg(errp, 605a6e8d6d9SJagannathan Raman "vfu: Failed to attach PCI device %s to context - %s", 606a6e8d6d9SJagannathan Raman o->device, strerror(errno)); 607a6e8d6d9SJagannathan Raman goto fail; 608a6e8d6d9SJagannathan Raman } 609a6e8d6d9SJagannathan Raman 610a6e8d6d9SJagannathan Raman error_setg(&o->unplug_blocker, 611a6e8d6d9SJagannathan Raman "vfu: %s for %s must be deleted before unplugging", 612a6e8d6d9SJagannathan Raman TYPE_VFU_OBJECT, o->device); 613a6e8d6d9SJagannathan Raman qdev_add_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 614a6e8d6d9SJagannathan Raman 61590072f29SJagannathan Raman ret = vfu_setup_region(o->vfu_ctx, VFU_PCI_DEV_CFG_REGION_IDX, 61690072f29SJagannathan Raman pci_config_size(o->pci_dev), &vfu_object_cfg_access, 61790072f29SJagannathan Raman VFU_REGION_FLAG_RW | VFU_REGION_FLAG_ALWAYS_CB, 61890072f29SJagannathan Raman NULL, 0, -1, 0); 61990072f29SJagannathan Raman if (ret < 0) { 62090072f29SJagannathan Raman error_setg(errp, 62190072f29SJagannathan Raman "vfu: Failed to setup config space handlers for %s- %s", 62290072f29SJagannathan Raman o->device, strerror(errno)); 62390072f29SJagannathan Raman goto fail; 62490072f29SJagannathan Raman } 62590072f29SJagannathan Raman 62615ccf9beSJagannathan Raman ret = vfu_setup_device_dma(o->vfu_ctx, &dma_register, &dma_unregister); 62715ccf9beSJagannathan Raman if (ret < 0) { 62815ccf9beSJagannathan Raman error_setg(errp, "vfu: Failed to setup DMA handlers for %s", 62915ccf9beSJagannathan Raman o->device); 63015ccf9beSJagannathan Raman goto fail; 63115ccf9beSJagannathan Raman } 63215ccf9beSJagannathan Raman 633*3123f93dSJagannathan Raman vfu_object_register_bars(o->vfu_ctx, o->pci_dev); 634*3123f93dSJagannathan Raman 6359fb3fba1SJagannathan Raman ret = vfu_realize_ctx(o->vfu_ctx); 6369fb3fba1SJagannathan Raman if (ret < 0) { 6379fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to realize device %s- %s", 6389fb3fba1SJagannathan Raman o->device, strerror(errno)); 6399fb3fba1SJagannathan Raman goto fail; 6409fb3fba1SJagannathan Raman } 6419fb3fba1SJagannathan Raman 6429fb3fba1SJagannathan Raman o->vfu_poll_fd = vfu_get_poll_fd(o->vfu_ctx); 6439fb3fba1SJagannathan Raman if (o->vfu_poll_fd < 0) { 6449fb3fba1SJagannathan Raman error_setg(errp, "vfu: Failed to get poll fd %s", o->device); 6459fb3fba1SJagannathan Raman goto fail; 6469fb3fba1SJagannathan Raman } 6479fb3fba1SJagannathan Raman 6489fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, vfu_object_attach_ctx, NULL, o); 6499fb3fba1SJagannathan Raman 650a6e8d6d9SJagannathan Raman return; 651a6e8d6d9SJagannathan Raman 652a6e8d6d9SJagannathan Raman fail: 653a6e8d6d9SJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 654a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 655a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 656a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 657a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 658a6e8d6d9SJagannathan Raman } 659a6e8d6d9SJagannathan Raman if (o->pci_dev) { 660a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 661a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 662a6e8d6d9SJagannathan Raman } 663a6e8d6d9SJagannathan Raman o->vfu_ctx = NULL; 6648f9a9259SJagannathan Raman } 6658f9a9259SJagannathan Raman 6668f9a9259SJagannathan Raman static void vfu_object_init(Object *obj) 6678f9a9259SJagannathan Raman { 6688f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 6698f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 6708f9a9259SJagannathan Raman 6718f9a9259SJagannathan Raman k->nr_devs++; 6728f9a9259SJagannathan Raman 6738f9a9259SJagannathan Raman if (!object_dynamic_cast(OBJECT(current_machine), TYPE_REMOTE_MACHINE)) { 6748f9a9259SJagannathan Raman error_setg(&o->err, "vfu: %s only compatible with %s machine", 6758f9a9259SJagannathan Raman TYPE_VFU_OBJECT, TYPE_REMOTE_MACHINE); 6768f9a9259SJagannathan Raman return; 6778f9a9259SJagannathan Raman } 67887f7249fSJagannathan Raman 67987f7249fSJagannathan Raman if (!phase_check(PHASE_MACHINE_READY)) { 68087f7249fSJagannathan Raman o->machine_done.notify = vfu_object_machine_done; 68187f7249fSJagannathan Raman qemu_add_machine_init_done_notifier(&o->machine_done); 68287f7249fSJagannathan Raman } 68387f7249fSJagannathan Raman 6849fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 6858f9a9259SJagannathan Raman } 6868f9a9259SJagannathan Raman 6878f9a9259SJagannathan Raman static void vfu_object_finalize(Object *obj) 6888f9a9259SJagannathan Raman { 6898f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_GET_CLASS(obj); 6908f9a9259SJagannathan Raman VfuObject *o = VFU_OBJECT(obj); 6918f9a9259SJagannathan Raman 6928f9a9259SJagannathan Raman k->nr_devs--; 6938f9a9259SJagannathan Raman 6948f9a9259SJagannathan Raman qapi_free_SocketAddress(o->socket); 6958f9a9259SJagannathan Raman 6968f9a9259SJagannathan Raman o->socket = NULL; 6978f9a9259SJagannathan Raman 6989fb3fba1SJagannathan Raman if (o->vfu_poll_fd != -1) { 6999fb3fba1SJagannathan Raman qemu_set_fd_handler(o->vfu_poll_fd, NULL, NULL, NULL); 7009fb3fba1SJagannathan Raman o->vfu_poll_fd = -1; 7019fb3fba1SJagannathan Raman } 7029fb3fba1SJagannathan Raman 70387f7249fSJagannathan Raman if (o->vfu_ctx) { 70487f7249fSJagannathan Raman vfu_destroy_ctx(o->vfu_ctx); 70587f7249fSJagannathan Raman o->vfu_ctx = NULL; 70687f7249fSJagannathan Raman } 70787f7249fSJagannathan Raman 7088f9a9259SJagannathan Raman g_free(o->device); 7098f9a9259SJagannathan Raman 7108f9a9259SJagannathan Raman o->device = NULL; 7118f9a9259SJagannathan Raman 712a6e8d6d9SJagannathan Raman if (o->unplug_blocker && o->pci_dev) { 713a6e8d6d9SJagannathan Raman qdev_del_unplug_blocker(DEVICE(o->pci_dev), o->unplug_blocker); 714a6e8d6d9SJagannathan Raman error_free(o->unplug_blocker); 715a6e8d6d9SJagannathan Raman o->unplug_blocker = NULL; 716a6e8d6d9SJagannathan Raman } 717a6e8d6d9SJagannathan Raman 718a6e8d6d9SJagannathan Raman if (o->pci_dev) { 719a6e8d6d9SJagannathan Raman object_unref(OBJECT(o->pci_dev)); 720a6e8d6d9SJagannathan Raman o->pci_dev = NULL; 721a6e8d6d9SJagannathan Raman } 722a6e8d6d9SJagannathan Raman 7238f9a9259SJagannathan Raman if (!k->nr_devs && vfu_object_auto_shutdown()) { 7248f9a9259SJagannathan Raman qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 7258f9a9259SJagannathan Raman } 72687f7249fSJagannathan Raman 72787f7249fSJagannathan Raman if (o->machine_done.notify) { 72887f7249fSJagannathan Raman qemu_remove_machine_init_done_notifier(&o->machine_done); 72987f7249fSJagannathan Raman o->machine_done.notify = NULL; 73087f7249fSJagannathan Raman } 7318f9a9259SJagannathan Raman } 7328f9a9259SJagannathan Raman 7338f9a9259SJagannathan Raman static void vfu_object_class_init(ObjectClass *klass, void *data) 7348f9a9259SJagannathan Raman { 7358f9a9259SJagannathan Raman VfuObjectClass *k = VFU_OBJECT_CLASS(klass); 7368f9a9259SJagannathan Raman 7378f9a9259SJagannathan Raman k->nr_devs = 0; 7388f9a9259SJagannathan Raman 7398f9a9259SJagannathan Raman object_class_property_add(klass, "socket", "SocketAddress", NULL, 7408f9a9259SJagannathan Raman vfu_object_set_socket, NULL, NULL); 7418f9a9259SJagannathan Raman object_class_property_set_description(klass, "socket", 7428f9a9259SJagannathan Raman "SocketAddress " 7438f9a9259SJagannathan Raman "(ex: type=unix,path=/tmp/sock). " 7448f9a9259SJagannathan Raman "Only UNIX is presently supported"); 7458f9a9259SJagannathan Raman object_class_property_add_str(klass, "device", NULL, 7468f9a9259SJagannathan Raman vfu_object_set_device); 7478f9a9259SJagannathan Raman object_class_property_set_description(klass, "device", 7488f9a9259SJagannathan Raman "device ID - only PCI devices " 7498f9a9259SJagannathan Raman "are presently supported"); 7508f9a9259SJagannathan Raman } 7518f9a9259SJagannathan Raman 7528f9a9259SJagannathan Raman static const TypeInfo vfu_object_info = { 7538f9a9259SJagannathan Raman .name = TYPE_VFU_OBJECT, 7548f9a9259SJagannathan Raman .parent = TYPE_OBJECT, 7558f9a9259SJagannathan Raman .instance_size = sizeof(VfuObject), 7568f9a9259SJagannathan Raman .instance_init = vfu_object_init, 7578f9a9259SJagannathan Raman .instance_finalize = vfu_object_finalize, 7588f9a9259SJagannathan Raman .class_size = sizeof(VfuObjectClass), 7598f9a9259SJagannathan Raman .class_init = vfu_object_class_init, 7608f9a9259SJagannathan Raman .interfaces = (InterfaceInfo[]) { 7618f9a9259SJagannathan Raman { TYPE_USER_CREATABLE }, 7628f9a9259SJagannathan Raman { } 7638f9a9259SJagannathan Raman } 7648f9a9259SJagannathan Raman }; 7658f9a9259SJagannathan Raman 7668f9a9259SJagannathan Raman static void vfu_register_types(void) 7678f9a9259SJagannathan Raman { 7688f9a9259SJagannathan Raman type_register_static(&vfu_object_info); 7698f9a9259SJagannathan Raman } 7708f9a9259SJagannathan Raman 7718f9a9259SJagannathan Raman type_init(vfu_register_types); 772