#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
#include "qapi/qapi-commands-virtio.h"
-#include "qapi/qapi-commands-qom.h"
-#include "qapi/qapi-visit-virtio.h"
-#include "qapi/qmp/qjson.h"
-#include "cpu.h"
#include "trace.h"
+#include "qemu/defer-call.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qom/object_interfaces.h"
#include "hw/core/cpu.h"
#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
#include "migration/qemu-file-types.h"
#include "qemu/atomic.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "sysemu/dma.h"
#include "sysemu/runstate.h"
+#include "virtio-qmp.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_iommu.h"
#include "standard-headers/linux/virtio_mem.h"
#include "standard-headers/linux/virtio_vsock.h"
-#include CONFIG_DEVICES
-
-/* QAPI list of realized VirtIODevices */
-static QTAILQ_HEAD(, VirtIODevice) virtio_list;
/*
* Maximum size of virtio device config space
*/
#define VHOST_USER_MAX_CONFIG_SIZE 256
-#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_SLAVE_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_SLAVE_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_SLAVE_REQ, \
- "VHOST_USER_PROTOCOL_F_SLAVE_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_SLAVE_SEND_FD, \
- "VHOST_USER_PROTOCOL_F_SLAVE_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"),
-#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
-
/*
* The alignment to use between consumer and producer parts of vring.
* x86 pagesize again. This is the default, used by transports like PCI
}
}
-static void virtio_init_region_cache(VirtIODevice *vdev, int n)
+void virtio_init_region_cache(VirtIODevice *vdev, int n)
{
VirtQueue *vq = &vdev->vq[n];
VRingMemoryRegionCaches *old = vq->vring.caches;
/* Called within rcu_read_lock(). */
static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
{
- uint16_t num_heads = vring_avail_idx(vq) - idx;
+ uint16_t avail_idx, num_heads;
+
+ /* Use shadow index whenever possible. */
+ avail_idx = (vq->shadow_avail_idx != idx) ? vq->shadow_avail_idx
+ : vring_avail_idx(vq);
+ num_heads = avail_idx - idx;
/* Check it isn't doing very strange things with descriptor numbers. */
if (num_heads > vq->vring.num) {
idx, vq->shadow_avail_idx);
return -EINVAL;
}
- /* On success, callers read a descriptor at vq->last_avail_idx.
- * Make sure descriptor read does not bypass avail index read. */
+ /*
+ * On success, callers read a descriptor at vq->last_avail_idx.
+ * Make sure descriptor read does not bypass avail index read.
+ *
+ * This is necessary even if we are using a shadow index, since
+ * the shadow index could have been initialized by calling
+ * vring_avail_idx() outside of this function, i.e., by a guest
+ * memory read not accompanied by a barrier.
+ */
if (num_heads) {
smp_rmb();
}
VIRTQUEUE_READ_DESC_MORE = 1, /* more buffers in chain */
};
+/* Reads the 'desc->next' descriptor into '*desc'. */
static int virtqueue_split_read_next_desc(VirtIODevice *vdev, VRingDesc *desc,
MemoryRegionCache *desc_cache,
- unsigned int max, unsigned int *next)
+ unsigned int max)
{
/* If this descriptor says it doesn't chain, we're done. */
if (!(desc->flags & VRING_DESC_F_NEXT)) {
}
/* Check they're not leading us off end of descriptors. */
- *next = desc->next;
- /* Make sure compiler knows to grab that: we don't want it changing! */
- smp_wmb();
-
- if (*next >= max) {
- virtio_error(vdev, "Desc next is %u", *next);
+ if (desc->next >= max) {
+ virtio_error(vdev, "Desc next is %u", desc->next);
return VIRTQUEUE_READ_DESC_ERROR;
}
- vring_split_desc_read(vdev, desc, desc_cache, *next);
+ vring_split_desc_read(vdev, desc, desc_cache, desc->next);
return VIRTQUEUE_READ_DESC_MORE;
}
VRingMemoryRegionCaches *caches)
{
VirtIODevice *vdev = vq->vdev;
- unsigned int max, idx;
+ unsigned int idx;
unsigned int total_bufs, in_total, out_total;
- MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+ MemoryRegionCache indirect_desc_cache;
int64_t len = 0;
int rc;
+ address_space_cache_init_empty(&indirect_desc_cache);
+
idx = vq->last_avail_idx;
total_bufs = in_total = out_total = 0;
- max = vq->vring.num;
-
while ((rc = virtqueue_num_heads(vq, idx)) > 0) {
MemoryRegionCache *desc_cache = &caches->desc;
unsigned int num_bufs;
VRingDesc desc;
unsigned int i;
+ unsigned int max = vq->vring.num;
num_bufs = total_bufs;
goto done;
}
- rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max, &i);
+ rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max);
} while (rc == VIRTQUEUE_READ_DESC_MORE);
if (rc == VIRTQUEUE_READ_DESC_ERROR) {
VRingMemoryRegionCaches *caches)
{
VirtIODevice *vdev = vq->vdev;
- unsigned int max, idx;
+ unsigned int idx;
unsigned int total_bufs, in_total, out_total;
+ MemoryRegionCache indirect_desc_cache;
MemoryRegionCache *desc_cache;
- MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
int64_t len = 0;
VRingPackedDesc desc;
bool wrap_counter;
+ address_space_cache_init_empty(&indirect_desc_cache);
+
idx = vq->last_avail_idx;
wrap_counter = vq->last_avail_wrap_counter;
total_bufs = in_total = out_total = 0;
- max = vq->vring.num;
-
for (;;) {
unsigned int num_bufs = total_bufs;
unsigned int i = idx;
int rc;
+ unsigned int max = vq->vring.num;
desc_cache = &caches->desc;
+
vring_packed_desc_read(vdev, &desc, desc_cache, idx, true);
if (!is_desc_avail(desc.flags, wrap_counter)) {
break;
{
unsigned int i, head, max;
VRingMemoryRegionCaches *caches;
- MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+ MemoryRegionCache indirect_desc_cache;
MemoryRegionCache *desc_cache;
int64_t len;
VirtIODevice *vdev = vq->vdev;
VRingDesc desc;
int rc;
+ address_space_cache_init_empty(&indirect_desc_cache);
+
RCU_READ_LOCK_GUARD();
if (virtio_queue_empty_rcu(vq)) {
goto done;
goto err_undo_map;
}
- rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max, &i);
+ rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max);
} while (rc == VIRTQUEUE_READ_DESC_MORE);
if (rc == VIRTQUEUE_READ_DESC_ERROR) {
{
unsigned int i, max;
VRingMemoryRegionCaches *caches;
- MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+ MemoryRegionCache indirect_desc_cache;
MemoryRegionCache *desc_cache;
int64_t len;
VirtIODevice *vdev = vq->vdev;
uint16_t id;
int rc;
+ address_space_cache_init_empty(&indirect_desc_cache);
+
RCU_READ_LOCK_GUARD();
if (virtio_queue_packed_empty_rcu(vq)) {
goto done;
* being converted to LOG_GUEST_ERROR.
*
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
- error_report("queue_enable is only suppported in devices of virtio "
+ error_report("queue_enable is only supported in devices of virtio "
"1.0 or later.");
}
*/
vdev->device_endian = virtio_default_endian();
}
+ if (vdev->vhost_started) {
+ vhost_reset_device(k->get_vhost(vdev));
+ }
+
if (k->reset) {
k->reset(vdev);
}
}
}
-uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldub_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = lduw_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldl_p(vdev->config + addr);
- return val;
-}
-
-void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stb_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stw_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stl_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldub_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = lduw_le_p(vdev->config + addr);
- return val;
-}
-
-uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return (uint32_t)-1;
- }
-
- k->get_config(vdev, vdev->config);
-
- val = ldl_le_p(vdev->config + addr);
- return val;
-}
-
-void virtio_config_modern_writeb(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint8_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stb_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_modern_writew(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint16_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stw_le_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
-void virtio_config_modern_writel(VirtIODevice *vdev,
- uint32_t addr, uint32_t data)
-{
- VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
- uint32_t val = data;
-
- if (addr + sizeof(val) > vdev->config_len) {
- return;
- }
-
- stl_le_p(vdev->config + addr, val);
-
- if (k->set_config) {
- k->set_config(vdev, vdev->config);
- }
-}
-
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
{
if (!vdev->vq[n].vring.num) {
}
}
+/* Batch irqs while inside a defer_call_begin()/defer_call_end() section */
+static void virtio_notify_irqfd_deferred_fn(void *opaque)
+{
+ EventNotifier *notifier = opaque;
+ VirtQueue *vq = container_of(notifier, VirtQueue, guest_notifier);
+
+ trace_virtio_notify_irqfd_deferred_fn(vq->vdev, vq);
+ event_notifier_set(notifier);
+}
+
void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq)
{
WITH_RCU_READ_LOCK_GUARD() {
* to an atomic operation.
*/
virtio_set_isr(vq->vdev, 0x1);
- event_notifier_set(&vq->guest_notifier);
+ defer_call(virtio_notify_irqfd_deferred_fn, &vq->guest_notifier);
}
static void virtio_irq(VirtQueue *vq)
}
/* A wrapper for use as a VMState .get function */
-static int virtio_device_get(QEMUFile *f, void *opaque, size_t size,
- const VMStateField *field)
+static int coroutine_mixed_fn
+virtio_device_get(QEMUFile *f, void *opaque, size_t size,
+ const VMStateField *field)
{
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
DeviceClass *dc = DEVICE_CLASS(VIRTIO_DEVICE_GET_CLASS(vdev));
return bad ? -1 : 0;
}
+typedef struct VirtioSetFeaturesNocheckData {
+ Coroutine *co;
+ VirtIODevice *vdev;
+ uint64_t val;
+ int ret;
+} VirtioSetFeaturesNocheckData;
+
+static void virtio_set_features_nocheck_bh(void *opaque)
+{
+ VirtioSetFeaturesNocheckData *data = opaque;
+
+ data->ret = virtio_set_features_nocheck(data->vdev, data->val);
+ aio_co_wake(data->co);
+}
+
+static int coroutine_mixed_fn
+virtio_set_features_nocheck_maybe_co(VirtIODevice *vdev, uint64_t val)
+{
+ if (qemu_in_coroutine()) {
+ VirtioSetFeaturesNocheckData data = {
+ .co = qemu_coroutine_self(),
+ .vdev = vdev,
+ .val = val,
+ };
+ aio_bh_schedule_oneshot(qemu_get_current_aio_context(),
+ virtio_set_features_nocheck_bh, &data);
+ qemu_coroutine_yield();
+ return data.ret;
+ } else {
+ return virtio_set_features_nocheck(vdev, val);
+ }
+}
+
int virtio_set_features(VirtIODevice *vdev, uint64_t val)
{
int ret;
return config_size;
}
-int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
+int coroutine_mixed_fn
+virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
{
int i, ret;
int32_t config_len;
* host_features.
*/
uint64_t features64 = vdev->guest_features;
- if (virtio_set_features_nocheck(vdev, features64) < 0) {
+ if (virtio_set_features_nocheck_maybe_co(vdev, features64) < 0) {
error_report("Features 0x%" PRIx64 " unsupported. "
"Allowed features: 0x%" PRIx64,
features64, vdev->host_features);
return -1;
}
} else {
- if (virtio_set_features_nocheck(vdev, features) < 0) {
+ if (virtio_set_features_nocheck_maybe_co(vdev, features) < 0) {
error_report("Features 0x%x unsupported. "
"Allowed features: 0x%" PRIx64,
features, vdev->host_features);
vq->last_avail_wrap_counter =
vq->shadow_avail_wrap_counter = !!(idx & 0x8000);
idx >>= 16;
- vq->used_idx = idx & 0x7ffff;
+ vq->used_idx = idx & 0x7fff;
vq->used_wrap_counter = !!(idx & 0x8000);
}
virtio_irq(vq);
}
}
+static void virtio_config_guest_notifier_read(EventNotifier *n)
+{
+ VirtIODevice *vdev = container_of(n, VirtIODevice, config_notifier);
+ if (event_notifier_test_and_clear(n)) {
+ virtio_notify_config(vdev);
+ }
+}
void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
bool with_irqfd)
{
}
}
+void virtio_config_set_guest_notifier_fd_handler(VirtIODevice *vdev,
+ bool assign, bool with_irqfd)
+{
+ EventNotifier *n;
+ n = &vdev->config_notifier;
+ if (assign && !with_irqfd) {
+ event_notifier_set_handler(n, virtio_config_guest_notifier_read);
+ } else {
+ event_notifier_set_handler(n, NULL);
+ }
+ if (!assign) {
+ /* Test and clear notifier before closing it,*/
+ /* in case poll callback didn't have time to run. */
+ virtio_config_guest_notifier_read(n);
+ }
+}
+
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{
return &vq->guest_notifier;
void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
{
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
+ aio_set_event_notifier(ctx, &vq->host_notifier,
virtio_queue_host_notifier_read,
virtio_queue_host_notifier_aio_poll,
virtio_queue_host_notifier_aio_poll_ready);
*/
void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx)
{
- aio_set_event_notifier(ctx, &vq->host_notifier, true,
+ aio_set_event_notifier(ctx, &vq->host_notifier,
virtio_queue_host_notifier_read,
NULL, NULL);
}
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
{
- aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
- /* Test and clear notifier before after disabling event,
- * in case poll callback didn't have time to run. */
- virtio_queue_host_notifier_read(&vq->host_notifier);
+ aio_set_event_notifier(ctx, &vq->host_notifier, NULL, NULL, NULL);
}
void virtio_queue_host_notifier_read(EventNotifier *n)
return &vq->host_notifier;
}
+EventNotifier *virtio_config_get_guest_notifier(VirtIODevice *vdev)
+{
+ return &vdev->config_notifier;
+}
+
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled)
{
vq->host_notifier_enabled = enabled;
vdev->listener.commit = virtio_memory_listener_commit;
vdev->listener.name = "virtio";
memory_listener_register(&vdev->listener, vdev->dma_as);
- QTAILQ_INSERT_TAIL(&virtio_list, vdev, next);
}
static void virtio_device_unrealize(DeviceState *dev)
vdc->unrealize(dev);
}
- QTAILQ_REMOVE(&virtio_list, vdev, next);
g_free(vdev->bus_name);
vdev->bus_name = NULL;
}
vdc->stop_ioeventfd = virtio_device_stop_ioeventfd_impl;
vdc->legacy_features |= VIRTIO_LEGACY_FEATURES;
-
- QTAILQ_INIT(&virtio_list);
}
bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
return virtio_bus_ioeventfd_enabled(vbus);
}
-VirtioInfoList *qmp_x_query_virtio(Error **errp)
-{
- VirtioInfoList *list = NULL;
- VirtioInfoList *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_new0(VirtioInfoList, 1);
- node->value = g_new(VirtioInfo, 1);
- node->value->path = g_strdup(dev->canonical_path);
- node->value->name = g_strdup(vdev->name);
- QAPI_LIST_PREPEND(list, node->value);
- }
- g_string_free(is_realized, true);
- }
- qobject_unref(obj);
- }
-
- return list;
-}
-
-static VirtIODevice *virtio_device_find(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;
-}
-
-#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; \
- })
-
-static 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;
-}
-
-static 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;
-}
-
-static 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;
-}
-
-VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
-{
- VirtIODevice *vdev;
- VirtioStatus *status;
-
- vdev = virtio_device_find(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 = virtio_device_find(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;
-}
-
VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path,
uint16_t queue,
Error **errp)
VirtIODevice *vdev;
VirtQueueStatus *status;
- vdev = virtio_device_find(path);
+ vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIODevice", path);
return NULL;
VirtQueue *vq;
VirtioQueueElement *element = NULL;
- vdev = virtio_device_find(path);
+ vdev = qmp_find_virtio_device(path);
if (vdev == NULL) {
error_setg(errp, "Path %s is not a VirtIO device", path);
return NULL;
} else {
unsigned int head, i, max;
VRingMemoryRegionCaches *caches;
- MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+ MemoryRegionCache indirect_desc_cache;
MemoryRegionCache *desc_cache;
VRingDesc desc;
VirtioRingDescList *list = NULL;
VirtioRingDescList *node;
int rc; int ndescs;
+ address_space_cache_init_empty(&indirect_desc_cache);
+
RCU_READ_LOCK_GUARD();
max = vq->vring.num;
list = node;
ndescs++;
- rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache,
- max, &i);
+ rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache, max);
} while (rc == VIRTQUEUE_READ_DESC_MORE);
element->descs = list;
done: