xref: /openbmc/qemu/hw/virtio/virtio-qmp.c (revision 21063bce)
1 /*
2  * Virtio QMP helpers
3  *
4  * Copyright IBM, Corp. 2007
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "qemu/osdep.h"
13 #include "virtio-qmp.h"
14 
15 #include "qapi/error.h"
16 #include "qapi/qapi-commands-virtio.h"
17 #include "qapi/qapi-commands-qom.h"
18 #include "qapi/qmp/qobject.h"
19 #include "qapi/qmp/qjson.h"
20 
21 #include "standard-headers/linux/virtio_ids.h"
22 #include "standard-headers/linux/vhost_types.h"
23 #include "standard-headers/linux/virtio_blk.h"
24 #include "standard-headers/linux/virtio_console.h"
25 #include "standard-headers/linux/virtio_gpu.h"
26 #include "standard-headers/linux/virtio_net.h"
27 #include "standard-headers/linux/virtio_scsi.h"
28 #include "standard-headers/linux/virtio_i2c.h"
29 #include "standard-headers/linux/virtio_balloon.h"
30 #include "standard-headers/linux/virtio_iommu.h"
31 #include "standard-headers/linux/virtio_mem.h"
32 #include "standard-headers/linux/virtio_vsock.h"
33 
34 #include CONFIG_DEVICES
35 
36 #define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \
37     { .virtio_bit = name, .feature_desc = desc }
38 
39 enum VhostUserProtocolFeature {
40     VHOST_USER_PROTOCOL_F_MQ = 0,
41     VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
42     VHOST_USER_PROTOCOL_F_RARP = 2,
43     VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
44     VHOST_USER_PROTOCOL_F_NET_MTU = 4,
45     VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5,
46     VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
47     VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
48     VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
49     VHOST_USER_PROTOCOL_F_CONFIG = 9,
50     VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10,
51     VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
52     VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
53     VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
54     VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
55     VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
56     VHOST_USER_PROTOCOL_F_MAX
57 };
58 
59 /* Virtio transport features mapping */
60 static const qmp_virtio_feature_map_t virtio_transport_map[] = {
61     /* Virtio device transport features */
62 #ifndef VIRTIO_CONFIG_NO_LEGACY
63     FEATURE_ENTRY(VIRTIO_F_NOTIFY_ON_EMPTY, \
64             "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. "
65             "descs. on VQ"),
66     FEATURE_ENTRY(VIRTIO_F_ANY_LAYOUT, \
67             "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts"),
68 #endif /* !VIRTIO_CONFIG_NO_LEGACY */
69     FEATURE_ENTRY(VIRTIO_F_VERSION_1, \
70             "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"),
71     FEATURE_ENTRY(VIRTIO_F_IOMMU_PLATFORM, \
72             "VIRTIO_F_IOMMU_PLATFORM: Device can be used on IOMMU platform"),
73     FEATURE_ENTRY(VIRTIO_F_RING_PACKED, \
74             "VIRTIO_F_RING_PACKED: Device supports packed VQ layout"),
75     FEATURE_ENTRY(VIRTIO_F_IN_ORDER, \
76             "VIRTIO_F_IN_ORDER: Device uses buffers in same order as made "
77             "available by driver"),
78     FEATURE_ENTRY(VIRTIO_F_ORDER_PLATFORM, \
79             "VIRTIO_F_ORDER_PLATFORM: Memory accesses ordered by platform"),
80     FEATURE_ENTRY(VIRTIO_F_SR_IOV, \
81             "VIRTIO_F_SR_IOV: Device supports single root I/O virtualization"),
82     /* Virtio ring transport features */
83     FEATURE_ENTRY(VIRTIO_RING_F_INDIRECT_DESC, \
84             "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported"),
85     FEATURE_ENTRY(VIRTIO_RING_F_EVENT_IDX, \
86             "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled"),
87     { -1, "" }
88 };
89 
90 /* Vhost-user protocol features mapping */
91 static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
92     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_MQ, \
93             "VHOST_USER_PROTOCOL_F_MQ: Multiqueue protocol supported"),
94     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_LOG_SHMFD, \
95             "VHOST_USER_PROTOCOL_F_LOG_SHMFD: Shared log memory fd supported"),
96     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RARP, \
97             "VHOST_USER_PROTOCOL_F_RARP: Vhost-user back-end RARP broadcasting "
98             "supported"),
99     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_REPLY_ACK, \
100             "VHOST_USER_PROTOCOL_F_REPLY_ACK: Requested operation status ack. "
101             "supported"),
102     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_NET_MTU, \
103             "VHOST_USER_PROTOCOL_F_NET_MTU: Expose host MTU to guest supported"),
104     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_BACKEND_REQ, \
105             "VHOST_USER_PROTOCOL_F_BACKEND_REQ: Socket fd for back-end initiated "
106             "requests supported"),
107     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CROSS_ENDIAN, \
108             "VHOST_USER_PROTOCOL_F_CROSS_ENDIAN: Endianness of VQs for legacy "
109             "devices supported"),
110     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CRYPTO_SESSION, \
111             "VHOST_USER_PROTOCOL_F_CRYPTO_SESSION: Session creation for crypto "
112             "operations supported"),
113     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_PAGEFAULT, \
114             "VHOST_USER_PROTOCOL_F_PAGEFAULT: Request servicing on userfaultfd "
115             "for accessed pages supported"),
116     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIG, \
117             "VHOST_USER_PROTOCOL_F_CONFIG: Vhost-user messaging for virtio "
118             "device configuration space supported"),
119     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD, \
120             "VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD: Slave fd communication "
121             "channel supported"),
122     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_HOST_NOTIFIER, \
123             "VHOST_USER_PROTOCOL_F_HOST_NOTIFIER: Host notifiers for specified "
124             "VQs supported"),
125     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD, \
126             "VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD: Shared inflight I/O buffers "
127             "supported"),
128     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_RESET_DEVICE, \
129             "VHOST_USER_PROTOCOL_F_RESET_DEVICE: Disabling all rings and "
130             "resetting internal device state supported"),
131     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS, \
132             "VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS: In-band messaging "
133             "supported"),
134     FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \
135             "VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for "
136             "memory slots supported"),
137     { -1, "" }
138 };
139 
140 /* virtio device configuration statuses */
141 static const qmp_virtio_feature_map_t virtio_config_status_map[] = {
142     FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER_OK, \
143             "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready"),
144     FEATURE_ENTRY(VIRTIO_CONFIG_S_FEATURES_OK, \
145             "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete"),
146     FEATURE_ENTRY(VIRTIO_CONFIG_S_DRIVER, \
147             "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device"),
148     FEATURE_ENTRY(VIRTIO_CONFIG_S_NEEDS_RESET, \
149             "VIRTIO_CONFIG_S_NEEDS_RESET: Irrecoverable error, device needs "
150             "reset"),
151     FEATURE_ENTRY(VIRTIO_CONFIG_S_FAILED, \
152             "VIRTIO_CONFIG_S_FAILED: Error in guest, device failed"),
153     FEATURE_ENTRY(VIRTIO_CONFIG_S_ACKNOWLEDGE, \
154             "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found"),
155     { -1, "" }
156 };
157 
158 /* virtio-blk features mapping */
159 #ifdef CONFIG_VIRTIO_BLK
160 static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = {
161     FEATURE_ENTRY(VIRTIO_BLK_F_SIZE_MAX, \
162             "VIRTIO_BLK_F_SIZE_MAX: Max segment size is size_max"),
163     FEATURE_ENTRY(VIRTIO_BLK_F_SEG_MAX, \
164             "VIRTIO_BLK_F_SEG_MAX: Max segments in a request is seg_max"),
165     FEATURE_ENTRY(VIRTIO_BLK_F_GEOMETRY, \
166             "VIRTIO_BLK_F_GEOMETRY: Legacy geometry available"),
167     FEATURE_ENTRY(VIRTIO_BLK_F_RO, \
168             "VIRTIO_BLK_F_RO: Device is read-only"),
169     FEATURE_ENTRY(VIRTIO_BLK_F_BLK_SIZE, \
170             "VIRTIO_BLK_F_BLK_SIZE: Block size of disk available"),
171     FEATURE_ENTRY(VIRTIO_BLK_F_TOPOLOGY, \
172             "VIRTIO_BLK_F_TOPOLOGY: Topology information available"),
173     FEATURE_ENTRY(VIRTIO_BLK_F_MQ, \
174             "VIRTIO_BLK_F_MQ: Multiqueue supported"),
175     FEATURE_ENTRY(VIRTIO_BLK_F_DISCARD, \
176             "VIRTIO_BLK_F_DISCARD: Discard command supported"),
177     FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \
178             "VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"),
179 #ifndef VIRTIO_BLK_NO_LEGACY
180     FEATURE_ENTRY(VIRTIO_BLK_F_BARRIER, \
181             "VIRTIO_BLK_F_BARRIER: Request barriers supported"),
182     FEATURE_ENTRY(VIRTIO_BLK_F_SCSI, \
183             "VIRTIO_BLK_F_SCSI: SCSI packet commands supported"),
184     FEATURE_ENTRY(VIRTIO_BLK_F_FLUSH, \
185             "VIRTIO_BLK_F_FLUSH: Flush command supported"),
186     FEATURE_ENTRY(VIRTIO_BLK_F_CONFIG_WCE, \
187             "VIRTIO_BLK_F_CONFIG_WCE: Cache writeback and writethrough modes "
188             "supported"),
189 #endif /* !VIRTIO_BLK_NO_LEGACY */
190     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
191             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
192     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
193             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
194             "negotiation supported"),
195     { -1, "" }
196 };
197 #endif
198 
199 /* virtio-serial features mapping */
200 #ifdef CONFIG_VIRTIO_SERIAL
201 static const qmp_virtio_feature_map_t virtio_serial_feature_map[] = {
202     FEATURE_ENTRY(VIRTIO_CONSOLE_F_SIZE, \
203             "VIRTIO_CONSOLE_F_SIZE: Host providing console size"),
204     FEATURE_ENTRY(VIRTIO_CONSOLE_F_MULTIPORT, \
205             "VIRTIO_CONSOLE_F_MULTIPORT: Multiple ports for device supported"),
206     FEATURE_ENTRY(VIRTIO_CONSOLE_F_EMERG_WRITE, \
207             "VIRTIO_CONSOLE_F_EMERG_WRITE: Emergency write supported"),
208     { -1, "" }
209 };
210 #endif
211 
212 /* virtio-gpu features mapping */
213 #ifdef CONFIG_VIRTIO_GPU
214 static const qmp_virtio_feature_map_t virtio_gpu_feature_map[] = {
215     FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL, \
216             "VIRTIO_GPU_F_VIRGL: Virgl 3D mode supported"),
217     FEATURE_ENTRY(VIRTIO_GPU_F_EDID, \
218             "VIRTIO_GPU_F_EDID: EDID metadata supported"),
219     FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_UUID, \
220             "VIRTIO_GPU_F_RESOURCE_UUID: Resource UUID assigning supported"),
221     FEATURE_ENTRY(VIRTIO_GPU_F_RESOURCE_BLOB, \
222             "VIRTIO_GPU_F_RESOURCE_BLOB: Size-based blob resources supported"),
223     FEATURE_ENTRY(VIRTIO_GPU_F_CONTEXT_INIT, \
224             "VIRTIO_GPU_F_CONTEXT_INIT: Context types and synchronization "
225             "timelines supported"),
226     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
227             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
228     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
229             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
230             "negotiation supported"),
231     { -1, "" }
232 };
233 #endif
234 
235 /* virtio-input features mapping */
236 #ifdef CONFIG_VIRTIO_INPUT
237 static const qmp_virtio_feature_map_t virtio_input_feature_map[] = {
238     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
239             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
240     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
241             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
242             "negotiation supported"),
243     { -1, "" }
244 };
245 #endif
246 
247 /* virtio-net features mapping */
248 #ifdef CONFIG_VIRTIO_NET
249 static const qmp_virtio_feature_map_t virtio_net_feature_map[] = {
250     FEATURE_ENTRY(VIRTIO_NET_F_CSUM, \
251             "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum "
252             "supported"),
253     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_CSUM, \
254             "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial "
255             "checksum supported"),
256     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
257             "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading "
258             "reconfig. supported"),
259     FEATURE_ENTRY(VIRTIO_NET_F_MTU, \
260             "VIRTIO_NET_F_MTU: Device max MTU reporting supported"),
261     FEATURE_ENTRY(VIRTIO_NET_F_MAC, \
262             "VIRTIO_NET_F_MAC: Device has given MAC address"),
263     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO4, \
264             "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4"),
265     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_TSO6, \
266             "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6"),
267     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ECN, \
268             "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN"),
269     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_UFO, \
270             "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO"),
271     FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO4, \
272             "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4"),
273     FEATURE_ENTRY(VIRTIO_NET_F_HOST_TSO6, \
274             "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6"),
275     FEATURE_ENTRY(VIRTIO_NET_F_HOST_ECN, \
276             "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN"),
277     FEATURE_ENTRY(VIRTIO_NET_F_HOST_UFO, \
278             "VIRTIO_NET_F_HOST_UFO: Device can receive UFO"),
279     FEATURE_ENTRY(VIRTIO_NET_F_MRG_RXBUF, \
280             "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers"),
281     FEATURE_ENTRY(VIRTIO_NET_F_STATUS, \
282             "VIRTIO_NET_F_STATUS: Configuration status field available"),
283     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VQ, \
284             "VIRTIO_NET_F_CTRL_VQ: Control channel available"),
285     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX, \
286             "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported"),
287     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_VLAN, \
288             "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported"),
289     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_RX_EXTRA, \
290             "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported"),
291     FEATURE_ENTRY(VIRTIO_NET_F_GUEST_ANNOUNCE, \
292             "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets "
293             "supported"),
294     FEATURE_ENTRY(VIRTIO_NET_F_MQ, \
295             "VIRTIO_NET_F_MQ: Multiqueue with automatic receive steering "
296             "supported"),
297     FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \
298             "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control "
299             "channel"),
300     FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \
301             "VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"),
302     FEATURE_ENTRY(VIRTIO_NET_F_RSS, \
303             "VIRTIO_NET_F_RSS: RSS RX steering supported"),
304     FEATURE_ENTRY(VIRTIO_NET_F_RSC_EXT, \
305             "VIRTIO_NET_F_RSC_EXT: Extended coalescing info supported"),
306     FEATURE_ENTRY(VIRTIO_NET_F_STANDBY, \
307             "VIRTIO_NET_F_STANDBY: Device acting as standby for primary "
308             "device with same MAC addr. supported"),
309     FEATURE_ENTRY(VIRTIO_NET_F_SPEED_DUPLEX, \
310             "VIRTIO_NET_F_SPEED_DUPLEX: Device set linkspeed and duplex"),
311 #ifndef VIRTIO_NET_NO_LEGACY
312     FEATURE_ENTRY(VIRTIO_NET_F_GSO, \
313             "VIRTIO_NET_F_GSO: Handling GSO-type packets supported"),
314 #endif /* !VIRTIO_NET_NO_LEGACY */
315     FEATURE_ENTRY(VHOST_NET_F_VIRTIO_NET_HDR, \
316             "VHOST_NET_F_VIRTIO_NET_HDR: Virtio-net headers for RX and TX "
317             "packets supported"),
318     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
319             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
320     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
321             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
322             "negotiation supported"),
323     { -1, "" }
324 };
325 #endif
326 
327 /* virtio-scsi features mapping */
328 #ifdef CONFIG_VIRTIO_SCSI
329 static const qmp_virtio_feature_map_t virtio_scsi_feature_map[] = {
330     FEATURE_ENTRY(VIRTIO_SCSI_F_INOUT, \
331             "VIRTIO_SCSI_F_INOUT: Requests including read and writable data "
332             "buffers suppoted"),
333     FEATURE_ENTRY(VIRTIO_SCSI_F_HOTPLUG, \
334             "VIRTIO_SCSI_F_HOTPLUG: Reporting and handling hot-plug events "
335             "supported"),
336     FEATURE_ENTRY(VIRTIO_SCSI_F_CHANGE, \
337             "VIRTIO_SCSI_F_CHANGE: Reporting and handling LUN changes "
338             "supported"),
339     FEATURE_ENTRY(VIRTIO_SCSI_F_T10_PI, \
340             "VIRTIO_SCSI_F_T10_PI: T10 info included in request header"),
341     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
342             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
343     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
344             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
345             "negotiation supported"),
346     { -1, "" }
347 };
348 #endif
349 
350 /* virtio/vhost-user-fs features mapping */
351 #ifdef CONFIG_VHOST_USER_FS
352 static const qmp_virtio_feature_map_t virtio_fs_feature_map[] = {
353     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
354             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
355     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
356             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
357             "negotiation supported"),
358     { -1, "" }
359 };
360 #endif
361 
362 /* virtio/vhost-user-i2c features mapping */
363 #ifdef CONFIG_VIRTIO_I2C_ADAPTER
364 static const qmp_virtio_feature_map_t virtio_i2c_feature_map[] = {
365     FEATURE_ENTRY(VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, \
366             "VIRTIO_I2C_F_ZERO_LEGNTH_REQUEST: Zero length requests supported"),
367     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
368             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
369     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
370             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
371             "negotiation supported"),
372     { -1, "" }
373 };
374 #endif
375 
376 /* virtio/vhost-vsock features mapping */
377 #ifdef CONFIG_VHOST_VSOCK
378 static const qmp_virtio_feature_map_t virtio_vsock_feature_map[] = {
379     FEATURE_ENTRY(VIRTIO_VSOCK_F_SEQPACKET, \
380             "VIRTIO_VSOCK_F_SEQPACKET: SOCK_SEQPACKET supported"),
381     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
382             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
383     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
384             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
385             "negotiation supported"),
386     { -1, "" }
387 };
388 #endif
389 
390 /* virtio-balloon features mapping */
391 #ifdef CONFIG_VIRTIO_BALLOON
392 static const qmp_virtio_feature_map_t virtio_balloon_feature_map[] = {
393     FEATURE_ENTRY(VIRTIO_BALLOON_F_MUST_TELL_HOST, \
394             "VIRTIO_BALLOON_F_MUST_TELL_HOST: Tell host before reclaiming "
395             "pages"),
396     FEATURE_ENTRY(VIRTIO_BALLOON_F_STATS_VQ, \
397             "VIRTIO_BALLOON_F_STATS_VQ: Guest memory stats VQ available"),
398     FEATURE_ENTRY(VIRTIO_BALLOON_F_DEFLATE_ON_OOM, \
399             "VIRTIO_BALLOON_F_DEFLATE_ON_OOM: Deflate balloon when guest OOM"),
400     FEATURE_ENTRY(VIRTIO_BALLOON_F_FREE_PAGE_HINT, \
401             "VIRTIO_BALLOON_F_FREE_PAGE_HINT: VQ reporting free pages enabled"),
402     FEATURE_ENTRY(VIRTIO_BALLOON_F_PAGE_POISON, \
403             "VIRTIO_BALLOON_F_PAGE_POISON: Guest page poisoning enabled"),
404     FEATURE_ENTRY(VIRTIO_BALLOON_F_REPORTING, \
405             "VIRTIO_BALLOON_F_REPORTING: Page reporting VQ enabled"),
406     { -1, "" }
407 };
408 #endif
409 
410 /* virtio-crypto features mapping */
411 #ifdef CONFIG_VIRTIO_CRYPTO
412 static const qmp_virtio_feature_map_t virtio_crypto_feature_map[] = {
413     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
414             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
415     { -1, "" }
416 };
417 #endif
418 
419 /* virtio-iommu features mapping */
420 #ifdef CONFIG_VIRTIO_IOMMU
421 static const qmp_virtio_feature_map_t virtio_iommu_feature_map[] = {
422     FEATURE_ENTRY(VIRTIO_IOMMU_F_INPUT_RANGE, \
423             "VIRTIO_IOMMU_F_INPUT_RANGE: Range of available virtual addrs. "
424             "available"),
425     FEATURE_ENTRY(VIRTIO_IOMMU_F_DOMAIN_RANGE, \
426             "VIRTIO_IOMMU_F_DOMAIN_RANGE: Number of supported domains "
427             "available"),
428     FEATURE_ENTRY(VIRTIO_IOMMU_F_MAP_UNMAP, \
429             "VIRTIO_IOMMU_F_MAP_UNMAP: Map and unmap requests available"),
430     FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS, \
431             "VIRTIO_IOMMU_F_BYPASS: Endpoints not attached to domains are in "
432             "bypass mode"),
433     FEATURE_ENTRY(VIRTIO_IOMMU_F_PROBE, \
434             "VIRTIO_IOMMU_F_PROBE: Probe requests available"),
435     FEATURE_ENTRY(VIRTIO_IOMMU_F_MMIO, \
436             "VIRTIO_IOMMU_F_MMIO: VIRTIO_IOMMU_MAP_F_MMIO flag available"),
437     FEATURE_ENTRY(VIRTIO_IOMMU_F_BYPASS_CONFIG, \
438             "VIRTIO_IOMMU_F_BYPASS_CONFIG: Bypass field of IOMMU config "
439             "available"),
440     { -1, "" }
441 };
442 #endif
443 
444 /* virtio-mem features mapping */
445 #ifdef CONFIG_VIRTIO_MEM
446 static const qmp_virtio_feature_map_t virtio_mem_feature_map[] = {
447 #ifndef CONFIG_ACPI
448     FEATURE_ENTRY(VIRTIO_MEM_F_ACPI_PXM, \
449             "VIRTIO_MEM_F_ACPI_PXM: node_id is an ACPI PXM and is valid"),
450 #endif /* !CONFIG_ACPI */
451     FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \
452             "VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be "
453             "accessed"),
454     { -1, "" }
455 };
456 #endif
457 
458 /* virtio-rng features mapping */
459 #ifdef CONFIG_VIRTIO_RNG
460 static const qmp_virtio_feature_map_t virtio_rng_feature_map[] = {
461     FEATURE_ENTRY(VHOST_F_LOG_ALL, \
462             "VHOST_F_LOG_ALL: Logging write descriptors supported"),
463     FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
464             "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
465             "negotiation supported"),
466     { -1, "" }
467 };
468 #endif
469 
470 #define CONVERT_FEATURES(type, map, is_status, bitmap)   \
471     ({                                                   \
472         type *list = NULL;                               \
473         type *node;                                      \
474         for (i = 0; map[i].virtio_bit != -1; i++) {      \
475             if (is_status) {                             \
476                 bit = map[i].virtio_bit;                 \
477             }                                            \
478             else {                                       \
479                 bit = 1ULL << map[i].virtio_bit;         \
480             }                                            \
481             if ((bitmap & bit) == 0) {                   \
482                 continue;                                \
483             }                                            \
484             node = g_new0(type, 1);                      \
485             node->value = g_strdup(map[i].feature_desc); \
486             node->next = list;                           \
487             list = node;                                 \
488             bitmap ^= bit;                               \
489         }                                                \
490         list;                                            \
491     })
492 
493 VirtioDeviceStatus *qmp_decode_status(uint8_t bitmap)
494 {
495     VirtioDeviceStatus *status;
496     uint8_t bit;
497     int i;
498 
499     status = g_new0(VirtioDeviceStatus, 1);
500     status->statuses = CONVERT_FEATURES(strList, virtio_config_status_map,
501                                         1, bitmap);
502     status->has_unknown_statuses = bitmap != 0;
503     if (status->has_unknown_statuses) {
504         status->unknown_statuses = bitmap;
505     }
506 
507     return status;
508 }
509 
510 VhostDeviceProtocols *qmp_decode_protocols(uint64_t bitmap)
511 {
512     VhostDeviceProtocols *vhu_protocols;
513     uint64_t bit;
514     int i;
515 
516     vhu_protocols = g_new0(VhostDeviceProtocols, 1);
517     vhu_protocols->protocols =
518                     CONVERT_FEATURES(strList,
519                                      vhost_user_protocol_map, 0, bitmap);
520     vhu_protocols->has_unknown_protocols = bitmap != 0;
521     if (vhu_protocols->has_unknown_protocols) {
522         vhu_protocols->unknown_protocols = bitmap;
523     }
524 
525     return vhu_protocols;
526 }
527 
528 VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
529 {
530     VirtioDeviceFeatures *features;
531     uint64_t bit;
532     int i;
533 
534     features = g_new0(VirtioDeviceFeatures, 1);
535     features->has_dev_features = true;
536 
537     /* transport features */
538     features->transports = CONVERT_FEATURES(strList, virtio_transport_map, 0,
539                                             bitmap);
540 
541     /* device features */
542     switch (device_id) {
543 #ifdef CONFIG_VIRTIO_SERIAL
544     case VIRTIO_ID_CONSOLE:
545         features->dev_features =
546             CONVERT_FEATURES(strList, virtio_serial_feature_map, 0, bitmap);
547         break;
548 #endif
549 #ifdef CONFIG_VIRTIO_BLK
550     case VIRTIO_ID_BLOCK:
551         features->dev_features =
552             CONVERT_FEATURES(strList, virtio_blk_feature_map, 0, bitmap);
553         break;
554 #endif
555 #ifdef CONFIG_VIRTIO_GPU
556     case VIRTIO_ID_GPU:
557         features->dev_features =
558             CONVERT_FEATURES(strList, virtio_gpu_feature_map, 0, bitmap);
559         break;
560 #endif
561 #ifdef CONFIG_VIRTIO_NET
562     case VIRTIO_ID_NET:
563         features->dev_features =
564             CONVERT_FEATURES(strList, virtio_net_feature_map, 0, bitmap);
565         break;
566 #endif
567 #ifdef CONFIG_VIRTIO_SCSI
568     case VIRTIO_ID_SCSI:
569         features->dev_features =
570             CONVERT_FEATURES(strList, virtio_scsi_feature_map, 0, bitmap);
571         break;
572 #endif
573 #ifdef CONFIG_VIRTIO_BALLOON
574     case VIRTIO_ID_BALLOON:
575         features->dev_features =
576             CONVERT_FEATURES(strList, virtio_balloon_feature_map, 0, bitmap);
577         break;
578 #endif
579 #ifdef CONFIG_VIRTIO_IOMMU
580     case VIRTIO_ID_IOMMU:
581         features->dev_features =
582             CONVERT_FEATURES(strList, virtio_iommu_feature_map, 0, bitmap);
583         break;
584 #endif
585 #ifdef CONFIG_VIRTIO_INPUT
586     case VIRTIO_ID_INPUT:
587         features->dev_features =
588             CONVERT_FEATURES(strList, virtio_input_feature_map, 0, bitmap);
589         break;
590 #endif
591 #ifdef CONFIG_VHOST_USER_FS
592     case VIRTIO_ID_FS:
593         features->dev_features =
594             CONVERT_FEATURES(strList, virtio_fs_feature_map, 0, bitmap);
595         break;
596 #endif
597 #ifdef CONFIG_VHOST_VSOCK
598     case VIRTIO_ID_VSOCK:
599         features->dev_features =
600             CONVERT_FEATURES(strList, virtio_vsock_feature_map, 0, bitmap);
601         break;
602 #endif
603 #ifdef CONFIG_VIRTIO_CRYPTO
604     case VIRTIO_ID_CRYPTO:
605         features->dev_features =
606             CONVERT_FEATURES(strList, virtio_crypto_feature_map, 0, bitmap);
607         break;
608 #endif
609 #ifdef CONFIG_VIRTIO_MEM
610     case VIRTIO_ID_MEM:
611         features->dev_features =
612             CONVERT_FEATURES(strList, virtio_mem_feature_map, 0, bitmap);
613         break;
614 #endif
615 #ifdef CONFIG_VIRTIO_I2C_ADAPTER
616     case VIRTIO_ID_I2C_ADAPTER:
617         features->dev_features =
618             CONVERT_FEATURES(strList, virtio_i2c_feature_map, 0, bitmap);
619         break;
620 #endif
621 #ifdef CONFIG_VIRTIO_RNG
622     case VIRTIO_ID_RNG:
623         features->dev_features =
624             CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap);
625         break;
626 #endif
627     /* No features */
628     case VIRTIO_ID_9P:
629     case VIRTIO_ID_PMEM:
630     case VIRTIO_ID_IOMEM:
631     case VIRTIO_ID_RPMSG:
632     case VIRTIO_ID_CLOCK:
633     case VIRTIO_ID_MAC80211_WLAN:
634     case VIRTIO_ID_MAC80211_HWSIM:
635     case VIRTIO_ID_RPROC_SERIAL:
636     case VIRTIO_ID_MEMORY_BALLOON:
637     case VIRTIO_ID_CAIF:
638     case VIRTIO_ID_SIGNAL_DIST:
639     case VIRTIO_ID_PSTORE:
640     case VIRTIO_ID_SOUND:
641     case VIRTIO_ID_BT:
642     case VIRTIO_ID_RPMB:
643     case VIRTIO_ID_VIDEO_ENCODER:
644     case VIRTIO_ID_VIDEO_DECODER:
645     case VIRTIO_ID_SCMI:
646     case VIRTIO_ID_NITRO_SEC_MOD:
647     case VIRTIO_ID_WATCHDOG:
648     case VIRTIO_ID_CAN:
649     case VIRTIO_ID_DMABUF:
650     case VIRTIO_ID_PARAM_SERV:
651     case VIRTIO_ID_AUDIO_POLICY:
652     case VIRTIO_ID_GPIO:
653         break;
654     default:
655         g_assert_not_reached();
656     }
657 
658     features->has_unknown_dev_features = bitmap != 0;
659     if (features->has_unknown_dev_features) {
660         features->unknown_dev_features = bitmap;
661     }
662 
663     return features;
664 }
665 
666 VirtioInfoList *qmp_x_query_virtio(Error **errp)
667 {
668     VirtioInfoList *list = NULL;
669     VirtioInfoList *node;
670     VirtIODevice *vdev;
671 
672     QTAILQ_FOREACH(vdev, &virtio_list, next) {
673         DeviceState *dev = DEVICE(vdev);
674         Error *err = NULL;
675         QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
676 
677         if (err == NULL) {
678             GString *is_realized = qobject_to_json_pretty(obj, true);
679             /* virtio device is NOT realized, remove it from list */
680             if (!strncmp(is_realized->str, "false", 4)) {
681                 QTAILQ_REMOVE(&virtio_list, vdev, next);
682             } else {
683                 node = g_new0(VirtioInfoList, 1);
684                 node->value = g_new(VirtioInfo, 1);
685                 node->value->path = g_strdup(dev->canonical_path);
686                 node->value->name = g_strdup(vdev->name);
687                 QAPI_LIST_PREPEND(list, node->value);
688             }
689            g_string_free(is_realized, true);
690         }
691         qobject_unref(obj);
692     }
693 
694     return list;
695 }
696 
697 VirtIODevice *qmp_find_virtio_device(const char *path)
698 {
699     VirtIODevice *vdev;
700 
701     QTAILQ_FOREACH(vdev, &virtio_list, next) {
702         DeviceState *dev = DEVICE(vdev);
703 
704         if (strcmp(dev->canonical_path, path) != 0) {
705             continue;
706         }
707 
708         Error *err = NULL;
709         QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
710         if (err == NULL) {
711             GString *is_realized = qobject_to_json_pretty(obj, true);
712             /* virtio device is NOT realized, remove it from list */
713             if (!strncmp(is_realized->str, "false", 4)) {
714                 g_string_free(is_realized, true);
715                 qobject_unref(obj);
716                 QTAILQ_REMOVE(&virtio_list, vdev, next);
717                 return NULL;
718             }
719             g_string_free(is_realized, true);
720         } else {
721             /* virtio device doesn't exist in QOM tree */
722             QTAILQ_REMOVE(&virtio_list, vdev, next);
723             qobject_unref(obj);
724             return NULL;
725         }
726         /* device exists in QOM tree & is realized */
727         qobject_unref(obj);
728         return vdev;
729     }
730     return NULL;
731 }
732 
733 VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
734 {
735     VirtIODevice *vdev;
736     VirtioStatus *status;
737 
738     vdev = qmp_find_virtio_device(path);
739     if (vdev == NULL) {
740         error_setg(errp, "Path %s is not a VirtIODevice", path);
741         return NULL;
742     }
743 
744     status = g_new0(VirtioStatus, 1);
745     status->name = g_strdup(vdev->name);
746     status->device_id = vdev->device_id;
747     status->vhost_started = vdev->vhost_started;
748     status->guest_features = qmp_decode_features(vdev->device_id,
749                                                  vdev->guest_features);
750     status->host_features = qmp_decode_features(vdev->device_id,
751                                                 vdev->host_features);
752     status->backend_features = qmp_decode_features(vdev->device_id,
753                                                    vdev->backend_features);
754 
755     switch (vdev->device_endian) {
756     case VIRTIO_DEVICE_ENDIAN_LITTLE:
757         status->device_endian = g_strdup("little");
758         break;
759     case VIRTIO_DEVICE_ENDIAN_BIG:
760         status->device_endian = g_strdup("big");
761         break;
762     default:
763         status->device_endian = g_strdup("unknown");
764         break;
765     }
766 
767     status->num_vqs = virtio_get_num_queues(vdev);
768     status->status = qmp_decode_status(vdev->status);
769     status->isr = vdev->isr;
770     status->queue_sel = vdev->queue_sel;
771     status->vm_running = vdev->vm_running;
772     status->broken = vdev->broken;
773     status->disabled = vdev->disabled;
774     status->use_started = vdev->use_started;
775     status->started = vdev->started;
776     status->start_on_kick = vdev->start_on_kick;
777     status->disable_legacy_check = vdev->disable_legacy_check;
778     status->bus_name = g_strdup(vdev->bus_name);
779     status->use_guest_notifier_mask = vdev->use_guest_notifier_mask;
780 
781     if (vdev->vhost_started) {
782         VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
783         struct vhost_dev *hdev = vdc->get_vhost(vdev);
784 
785         status->vhost_dev = g_new0(VhostStatus, 1);
786         status->vhost_dev->n_mem_sections = hdev->n_mem_sections;
787         status->vhost_dev->n_tmp_sections = hdev->n_tmp_sections;
788         status->vhost_dev->nvqs = hdev->nvqs;
789         status->vhost_dev->vq_index = hdev->vq_index;
790         status->vhost_dev->features =
791             qmp_decode_features(vdev->device_id, hdev->features);
792         status->vhost_dev->acked_features =
793             qmp_decode_features(vdev->device_id, hdev->acked_features);
794         status->vhost_dev->backend_features =
795             qmp_decode_features(vdev->device_id, hdev->backend_features);
796         status->vhost_dev->protocol_features =
797             qmp_decode_protocols(hdev->protocol_features);
798         status->vhost_dev->max_queues = hdev->max_queues;
799         status->vhost_dev->backend_cap = hdev->backend_cap;
800         status->vhost_dev->log_enabled = hdev->log_enabled;
801         status->vhost_dev->log_size = hdev->log_size;
802     }
803 
804     return status;
805 }
806 
807 VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path,
808                                                             uint16_t queue,
809                                                             Error **errp)
810 {
811     VirtIODevice *vdev;
812     VirtVhostQueueStatus *status;
813 
814     vdev = qmp_find_virtio_device(path);
815     if (vdev == NULL) {
816         error_setg(errp, "Path %s is not a VirtIODevice", path);
817         return NULL;
818     }
819 
820     if (!vdev->vhost_started) {
821         error_setg(errp, "Error: vhost device has not started yet");
822         return NULL;
823     }
824 
825     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
826     struct vhost_dev *hdev = vdc->get_vhost(vdev);
827 
828     if (queue < hdev->vq_index || queue >= hdev->vq_index + hdev->nvqs) {
829         error_setg(errp, "Invalid vhost virtqueue number %d", queue);
830         return NULL;
831     }
832 
833     status = g_new0(VirtVhostQueueStatus, 1);
834     status->name = g_strdup(vdev->name);
835     status->kick = hdev->vqs[queue].kick;
836     status->call = hdev->vqs[queue].call;
837     status->desc = (uintptr_t)hdev->vqs[queue].desc;
838     status->avail = (uintptr_t)hdev->vqs[queue].avail;
839     status->used = (uintptr_t)hdev->vqs[queue].used;
840     status->num = hdev->vqs[queue].num;
841     status->desc_phys = hdev->vqs[queue].desc_phys;
842     status->desc_size = hdev->vqs[queue].desc_size;
843     status->avail_phys = hdev->vqs[queue].avail_phys;
844     status->avail_size = hdev->vqs[queue].avail_size;
845     status->used_phys = hdev->vqs[queue].used_phys;
846     status->used_size = hdev->vqs[queue].used_size;
847 
848     return status;
849 }
850