|  | /* | 
|  | * Virtio QMP helpers | 
|  | * | 
|  | * Copyright IBM, Corp. 2007 | 
|  | * | 
|  | * Authors: | 
|  | *  Anthony Liguori   <aliguori@us.ibm.com> | 
|  | * | 
|  | * SPDX-License-Identifier: GPL-2.0-or-later | 
|  | */ | 
|  |  | 
|  | #include "qemu/osdep.h" | 
|  | #include "virtio-qmp.h" | 
|  |  | 
|  | #include "qapi/error.h" | 
|  | #include "qapi/qapi-commands-virtio.h" | 
|  | #include "qapi/qapi-commands-qom.h" | 
|  | #include "qapi/qmp/qobject.h" | 
|  | #include "qapi/qmp/qjson.h" | 
|  |  | 
|  | #include "standard-headers/linux/virtio_ids.h" | 
|  | #include "standard-headers/linux/vhost_types.h" | 
|  | #include "standard-headers/linux/virtio_blk.h" | 
|  | #include "standard-headers/linux/virtio_console.h" | 
|  | #include "standard-headers/linux/virtio_gpu.h" | 
|  | #include "standard-headers/linux/virtio_net.h" | 
|  | #include "standard-headers/linux/virtio_scsi.h" | 
|  | #include "standard-headers/linux/virtio_i2c.h" | 
|  | #include "standard-headers/linux/virtio_balloon.h" | 
|  | #include "standard-headers/linux/virtio_iommu.h" | 
|  | #include "standard-headers/linux/virtio_mem.h" | 
|  | #include "standard-headers/linux/virtio_vsock.h" | 
|  |  | 
|  | #include CONFIG_DEVICES | 
|  |  | 
|  | #define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \ | 
|  | { .virtio_bit = name, .feature_desc = desc } | 
|  |  | 
|  | enum VhostUserProtocolFeature { | 
|  | VHOST_USER_PROTOCOL_F_MQ = 0, | 
|  | VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, | 
|  | VHOST_USER_PROTOCOL_F_RARP = 2, | 
|  | VHOST_USER_PROTOCOL_F_REPLY_ACK = 3, | 
|  | VHOST_USER_PROTOCOL_F_NET_MTU = 4, | 
|  | VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5, | 
|  | VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, | 
|  | VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, | 
|  | VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, | 
|  | VHOST_USER_PROTOCOL_F_CONFIG = 9, | 
|  | VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10, | 
|  | VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11, | 
|  | VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12, | 
|  | VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13, | 
|  | VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14, | 
|  | VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15, | 
|  | VHOST_USER_PROTOCOL_F_MAX | 
|  | }; | 
|  |  | 
|  | /* Virtio transport features mapping */ | 
|  | static const qmp_virtio_feature_map_t virtio_transport_map[] = { | 
|  | /* Virtio device transport features */ | 
|  | #ifndef VIRTIO_CONFIG_NO_LEGACY | 
|  | FEATURE_ENTRY(VIRTIO_F_NOTIFY_ON_EMPTY, \ | 
|  | "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. " | 
|  | "descs. on VQ"), | 
|  | FEATURE_ENTRY(VIRTIO_F_ANY_LAYOUT, \ | 
|  | "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts"), | 
|  | #endif /* !VIRTIO_CONFIG_NO_LEGACY */ | 
|  | FEATURE_ENTRY(VIRTIO_F_VERSION_1, \ | 
|  | "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"), | 
|  | FEATURE_ENTRY(VIRTIO_F_IOMMU_PLATFORM, \ | 
|  | "VIRTIO_F_IOMMU_PLATFORM: Device can be used on IOMMU platform"), | 
|  | FEATURE_ENTRY(VIRTIO_F_RING_PACKED, \ | 
|  | "VIRTIO_F_RING_PACKED: Device supports packed VQ layout"), | 
|  | FEATURE_ENTRY(VIRTIO_F_IN_ORDER, \ | 
|  | "VIRTIO_F_IN_ORDER: Device uses buffers in same order as made " | 
|  | "available by driver"), | 
|  | FEATURE_ENTRY(VIRTIO_F_ORDER_PLATFORM, \ | 
|  | "VIRTIO_F_ORDER_PLATFORM: Memory accesses ordered by platform"), | 
|  | FEATURE_ENTRY(VIRTIO_F_SR_IOV, \ | 
|  | "VIRTIO_F_SR_IOV: Device supports single root I/O virtualization"), | 
|  | /* Virtio ring transport features */ | 
|  | FEATURE_ENTRY(VIRTIO_RING_F_INDIRECT_DESC, \ | 
|  | "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported"), | 
|  | FEATURE_ENTRY(VIRTIO_RING_F_EVENT_IDX, \ | 
|  | "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled"), | 
|  | { -1, "" } | 
|  | }; | 
|  |  | 
|  | /* Vhost-user protocol features mapping */ | 
|  | static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = { | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_MQ, \ | 
|  | "VHOST_USER_PROTOCOL_F_MQ: Multiqueue protocol supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_LOG_SHMFD, \ | 
|  | "VHOST_USER_PROTOCOL_F_LOG_SHMFD: Shared log memory fd supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RARP, \ | 
|  | "VHOST_USER_PROTOCOL_F_RARP: Vhost-user back-end RARP broadcasting " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_REPLY_ACK, \ | 
|  | "VHOST_USER_PROTOCOL_F_REPLY_ACK: Requested operation status ack. " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_NET_MTU, \ | 
|  | "VHOST_USER_PROTOCOL_F_NET_MTU: Expose host MTU to guest supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_BACKEND_REQ, \ | 
|  | "VHOST_USER_PROTOCOL_F_BACKEND_REQ: Socket fd for back-end initiated " | 
|  | "requests supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, \ | 
|  | "VHOST_USER_PROTOCOL_F_CROSS_ENDIAN: Endianness of VQs for legacy " | 
|  | "devices supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CRYPTO_SESSION, \ | 
|  | "VHOST_USER_PROTOCOL_F_CRYPTO_SESSION: Session creation for crypto " | 
|  | "operations supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_PAGEFAULT, \ | 
|  | "VHOST_USER_PROTOCOL_F_PAGEFAULT: Request servicing on userfaultfd " | 
|  | "for accessed pages supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIG, \ | 
|  | "VHOST_USER_PROTOCOL_F_CONFIG: Vhost-user messaging for virtio " | 
|  | "device configuration space supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD, \ | 
|  | "VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD: Slave fd communication " | 
|  | "channel supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_HOST_NOTIFIER, \ | 
|  | "VHOST_USER_PROTOCOL_F_HOST_NOTIFIER: Host notifiers for specified " | 
|  | "VQs supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD, \ | 
|  | "VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD: Shared inflight I/O buffers " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RESET_DEVICE, \ | 
|  | "VHOST_USER_PROTOCOL_F_RESET_DEVICE: Disabling all rings and " | 
|  | "resetting internal device state supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS, \ | 
|  | "VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS: In-band messaging " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \ | 
|  | "VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for " | 
|  | "memory slots supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  |  | 
|  | /* virtio device configuration statuses */ | 
|  | static const qmp_virtio_feature_map_t virtio_config_status_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER_OK, \ | 
|  | "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready"), | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_FEATURES_OK, \ | 
|  | "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete"), | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER, \ | 
|  | "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device"), | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_NEEDS_RESET, \ | 
|  | "VIRTIO_CONFIG_S_NEEDS_RESET: Irrecoverable error, device needs " | 
|  | "reset"), | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_FAILED, \ | 
|  | "VIRTIO_CONFIG_S_FAILED: Error in guest, device failed"), | 
|  | FEATURE_ENTRY(VIRTIO_CONFIG_S_ACKNOWLEDGE, \ | 
|  | "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found"), | 
|  | { -1, "" } | 
|  | }; | 
|  |  | 
|  | /* virtio-blk features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_BLK | 
|  | static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_SIZE_MAX, \ | 
|  | "VIRTIO_BLK_F_SIZE_MAX: Max segment size is size_max"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_SEG_MAX, \ | 
|  | "VIRTIO_BLK_F_SEG_MAX: Max segments in a request is seg_max"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_GEOMETRY, \ | 
|  | "VIRTIO_BLK_F_GEOMETRY: Legacy geometry available"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_RO, \ | 
|  | "VIRTIO_BLK_F_RO: Device is read-only"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_BLK_SIZE, \ | 
|  | "VIRTIO_BLK_F_BLK_SIZE: Block size of disk available"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_TOPOLOGY, \ | 
|  | "VIRTIO_BLK_F_TOPOLOGY: Topology information available"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_MQ, \ | 
|  | "VIRTIO_BLK_F_MQ: Multiqueue supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_DISCARD, \ | 
|  | "VIRTIO_BLK_F_DISCARD: Discard command supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \ | 
|  | "VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \ | 
|  | "VIRTIO_BLK_F_ZONED: Zoned block devices"), | 
|  | #ifndef VIRTIO_BLK_NO_LEGACY | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_BARRIER, \ | 
|  | "VIRTIO_BLK_F_BARRIER: Request barriers supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_SCSI, \ | 
|  | "VIRTIO_BLK_F_SCSI: SCSI packet commands supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_FLUSH, \ | 
|  | "VIRTIO_BLK_F_FLUSH: Flush command supported"), | 
|  | FEATURE_ENTRY(VIRTIO_BLK_F_CONFIG_WCE, \ | 
|  | "VIRTIO_BLK_F_CONFIG_WCE: Cache writeback and writethrough modes " | 
|  | "supported"), | 
|  | #endif /* !VIRTIO_BLK_NO_LEGACY */ | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-serial features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_SERIAL | 
|  | static const qmp_virtio_feature_map_t virtio_serial_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_CONSOLE_F_SIZE, \ | 
|  | "VIRTIO_CONSOLE_F_SIZE: Host providing console size"), | 
|  | FEATURE_ENTRY(VIRTIO_CONSOLE_F_MULTIPORT, \ | 
|  | "VIRTIO_CONSOLE_F_MULTIPORT: Multiple ports for device supported"), | 
|  | FEATURE_ENTRY(VIRTIO_CONSOLE_F_EMERG_WRITE, \ | 
|  | "VIRTIO_CONSOLE_F_EMERG_WRITE: Emergency write supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-gpu features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_GPU | 
|  | static const qmp_virtio_feature_map_t virtio_gpu_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL, \ | 
|  | "VIRTIO_GPU_F_VIRGL: Virgl 3D mode supported"), | 
|  | FEATURE_ENTRY(VIRTIO_GPU_F_EDID, \ | 
|  | "VIRTIO_GPU_F_EDID: EDID metadata supported"), | 
|  | FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_UUID, \ | 
|  | "VIRTIO_GPU_F_RESOURCE_UUID: Resource UUID assigning supported"), | 
|  | FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_BLOB, \ | 
|  | "VIRTIO_GPU_F_RESOURCE_BLOB: Size-based blob resources supported"), | 
|  | FEATURE_ENTRY(VIRTIO_GPU_F_CONTEXT_INIT, \ | 
|  | "VIRTIO_GPU_F_CONTEXT_INIT: Context types and synchronization " | 
|  | "timelines supported"), | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-input features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_INPUT | 
|  | static const qmp_virtio_feature_map_t virtio_input_feature_map[] = { | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-net features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_NET | 
|  | static const qmp_virtio_feature_map_t virtio_net_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CSUM, \ | 
|  | "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_CSUM, \ | 
|  | "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial " | 
|  | "checksum supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \ | 
|  | "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading " | 
|  | "reconfig. supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_MTU, \ | 
|  | "VIRTIO_NET_F_MTU: Device max MTU reporting supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_MAC, \ | 
|  | "VIRTIO_NET_F_MAC: Device has given MAC address"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO4, \ | 
|  | "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO6, \ | 
|  | "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ECN, \ | 
|  | "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UFO, \ | 
|  | "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO4, \ | 
|  | "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO6, \ | 
|  | "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_HOST_ECN, \ | 
|  | "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_HOST_UFO, \ | 
|  | "VIRTIO_NET_F_HOST_UFO: Device can receive UFO"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_MRG_RXBUF, \ | 
|  | "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_STATUS, \ | 
|  | "VIRTIO_NET_F_STATUS: Configuration status field available"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VQ, \ | 
|  | "VIRTIO_NET_F_CTRL_VQ: Control channel available"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX, \ | 
|  | "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VLAN, \ | 
|  | "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX_EXTRA, \ | 
|  | "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ANNOUNCE, \ | 
|  | "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_MQ, \ | 
|  | "VIRTIO_NET_F_MQ: Multiqueue with automatic receive steering " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \ | 
|  | "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control " | 
|  | "channel"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \ | 
|  | "VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_RSS, \ | 
|  | "VIRTIO_NET_F_RSS: RSS RX steering supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_RSC_EXT, \ | 
|  | "VIRTIO_NET_F_RSC_EXT: Extended coalescing info supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_STANDBY, \ | 
|  | "VIRTIO_NET_F_STANDBY: Device acting as standby for primary " | 
|  | "device with same MAC addr. supported"), | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_SPEED_DUPLEX, \ | 
|  | "VIRTIO_NET_F_SPEED_DUPLEX: Device set linkspeed and duplex"), | 
|  | #ifndef VIRTIO_NET_NO_LEGACY | 
|  | FEATURE_ENTRY(VIRTIO_NET_F_GSO, \ | 
|  | "VIRTIO_NET_F_GSO: Handling GSO-type packets supported"), | 
|  | #endif /* !VIRTIO_NET_NO_LEGACY */ | 
|  | FEATURE_ENTRY(VHOST_NET_F_VIRTIO_NET_HDR, \ | 
|  | "VHOST_NET_F_VIRTIO_NET_HDR: Virtio-net headers for RX and TX " | 
|  | "packets supported"), | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-scsi features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_SCSI | 
|  | static const qmp_virtio_feature_map_t virtio_scsi_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_SCSI_F_INOUT, \ | 
|  | "VIRTIO_SCSI_F_INOUT: Requests including read and writable data " | 
|  | "buffers suppoted"), | 
|  | FEATURE_ENTRY(VIRTIO_SCSI_F_HOTPLUG, \ | 
|  | "VIRTIO_SCSI_F_HOTPLUG: Reporting and handling hot-plug events " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VIRTIO_SCSI_F_CHANGE, \ | 
|  | "VIRTIO_SCSI_F_CHANGE: Reporting and handling LUN changes " | 
|  | "supported"), | 
|  | FEATURE_ENTRY(VIRTIO_SCSI_F_T10_PI, \ | 
|  | "VIRTIO_SCSI_F_T10_PI: T10 info included in request header"), | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio/vhost-user-fs features mapping */ | 
|  | #ifdef CONFIG_VHOST_USER_FS | 
|  | static const qmp_virtio_feature_map_t virtio_fs_feature_map[] = { | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio/vhost-user-i2c features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_I2C_ADAPTER | 
|  | static const qmp_virtio_feature_map_t virtio_i2c_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, \ | 
|  | "VIRTIO_I2C_F_ZERO_LEGNTH_REQUEST: Zero length requests supported"), | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio/vhost-vsock features mapping */ | 
|  | #ifdef CONFIG_VHOST_VSOCK | 
|  | static const qmp_virtio_feature_map_t virtio_vsock_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_VSOCK_F_SEQPACKET, \ | 
|  | "VIRTIO_VSOCK_F_SEQPACKET: SOCK_SEQPACKET supported"), | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-balloon features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_BALLOON | 
|  | static const qmp_virtio_feature_map_t virtio_balloon_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_MUST_TELL_HOST, \ | 
|  | "VIRTIO_BALLOON_F_MUST_TELL_HOST: Tell host before reclaiming " | 
|  | "pages"), | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_STATS_VQ, \ | 
|  | "VIRTIO_BALLOON_F_STATS_VQ: Guest memory stats VQ available"), | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_DEFLATE_ON_OOM, \ | 
|  | "VIRTIO_BALLOON_F_DEFLATE_ON_OOM: Deflate balloon when guest OOM"), | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_FREE_PAGE_HINT, \ | 
|  | "VIRTIO_BALLOON_F_FREE_PAGE_HINT: VQ reporting free pages enabled"), | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_PAGE_POISON, \ | 
|  | "VIRTIO_BALLOON_F_PAGE_POISON: Guest page poisoning enabled"), | 
|  | FEATURE_ENTRY(VIRTIO_BALLOON_F_REPORTING, \ | 
|  | "VIRTIO_BALLOON_F_REPORTING: Page reporting VQ enabled"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-crypto features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_CRYPTO | 
|  | static const qmp_virtio_feature_map_t virtio_crypto_feature_map[] = { | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-iommu features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_IOMMU | 
|  | static const qmp_virtio_feature_map_t virtio_iommu_feature_map[] = { | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_INPUT_RANGE, \ | 
|  | "VIRTIO_IOMMU_F_INPUT_RANGE: Range of available virtual addrs. " | 
|  | "available"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_DOMAIN_RANGE, \ | 
|  | "VIRTIO_IOMMU_F_DOMAIN_RANGE: Number of supported domains " | 
|  | "available"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_MAP_UNMAP, \ | 
|  | "VIRTIO_IOMMU_F_MAP_UNMAP: Map and unmap requests available"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS, \ | 
|  | "VIRTIO_IOMMU_F_BYPASS: Endpoints not attached to domains are in " | 
|  | "bypass mode"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_PROBE, \ | 
|  | "VIRTIO_IOMMU_F_PROBE: Probe requests available"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_MMIO, \ | 
|  | "VIRTIO_IOMMU_F_MMIO: VIRTIO_IOMMU_MAP_F_MMIO flag available"), | 
|  | FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS_CONFIG, \ | 
|  | "VIRTIO_IOMMU_F_BYPASS_CONFIG: Bypass field of IOMMU config " | 
|  | "available"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-mem features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_MEM | 
|  | static const qmp_virtio_feature_map_t virtio_mem_feature_map[] = { | 
|  | #ifndef CONFIG_ACPI | 
|  | FEATURE_ENTRY(VIRTIO_MEM_F_ACPI_PXM, \ | 
|  | "VIRTIO_MEM_F_ACPI_PXM: node_id is an ACPI PXM and is valid"), | 
|  | #endif /* !CONFIG_ACPI */ | 
|  | FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \ | 
|  | "VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be " | 
|  | "accessed"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | /* virtio-rng features mapping */ | 
|  | #ifdef CONFIG_VIRTIO_RNG | 
|  | static const qmp_virtio_feature_map_t virtio_rng_feature_map[] = { | 
|  | FEATURE_ENTRY(VHOST_F_LOG_ALL, \ | 
|  | "VHOST_F_LOG_ALL: Logging write descriptors supported"), | 
|  | FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \ | 
|  | "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features " | 
|  | "negotiation supported"), | 
|  | { -1, "" } | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | #define CONVERT_FEATURES(type, map, is_status, bitmap)   \ | 
|  | ({                                                   \ | 
|  | type *list = NULL;                               \ | 
|  | type *node;                                      \ | 
|  | for (i = 0; map[i].virtio_bit != -1; i++) {      \ | 
|  | if (is_status) {                             \ | 
|  | bit = map[i].virtio_bit;                 \ | 
|  | }                                            \ | 
|  | else {                                       \ | 
|  | bit = 1ULL << map[i].virtio_bit;         \ | 
|  | }                                            \ | 
|  | if ((bitmap & bit) == 0) {                   \ | 
|  | continue;                                \ | 
|  | }                                            \ | 
|  | node = g_new0(type, 1);                      \ | 
|  | node->value = g_strdup(map[i].feature_desc); \ | 
|  | node->next = list;                           \ | 
|  | list = node;                                 \ | 
|  | bitmap ^= bit;                               \ | 
|  | }                                                \ | 
|  | list;                                            \ | 
|  | }) | 
|  |  | 
|  | VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap) | 
|  | { | 
|  | VirtioDeviceStatus *status; | 
|  | uint8_t bit; | 
|  | int i; | 
|  |  | 
|  | status = g_new0(VirtioDeviceStatus, 1); | 
|  | status->statuses = CONVERT_FEATURES(strList, virtio_config_status_map, | 
|  | 1, bitmap); | 
|  | status->has_unknown_statuses = bitmap != 0; | 
|  | if (status->has_unknown_statuses) { | 
|  | status->unknown_statuses = bitmap; | 
|  | } | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap) | 
|  | { | 
|  | VhostDeviceProtocols *vhu_protocols; | 
|  | uint64_t bit; | 
|  | int i; | 
|  |  | 
|  | vhu_protocols = g_new0(VhostDeviceProtocols, 1); | 
|  | vhu_protocols->protocols = | 
|  | CONVERT_FEATURES(strList, | 
|  | vhost_user_protocol_map, 0, bitmap); | 
|  | vhu_protocols->has_unknown_protocols = bitmap != 0; | 
|  | if (vhu_protocols->has_unknown_protocols) { | 
|  | vhu_protocols->unknown_protocols = bitmap; | 
|  | } | 
|  |  | 
|  | return vhu_protocols; | 
|  | } | 
|  |  | 
|  | VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap) | 
|  | { | 
|  | VirtioDeviceFeatures *features; | 
|  | uint64_t bit; | 
|  | int i; | 
|  |  | 
|  | features = g_new0(VirtioDeviceFeatures, 1); | 
|  | features->has_dev_features = true; | 
|  |  | 
|  | /* transport features */ | 
|  | features->transports = CONVERT_FEATURES(strList, virtio_transport_map, 0, | 
|  | bitmap); | 
|  |  | 
|  | /* device features */ | 
|  | switch (device_id) { | 
|  | #ifdef CONFIG_VIRTIO_SERIAL | 
|  | case VIRTIO_ID_CONSOLE: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_serial_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_BLK | 
|  | case VIRTIO_ID_BLOCK: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_blk_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_GPU | 
|  | case VIRTIO_ID_GPU: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_gpu_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_NET | 
|  | case VIRTIO_ID_NET: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_net_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_SCSI | 
|  | case VIRTIO_ID_SCSI: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_scsi_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_BALLOON | 
|  | case VIRTIO_ID_BALLOON: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_balloon_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_IOMMU | 
|  | case VIRTIO_ID_IOMMU: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_iommu_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_INPUT | 
|  | case VIRTIO_ID_INPUT: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_input_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VHOST_USER_FS | 
|  | case VIRTIO_ID_FS: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_fs_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VHOST_VSOCK | 
|  | case VIRTIO_ID_VSOCK: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_vsock_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_CRYPTO | 
|  | case VIRTIO_ID_CRYPTO: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_crypto_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_MEM | 
|  | case VIRTIO_ID_MEM: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_mem_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_I2C_ADAPTER | 
|  | case VIRTIO_ID_I2C_ADAPTER: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_i2c_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VIRTIO_RNG | 
|  | case VIRTIO_ID_RNG: | 
|  | features->dev_features = | 
|  | CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap); | 
|  | break; | 
|  | #endif | 
|  | /* No features */ | 
|  | case VIRTIO_ID_9P: | 
|  | case VIRTIO_ID_PMEM: | 
|  | case VIRTIO_ID_IOMEM: | 
|  | case VIRTIO_ID_RPMSG: | 
|  | case VIRTIO_ID_CLOCK: | 
|  | case VIRTIO_ID_MAC80211_WLAN: | 
|  | case VIRTIO_ID_MAC80211_HWSIM: | 
|  | case VIRTIO_ID_RPROC_SERIAL: | 
|  | case VIRTIO_ID_MEMORY_BALLOON: | 
|  | case VIRTIO_ID_CAIF: | 
|  | case VIRTIO_ID_SIGNAL_DIST: | 
|  | case VIRTIO_ID_PSTORE: | 
|  | case VIRTIO_ID_SOUND: | 
|  | case VIRTIO_ID_BT: | 
|  | case VIRTIO_ID_RPMB: | 
|  | case VIRTIO_ID_VIDEO_ENCODER: | 
|  | case VIRTIO_ID_VIDEO_DECODER: | 
|  | case VIRTIO_ID_SCMI: | 
|  | case VIRTIO_ID_NITRO_SEC_MOD: | 
|  | case VIRTIO_ID_WATCHDOG: | 
|  | case VIRTIO_ID_CAN: | 
|  | case VIRTIO_ID_DMABUF: | 
|  | case VIRTIO_ID_PARAM_SERV: | 
|  | case VIRTIO_ID_AUDIO_POLICY: | 
|  | case VIRTIO_ID_GPIO: | 
|  | break; | 
|  | default: | 
|  | g_assert_not_reached(); | 
|  | } | 
|  |  | 
|  | features->has_unknown_dev_features = bitmap != 0; | 
|  | if (features->has_unknown_dev_features) { | 
|  | features->unknown_dev_features = bitmap; | 
|  | } | 
|  |  | 
|  | return features; | 
|  | } | 
|  |  | 
|  | VirtioInfoList *qmp_x_query_virtio(Error **errp) | 
|  | { | 
|  | VirtioInfoList *list = NULL; | 
|  | VirtioInfo *node; | 
|  | VirtIODevice *vdev; | 
|  |  | 
|  | QTAILQ_FOREACH(vdev, &virtio_list, next) { | 
|  | DeviceState *dev = DEVICE(vdev); | 
|  | Error *err = NULL; | 
|  | QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); | 
|  |  | 
|  | if (err == NULL) { | 
|  | GString *is_realized = qobject_to_json_pretty(obj, true); | 
|  | /* virtio device is NOT realized, remove it from list */ | 
|  | if (!strncmp(is_realized->str, "false", 4)) { | 
|  | QTAILQ_REMOVE(&virtio_list, vdev, next); | 
|  | } else { | 
|  | node = g_new(VirtioInfo, 1); | 
|  | node->path = g_strdup(dev->canonical_path); | 
|  | node->name = g_strdup(vdev->name); | 
|  | QAPI_LIST_PREPEND(list, node); | 
|  | } | 
|  | g_string_free(is_realized, true); | 
|  | } | 
|  | qobject_unref(obj); | 
|  | } | 
|  |  | 
|  | return list; | 
|  | } | 
|  |  | 
|  | VirtIODevice *qmp_find_virtio_device(const char *path) | 
|  | { | 
|  | VirtIODevice *vdev; | 
|  |  | 
|  | QTAILQ_FOREACH(vdev, &virtio_list, next) { | 
|  | DeviceState *dev = DEVICE(vdev); | 
|  |  | 
|  | if (strcmp(dev->canonical_path, path) != 0) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | Error *err = NULL; | 
|  | QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err); | 
|  | if (err == NULL) { | 
|  | GString *is_realized = qobject_to_json_pretty(obj, true); | 
|  | /* virtio device is NOT realized, remove it from list */ | 
|  | if (!strncmp(is_realized->str, "false", 4)) { | 
|  | g_string_free(is_realized, true); | 
|  | qobject_unref(obj); | 
|  | QTAILQ_REMOVE(&virtio_list, vdev, next); | 
|  | return NULL; | 
|  | } | 
|  | g_string_free(is_realized, true); | 
|  | } else { | 
|  | /* virtio device doesn't exist in QOM tree */ | 
|  | QTAILQ_REMOVE(&virtio_list, vdev, next); | 
|  | qobject_unref(obj); | 
|  | return NULL; | 
|  | } | 
|  | /* device exists in QOM tree & is realized */ | 
|  | qobject_unref(obj); | 
|  | return vdev; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) | 
|  | { | 
|  | VirtIODevice *vdev; | 
|  | VirtioStatus *status; | 
|  |  | 
|  | vdev = qmp_find_virtio_device(path); | 
|  | if (vdev == NULL) { | 
|  | error_setg(errp, "Path %s is not a VirtIODevice", path); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | status = g_new0(VirtioStatus, 1); | 
|  | status->name = g_strdup(vdev->name); | 
|  | status->device_id = vdev->device_id; | 
|  | status->vhost_started = vdev->vhost_started; | 
|  | status->guest_features = qmp_decode_features(vdev->device_id, | 
|  | vdev->guest_features); | 
|  | status->host_features = qmp_decode_features(vdev->device_id, | 
|  | vdev->host_features); | 
|  | status->backend_features = qmp_decode_features(vdev->device_id, | 
|  | vdev->backend_features); | 
|  |  | 
|  | switch (vdev->device_endian) { | 
|  | case VIRTIO_DEVICE_ENDIAN_LITTLE: | 
|  | status->device_endian = g_strdup("little"); | 
|  | break; | 
|  | case VIRTIO_DEVICE_ENDIAN_BIG: | 
|  | status->device_endian = g_strdup("big"); | 
|  | break; | 
|  | default: | 
|  | status->device_endian = g_strdup("unknown"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | status->num_vqs = virtio_get_num_queues(vdev); | 
|  | status->status = qmp_decode_status(vdev->status); | 
|  | status->isr = vdev->isr; | 
|  | status->queue_sel = vdev->queue_sel; | 
|  | status->vm_running = vdev->vm_running; | 
|  | status->broken = vdev->broken; | 
|  | status->disabled = vdev->disabled; | 
|  | status->use_started = vdev->use_started; | 
|  | status->started = vdev->started; | 
|  | status->start_on_kick = vdev->start_on_kick; | 
|  | status->disable_legacy_check = vdev->disable_legacy_check; | 
|  | status->bus_name = g_strdup(vdev->bus_name); | 
|  | status->use_guest_notifier_mask = vdev->use_guest_notifier_mask; | 
|  |  | 
|  | if (vdev->vhost_started) { | 
|  | VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); | 
|  | struct vhost_dev *hdev = vdc->get_vhost(vdev); | 
|  |  | 
|  | status->vhost_dev = g_new0(VhostStatus, 1); | 
|  | status->vhost_dev->n_mem_sections = hdev->n_mem_sections; | 
|  | status->vhost_dev->n_tmp_sections = hdev->n_tmp_sections; | 
|  | status->vhost_dev->nvqs = hdev->nvqs; | 
|  | status->vhost_dev->vq_index = hdev->vq_index; | 
|  | status->vhost_dev->features = | 
|  | qmp_decode_features(vdev->device_id, hdev->features); | 
|  | status->vhost_dev->acked_features = | 
|  | qmp_decode_features(vdev->device_id, hdev->acked_features); | 
|  | status->vhost_dev->backend_features = | 
|  | qmp_decode_features(vdev->device_id, hdev->backend_features); | 
|  | status->vhost_dev->protocol_features = | 
|  | qmp_decode_protocols(hdev->protocol_features); | 
|  | status->vhost_dev->max_queues = hdev->max_queues; | 
|  | status->vhost_dev->backend_cap = hdev->backend_cap; | 
|  | status->vhost_dev->log_enabled = hdev->log_enabled; | 
|  | status->vhost_dev->log_size = hdev->log_size; | 
|  | } | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path, | 
|  | uint16_t queue, | 
|  | Error **errp) | 
|  | { | 
|  | VirtIODevice *vdev; | 
|  | VirtVhostQueueStatus *status; | 
|  |  | 
|  | vdev = qmp_find_virtio_device(path); | 
|  | if (vdev == NULL) { | 
|  | error_setg(errp, "Path %s is not a VirtIODevice", path); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (!vdev->vhost_started) { | 
|  | error_setg(errp, "Error: vhost device has not started yet"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); | 
|  | struct vhost_dev *hdev = vdc->get_vhost(vdev); | 
|  |  | 
|  | if (queue < hdev->vq_index || queue >= hdev->vq_index + hdev->nvqs) { | 
|  | error_setg(errp, "Invalid vhost virtqueue number %d", queue); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | status = g_new0(VirtVhostQueueStatus, 1); | 
|  | status->name = g_strdup(vdev->name); | 
|  | status->kick = hdev->vqs[queue].kick; | 
|  | status->call = hdev->vqs[queue].call; | 
|  | status->desc = (uintptr_t)hdev->vqs[queue].desc; | 
|  | status->avail = (uintptr_t)hdev->vqs[queue].avail; | 
|  | status->used = (uintptr_t)hdev->vqs[queue].used; | 
|  | status->num = hdev->vqs[queue].num; | 
|  | status->desc_phys = hdev->vqs[queue].desc_phys; | 
|  | status->desc_size = hdev->vqs[queue].desc_size; | 
|  | status->avail_phys = hdev->vqs[queue].avail_phys; | 
|  | status->avail_size = hdev->vqs[queue].avail_size; | 
|  | status->used_phys = hdev->vqs[queue].used_phys; | 
|  | status->used_size = hdev->vqs[queue].used_size; | 
|  |  | 
|  | return status; | 
|  | } |