All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices
@ 2022-04-01 13:23 Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 1/8] virtio: drop name parameter for virtio_init() Jonah Palmer
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

This series introduces new QMP/HMP commands to dump the status of a
virtio device at different levels.

[Jonah: Rebasing from previous patchset from Feb. 10 (v13). Original patches
 are by Laurent Vivier from May 2020.

 Rebase from v13 to v14 includes moving the definition of 'gpu_map' to
 virtio-gpu.c, adding a new virtio-gpu feature, creating a feature mapping
 for vhost-user-i2c, and fixing a casting error for cross-Win64 builds
 in VirtVhostQueueStatus.]

1. List available virtio devices in the machine

HMP Form:

    info virtio

    Example:

        (qemu) info virtio
        /machine/peripheral/vsock0/virtio-backend [vhost-vsock]
        /machine/peripheral/crypto0/virtio-backend [virtio-crypto]
        /machine/peripheral-anon/device[2]/virtio-backend [virtio-scsi]
        /machine/peripheral-anon/device[1]/virtio-backend [virtio-net]
        /machine/peripheral-anon/device[0]/virtio-backend [virtio-serial]

QMP Form:

    { 'command': 'x-query-virtio',
      'returns': ['VirtioInfo'],
      'features': [ 'unstable' ] }

    Example:

        -> { "execute": "x-query-virtio" }
        <- { "return": [
               {
                   "path": "/machine/peripheral/vsock0/virtio-backend",
                   "name": "vhost-vsock"
               },
               {
                   "path": "/machine/peripheral/crypto0/virtio-backend",
                   "name": "virtio-crypto"
               },
               {
                   "path": "/machine/peripheral-anon/device[2]/virtio-backend",
                   "name": "virtio-scsi"
               },
               {
                   "path": "/machine/peripheral-anon/device[1]/virtio-backend",
                   "name": "virtio-net"
               },
               {
                   "path": "/machine/peripheral-anon/device[0]/virtio-backend",
                   "name": "virtio-serial"
               }
             ]
           }

2. Display status of a given virtio device

HMP Form:

    info virtio-status <path>

    Example:

        (qemu) info virtio-status /machine/peripheral/vsock0/virtio-backend
        /machine/peripheral/vsock0/virtio-backend:
            device_name:             vhost-vsock (vhost)
            device_id:               19
            vhost_started:           true
            bus_name:                (null)
            broken:                  false
            disabled:                false
            disable_legacy_check:    false
            started:                 true
            use_started:             true
            start_on_kick:           false
            use_guest_notifier_mask: true
            vm_running:              true
            num_vqs:                 3
            queue_sel:               2
            isr:                     0
            endianness:              little
            status: ACKNOWLEDGE, DRIVER, FEATURES_OK, DRIVER_OK
            Guest features:   EVENT_IDX, INDIRECT_DESC, VERSION_1
            Host features:    PROTOCOL_FEATURES, EVENT_IDX, INDIRECT_DESC, VERSION_1, ANY_LAYOUT,
                              NOTIFY_ON_EMPTY
            Backend features:
            VHost:
                nvqs:           2
                vq_index:       0
                max_queues:     0
                n_mem_sections: 4
                n_tmp_sections: 4
                backend_cap:    0
                log_enabled:    false
                log_size:       0
                Features:          EVENT_IDX, INDIRECT_DESC, VERSION_1, ANY_LAYOUT, NOTIFY_ON_EMPTY
                                   LOG_ALL
                Acked features:    EVENT_IDX, INDIRECT_DESC, VERSION_1
                Backend features:
                Protocol features:

QMP Form:

    { 'command': 'x-query-virtio-status',
      'data': { 'path': 'str' },
      'returns': 'VirtioStatus',
      'features': [ 'unstable' ] }

    Example:

        -> { "execute": "x-query-virtio-status",
             "arguments": { "path": "/machine/peripheral/vsock0/virtio-backend" }
           }
        <- { "return": {
                   "device-endian": "little",
                   "bus-name": "",
                   "disable-legacy-check": false,
                   "name": "vhost-vsock",
                   "started": true,
                   "device-id": 19,
                   "vhost-dev": {
                      "n-tmp-sections": 4,
                      "n-mem-sections": 4,
                      "max-queues": 0,
                      "backend-cap": 0,
                      "log-size": 0,
                      "backend-features": {
                         "transports": [],
                         "dev-features": []
                      },
                      "nvqs": 2,
                      "protocol-features": {
                         "protocols": []
                      },
                      "vq-index": 0,
                      "log-enabled": false,
                      "acked-features": {
                         "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
                         "dev-features": []
                      },
                      "features": {
                         "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
                                        "NOTIFY_ON_EMPTY"],
                         "dev-features": ["LOG_ALL"]
                      }
                   },
                   "backend-features": {
                      "transports": [],
                      "dev-features": []
                   },
                   "start-on-kick": false,
                   "isr": 0,
                   "broken": false,
                   "status": {
                      "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
                   },
                   "num-vqs": 3,
                   "guest-features": {
                      "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
                      "dev-features": []
                   },
                   "host-features": {
                      "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
                                     "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
                      "dev-features": []
                   },
                   "use-guest-notifier-mask": true,
                   "vm-running": true,
                   "queue-sel": 2,
                   "disabled": false,
                   "vhost-started": true,
                   "use-started": true
             }
           }

3. Display status of a given virtio queue

HMP Form:

    info virtio-queue-status <path> <queue>

    Example:

        (qemu) info virtio-queue-status /machine/peripheral-anon/device[1]/virtio-backend 2
        /machine/peripheral-anon/device[1]/virtio-backend:
            device_name:          virtio-net
            queue_index:          2
            inuse:                0
            used_idx:             27
            signalled_used:       27
            signalled_used_valid: true
            VRing:
                num:          64
                num_default:  64
                align:        4096
                desc:         0x00000001342b5000
                avail:        0x00000001342b5400
                used:         0x00000001342b54c0

QMP Form:

    { 'command': 'x-query-virtio-queue-status',
      'data': { 'path': 'str', 'queue': 'uint16' },
      'returns': 'VirtQueueStatus',
      'features': [ 'unstable' ] }

    Example:

        -> { "execute": "x-query-virtio-queue-status",
             "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend",
                            "queue": 2 }
           }
        <- { "return": {
                   "signalled-used": 27,
                   "inuse": 0,
                   "vring-align": 4096,
                   "vring-desc": 5170221056,
                   "signalled-used-valid": true,
                   "vring-num-default": 64,
                   "vring-avail": 5170222080,
                   "queue-index": 2,
                   "vring-used": 5170222272,
                   "used-idx": 27,
                   "name": "virtio-net",
                   "vring-num": 64 }
           }

4. Display status of a given vhost queue

HMP Form:

    info virtio-vhost-queue-status <path> <queue>

    Example:

        (qemu) info virtio-vhost-queue-status /machine/peripheral-anon/device[1]/virtio-backend 1
        /machine/peripheral-anon/device[1]/virtio-backend:
            device_name:          virtio-net (vhost)
            kick:                 0
            call:                 0
            VRing:
                num:         256
                desc:        0x00007f31c032c000
                desc_phys:   0x00000001340c6000
                desc_size:   4096
                avail:       0x00007f31c032d000
                avail_phys:  0x00000001340c7000
                avail_size:  518
                used:        0x00007f31c032d240
                used_phys:   0x00000001340c7240
                used_size:   2054

QMP Form:

    { 'command': 'x-query-virtio-vhost-queue-status',
      'data': { 'path': 'str', 'queue': 'uint16' },
      'returns': 'VirtVhostQueueStatus',
      'features': [ 'unstable' ] }

    Example:

        -> { "execute": "x-query-virtio-vhost-queue-status",
             "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend",
                            "queue": 1 }
           }
        <- { "return": {
                   "avail-phys": 5168197632,
                   "used-phys": 5168198208,
                   "avail-size": 518,
                   "desc-size": 4096,
                   "used-size": 2054,
                   "desc": 139851654676480,
                   "num": 256,
                   "name": "virtio-net",
                   "call": 0,
                   "avail": 139851654680576,
                   "desc-phys": 5168193536,
                   "used": 139851654681152,
                   "kick": 0 }
           }

5. Display an element of a given virtio queue

HMP Form:

    info virtio-queue-element <path> <queue> [index]

    Example:

        Dump the information of the head element of the third queue of virtio-scsi:

        (qemu) info virtio-queue-element /machine/peripheral-anon/device[2]/virtio-backend 2
        /machine/peripheral-anon/device[2]/virtio-backend:
            device_name: virtio-scsi
            index:       125
            desc:
               descs:   addr 0xa4f90f1d0653b5fc len 1862028160 (used, avail, next)
            avail:
               flags: 0
               idx:   2936
               ring:  125
            used:
               flags: 0
               idx:   2936

QMP Form:

    { 'command': 'x-query-virtio-queue-element',
      'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
      'returns': 'VirtioQueueElement',
      'features': [ 'unstable' ] }

    Example:

        -> { "execute": "x-query-virtio-queue-element",
             "arguments": { "path": "/machine/peripheral-anon/device[2]/virtio-backend",
                            "queue": 2 }
           }
        <- { "return": {
                   "index": 125,
                   "name": "virtio-scsi",
                   "descs": [
                      { "flags": ["used", "avail", "next"],
                        "len": 1862028160,
                        "addr": 11887549308755752444 }
                   ],
                   "avail": {
                      "idx": 2936,
                      "flags": 0,
                      "ring": 125
                   },
                   "used": {
                      "idx": 2936,
                      "flags": 0
                   }
             }
           }

v14: move definition of 'gpu_map' to virtio-gpu.c
     add new 'context-init' virtio-gpu feature
     created new feature map 'i2c_map' for vhost-user-i2c
     fixed casting error for cross-Win64 builds

v13: minor text edit in qapi/virtio.json

v12: minor reformatting for monitor/hmp-cmds.c
     use PRI types in virtio hmp monitor printfs

v11: minor reformatting in virtio.json
     added synchronicity check when querying virtio devices

v10: rebased for upstream (Qemu 7.0)
     reformat virtio.json for better consistency
     removed all enums from virtio.json; replaced with string literals
     removed @ndescs from VirtioQueueElement
     removed examples in hmp-commands-info.hx (to fix 'inconsistent
     literal block quoting' error from Sphinx)

v9: rebased for upstream (Qemu 6.3)
    change QMP command prefixes from 'x-debug-virtio' to
    'x-query-virtio'
    add 'unstable' feature to all 'x-query-virtio' prefixed
    QMP commands
    fix odd indentation for qapi/virtio.json
    device features support for virtio-mem
    move HMP sub-commands under 'virtio' top level to 'info'
    top level

v8: add assert in virtio_id_to_name() to make sure we're
    not returning NULL
    minor documentation additions to qapi/virtio.json
    add virtio introspection support for vhost-user-rng

v7: rebased for upstream (Qemu 6.2)
    add ability to map between numberic device ID and
    string device ID (name) for virtio devices
    add get_vhost() callback function for VirtIODevices
    expose more fields of VirtIODevice
    expose fields of vhost devices
    decode vhost user protocol features
    decode VirtIODevice configuration statuses
    vhost support for displaying virtio queue statuses
    vhost support for displaying vhost queue statuses
    expose driver and device areas when introspecting a
    virtio queue element
    changed patch attribution

v6: rebased for upstream (Qemu 6.1)
    add all virtio/vhost types in same order as
    include/standard-headers/linux/virtio_ids.h
    use QAPI_LIST_PREPEND in qmp_x_debug_query_virtio rather than open
    coding

v5: rebased for upstream
    add device name, used index, and relative indicies to virtio queue-status
    HMP command
    add device name to virtio queue-status QMP command
    add new virtio device features

v4: re-send series as v3 didn't reach qemu-devel

v3: use qapi_free_VirtioInfoList() on the head of the list, not on the tail.
    Prefix the QMP commands with 'x-debug-'

v2: introduce VirtioType enum
    use an enum for the endianness
    change field names to stick to naming convertions (s/_/-/)
    add a patch to decode feature bits
    don't check if the queue is empty to allow display of old elements
    use enum for desc flags
    manage indirect desc
    decode device features in the HMP command

Jonah Palmer (2):
  virtio: drop name parameter for virtio_init()
  virtio: add vhost support for virtio devices

Laurent Vivier (6):
  qmp: add QMP command x-query-virtio
  qmp: add QMP command x-query-virtio-status
  qmp: decode feature & status bits in virtio-status
  qmp: add QMP commands for virtio/vhost queue-status
  qmp: add QMP command x-query-virtio-queue-element
  hmp: add virtio commands

 hmp-commands-info.hx                   |  70 ++
 hw/9pfs/virtio-9p-device.c             |   2 +-
 hw/block/vhost-user-blk.c              |   9 +-
 hw/block/virtio-blk.c                  |  31 +-
 hw/char/virtio-serial-bus.c            |  14 +-
 hw/display/vhost-user-gpu.c            |   7 +
 hw/display/virtio-gpu-base.c           |   2 +-
 hw/display/virtio-gpu.c                |  18 +
 hw/input/vhost-user-input.c            |   7 +
 hw/input/virtio-input.c                |  13 +-
 hw/net/virtio-net.c                    |  58 +-
 hw/scsi/vhost-scsi.c                   |   8 +
 hw/scsi/virtio-scsi.c                  |  20 +-
 hw/virtio/meson.build                  |   2 +
 hw/virtio/vhost-user-fs.c              |  20 +-
 hw/virtio/vhost-user-i2c.c             |  21 +-
 hw/virtio/vhost-user-rng.c             |   9 +-
 hw/virtio/vhost-user-vsock.c           |   2 +-
 hw/virtio/vhost-vsock-common.c         |  22 +-
 hw/virtio/vhost-vsock.c                |   2 +-
 hw/virtio/vhost.c                      |   4 +-
 hw/virtio/virtio-balloon.c             |  17 +-
 hw/virtio/virtio-crypto.c              |  22 +-
 hw/virtio/virtio-iommu.c               |  17 +-
 hw/virtio/virtio-mem.c                 |  14 +-
 hw/virtio/virtio-pmem.c                |   3 +-
 hw/virtio/virtio-rng.c                 |   2 +-
 hw/virtio/virtio-stub.c                |  42 ++
 hw/virtio/virtio.c                     | 747 +++++++++++++++++++++-
 include/hw/virtio/vhost-vsock-common.h |   2 +-
 include/hw/virtio/vhost.h              |   3 +
 include/hw/virtio/virtio-gpu.h         |   3 +-
 include/hw/virtio/virtio.h             |  27 +-
 include/monitor/hmp.h                  |   5 +
 monitor/hmp-cmds.c                     | 311 +++++++++
 qapi/meson.build                       |   1 +
 qapi/qapi-schema.json                  |   1 +
 qapi/virtio.json                       | 841 +++++++++++++++++++++++++
 tests/qtest/qmp-cmd-test.c             |   1 +
 39 files changed, 2356 insertions(+), 44 deletions(-)
 create mode 100644 hw/virtio/virtio-stub.c
 create mode 100644 qapi/virtio.json

-- 
2.35.1



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v14 1/8] virtio: drop name parameter for virtio_init()
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-21 17:47   ` Dr. David Alan Gilbert
  2022-04-01 13:23 ` [PATCH v14 2/8] virtio: add vhost support for virtio devices Jonah Palmer
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

This patch drops the name parameter for the virtio_init function.

The pair between the numeric device ID and the string device ID
(name) of a virtio device already exists, but not in a way that
lets us map between them.

This patch lets us do this and removes the need for the name
parameter in the virtio_init function.

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/9pfs/virtio-9p-device.c             |  2 +-
 hw/block/vhost-user-blk.c              |  2 +-
 hw/block/virtio-blk.c                  |  2 +-
 hw/char/virtio-serial-bus.c            |  3 +-
 hw/display/virtio-gpu-base.c           |  2 +-
 hw/input/virtio-input.c                |  3 +-
 hw/net/virtio-net.c                    |  2 +-
 hw/scsi/virtio-scsi.c                  |  3 +-
 hw/virtio/vhost-user-fs.c              |  3 +-
 hw/virtio/vhost-user-i2c.c             |  7 +---
 hw/virtio/vhost-user-rng.c             |  2 +-
 hw/virtio/vhost-user-vsock.c           |  2 +-
 hw/virtio/vhost-vsock-common.c         |  5 +--
 hw/virtio/vhost-vsock.c                |  2 +-
 hw/virtio/virtio-balloon.c             |  3 +-
 hw/virtio/virtio-crypto.c              |  2 +-
 hw/virtio/virtio-iommu.c               |  3 +-
 hw/virtio/virtio-mem.c                 |  3 +-
 hw/virtio/virtio-pmem.c                |  3 +-
 hw/virtio/virtio-rng.c                 |  2 +-
 hw/virtio/virtio.c                     | 55 ++++++++++++++++++++++++--
 include/hw/virtio/vhost-vsock-common.h |  2 +-
 include/hw/virtio/virtio-gpu.h         |  3 +-
 include/hw/virtio/virtio.h             |  4 +-
 24 files changed, 77 insertions(+), 43 deletions(-)

diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 54ee93b71f..5f522e68e9 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -216,7 +216,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
     }
 
     v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
-    virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
+    virtio_init(vdev, VIRTIO_ID_9P, v->config_size);
     v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
 }
 
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 1a42ae9187..e8cb170032 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -491,7 +491,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
+    virtio_init(vdev, VIRTIO_ID_BLOCK,
                 sizeof(struct virtio_blk_config));
 
     s->virtqs = g_new(VirtQueue *, s->num_queues);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 540c38f829..27c71ad316 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1206,7 +1206,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
 
     virtio_blk_set_config_size(s, s->host_features);
 
-    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size);
+    virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
 
     s->blk = conf->conf.blk;
     s->rq = NULL;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 6048d408b8..7d4601cb5d 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -1044,8 +1044,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
                             VIRTIO_CONSOLE_F_EMERG_WRITE)) {
         config_size = offsetof(struct virtio_console_config, emerg_wr);
     }
-    virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
-                config_size);
+    virtio_init(vdev, VIRTIO_ID_CONSOLE, config_size);
 
     /* Spawn a new virtio-serial bus on which the ports will ride as devices */
     qbus_init(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index fff0fb4a82..8ba5da4312 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -173,7 +173,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
     }
 
     g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
-    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
+    virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU,
                 sizeof(struct virtio_gpu_config));
 
     if (virtio_gpu_virgl_enabled(g->conf)) {
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index 54bcb46c74..5b5398b3ca 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -257,8 +257,7 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp)
     vinput->cfg_size += 8;
     assert(vinput->cfg_size <= sizeof(virtio_input_config));
 
-    virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
-                vinput->cfg_size);
+    virtio_init(vdev, VIRTIO_ID_INPUT, vinput->cfg_size);
     vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
     vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
 }
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 1067e72b39..6fbcfd7cb7 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3392,7 +3392,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
     }
 
     virtio_net_set_config_size(n, n->host_features);
-    virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
+    virtio_init(vdev, VIRTIO_ID_NET, n->config_size);
 
     /*
      * We set a lower limit on RX queue size to what it always was.
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 34a968ecfb..2a6141d081 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -972,8 +972,7 @@ void virtio_scsi_common_realize(DeviceState *dev,
     VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
     int i;
 
-    virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
-                sizeof(VirtIOSCSIConfig));
+    virtio_init(vdev, VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig));
 
     if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
         s->conf.num_queues = 1;
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index c595957983..b875640147 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -219,8 +219,7 @@ static void vuf_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS,
-                sizeof(struct virtio_fs_config));
+    virtio_init(vdev, VIRTIO_ID_FS, sizeof(struct virtio_fs_config));
 
     /* Hiprio queue */
     fs->hiprio_vq = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
index 42c7f6d9e5..6020eee093 100644
--- a/hw/virtio/vhost-user-i2c.c
+++ b/hw/virtio/vhost-user-i2c.c
@@ -14,11 +14,6 @@
 #include "qemu/error-report.h"
 #include "standard-headers/linux/virtio_ids.h"
 
-/* Remove this once the header is updated in Linux kernel */
-#ifndef VIRTIO_ID_I2C_ADAPTER
-#define VIRTIO_ID_I2C_ADAPTER                34
-#endif
-
 static const int feature_bits[] = {
     VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
     VHOST_INVALID_FEATURE_BIT
@@ -227,7 +222,7 @@ static void vu_i2c_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "vhost-user-i2c", VIRTIO_ID_I2C_ADAPTER, 0);
+    virtio_init(vdev, VIRTIO_ID_I2C_ADAPTER, 0);
 
     i2c->vhost_dev.nvqs = 1;
     i2c->vq = virtio_add_queue(vdev, 4, vu_i2c_handle_output);
diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c
index 209ee5bf9a..08bccba9dc 100644
--- a/hw/virtio/vhost-user-rng.c
+++ b/hw/virtio/vhost-user-rng.c
@@ -203,7 +203,7 @@ static void vu_rng_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "vhost-user-rng", VIRTIO_ID_RNG, 0);
+    virtio_init(vdev, VIRTIO_ID_RNG, 0);
 
     rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output);
     if (!rng->req_vq) {
diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c
index 52bd682c34..0f8ff99f85 100644
--- a/hw/virtio/vhost-user-vsock.c
+++ b/hw/virtio/vhost-user-vsock.c
@@ -107,7 +107,7 @@ static void vuv_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    vhost_vsock_common_realize(vdev, "vhost-user-vsock");
+    vhost_vsock_common_realize(vdev);
 
     vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops);
 
diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
index ed706681ac..ad5c8ff5d5 100644
--- a/hw/virtio/vhost-vsock-common.c
+++ b/hw/virtio/vhost-vsock-common.c
@@ -224,12 +224,11 @@ int vhost_vsock_common_post_load(void *opaque, int version_id)
     return 0;
 }
 
-void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name)
+void vhost_vsock_common_realize(VirtIODevice *vdev)
 {
     VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
 
-    virtio_init(vdev, name, VIRTIO_ID_VSOCK,
-                sizeof(struct virtio_vsock_config));
+    virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config));
 
     /* Receive and transmit queues belong to vhost */
     vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
index 433d42d897..696635b1f7 100644
--- a/hw/virtio/vhost-vsock.c
+++ b/hw/virtio/vhost-vsock.c
@@ -166,7 +166,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
         qemu_set_nonblock(vhostfd);
     }
 
-    vhost_vsock_common_realize(vdev, "vhost-vsock");
+    vhost_vsock_common_realize(vdev);
 
     ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd,
                          VHOST_BACKEND_TYPE_KERNEL, 0, errp);
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 163d244eb4..193ff5261c 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -889,8 +889,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
     VirtIOBalloon *s = VIRTIO_BALLOON(dev);
     int ret;
 
-    virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON,
-                virtio_balloon_config_size(s));
+    virtio_init(vdev, VIRTIO_ID_BALLOON, virtio_balloon_config_size(s));
 
     ret = qemu_add_balloon_handler(virtio_balloon_to_target,
                                    virtio_balloon_stat, s);
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index dcd80b904d..0a1f3dfdbe 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -810,7 +810,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "virtio-crypto", VIRTIO_ID_CRYPTO, vcrypto->config_size);
+    virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size);
     vcrypto->curr_queues = 1;
     vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues);
     for (i = 0; i < vcrypto->max_queues; i++) {
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 664cbd9583..4ed5bb16ba 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -1033,8 +1033,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
 
-    virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU,
-                sizeof(struct virtio_iommu_config));
+    virtio_init(vdev, VIRTIO_ID_IOMMU, sizeof(struct virtio_iommu_config));
 
     memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num));
 
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index f55dcf61f2..465a996214 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -868,8 +868,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
                         vmem->block_size;
     vmem->bitmap = bitmap_new(vmem->bitmap_size);
 
-    virtio_init(vdev, TYPE_VIRTIO_MEM, VIRTIO_ID_MEM,
-                sizeof(struct virtio_mem_config));
+    virtio_init(vdev, VIRTIO_ID_MEM, sizeof(struct virtio_mem_config));
     vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request);
 
     host_memory_backend_set_mapped(vmem->memdev, true);
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
index 5419dca75e..ec74890676 100644
--- a/hw/virtio/virtio-pmem.c
+++ b/hw/virtio/virtio-pmem.c
@@ -123,8 +123,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp)
     }
 
     host_memory_backend_set_mapped(pmem->memdev, true);
-    virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM,
-                sizeof(struct virtio_pmem_config));
+    virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config));
     pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush);
 }
 
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index cc8e9f775d..7e12fc03bf 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -215,7 +215,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
+    virtio_init(vdev, VIRTIO_ID_RNG, 0);
 
     vrng->vq = virtio_add_queue(vdev, 8, handle_input);
     vrng->quota_remaining = vrng->conf.max_bytes;
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 9d637e043e..cbb4920f49 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -132,6 +132,56 @@ struct VirtQueue
     QLIST_ENTRY(VirtQueue) node;
 };
 
+const char *virtio_device_names[] = {
+    [VIRTIO_ID_NET] = "virtio-net",
+    [VIRTIO_ID_BLOCK] = "virtio-blk",
+    [VIRTIO_ID_CONSOLE] = "virtio-serial",
+    [VIRTIO_ID_RNG] = "virtio-rng",
+    [VIRTIO_ID_BALLOON] = "virtio-balloon",
+    [VIRTIO_ID_IOMEM] = "virtio-iomem",
+    [VIRTIO_ID_RPMSG] = "virtio-rpmsg",
+    [VIRTIO_ID_SCSI] = "virtio-scsi",
+    [VIRTIO_ID_9P] = "virtio-9p",
+    [VIRTIO_ID_MAC80211_WLAN] = "virtio-mac-wlan",
+    [VIRTIO_ID_RPROC_SERIAL] = "virtio-rproc-serial",
+    [VIRTIO_ID_CAIF] = "virtio-caif",
+    [VIRTIO_ID_MEMORY_BALLOON] = "virtio-mem-balloon",
+    [VIRTIO_ID_GPU] = "virtio-gpu",
+    [VIRTIO_ID_CLOCK] = "virtio-clk",
+    [VIRTIO_ID_INPUT] = "virtio-input",
+    [VIRTIO_ID_VSOCK] = "vhost-vsock",
+    [VIRTIO_ID_CRYPTO] = "virtio-crypto",
+    [VIRTIO_ID_SIGNAL_DIST] = "virtio-signal",
+    [VIRTIO_ID_PSTORE] = "virtio-pstore",
+    [VIRTIO_ID_IOMMU] = "virtio-iommu",
+    [VIRTIO_ID_MEM] = "virtio-mem",
+    [VIRTIO_ID_SOUND] = "virtio-sound",
+    [VIRTIO_ID_FS] = "virtio-user-fs",
+    [VIRTIO_ID_PMEM] = "virtio-pmem",
+    [VIRTIO_ID_RPMB] = "virtio-rpmb",
+    [VIRTIO_ID_MAC80211_HWSIM] = "virtio-mac-hwsim",
+    [VIRTIO_ID_VIDEO_ENCODER] = "virtio-vid-encoder",
+    [VIRTIO_ID_VIDEO_DECODER] = "virtio-vid-decoder",
+    [VIRTIO_ID_SCMI] = "virtio-scmi",
+    [VIRTIO_ID_NITRO_SEC_MOD] = "virtio-nitro-sec-mod",
+    [VIRTIO_ID_I2C_ADAPTER] = "vhost-user-i2c",
+    [VIRTIO_ID_WATCHDOG] = "virtio-watchdog",
+    [VIRTIO_ID_CAN] = "virtio-can",
+    [VIRTIO_ID_DMABUF] = "virtio-dmabuf",
+    [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
+    [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
+    [VIRTIO_ID_BT] = "virtio-bluetooth",
+    [VIRTIO_ID_GPIO] = "virtio-gpio"
+};
+
+static const char *virtio_id_to_name(uint16_t device_id)
+{
+    assert(device_id < G_N_ELEMENTS(virtio_device_names));
+    const char *name = virtio_device_names[device_id];
+    assert(name != NULL);
+    return name;
+}
+
 /* Called within call_rcu().  */
 static void virtio_free_region_cache(VRingMemoryRegionCaches *caches)
 {
@@ -3207,8 +3257,7 @@ void virtio_instance_init_common(Object *proxy_obj, void *data,
     qdev_alias_all_properties(vdev, proxy_obj);
 }
 
-void virtio_init(VirtIODevice *vdev, const char *name,
-                 uint16_t device_id, size_t config_size)
+void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size)
 {
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
@@ -3237,7 +3286,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
         vdev->vq[i].host_notifier_enabled = false;
     }
 
-    vdev->name = name;
+    vdev->name = virtio_id_to_name(device_id);
     vdev->config_len = config_size;
     if (vdev->config_len) {
         vdev->config = g_malloc0(config_size);
diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h
index d8b565b4da..076b7ab779 100644
--- a/include/hw/virtio/vhost-vsock-common.h
+++ b/include/hw/virtio/vhost-vsock-common.h
@@ -44,7 +44,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev);
 void vhost_vsock_common_stop(VirtIODevice *vdev);
 int vhost_vsock_common_pre_save(void *opaque);
 int vhost_vsock_common_post_load(void *opaque, int version_id);
-void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name);
+void vhost_vsock_common_realize(VirtIODevice *vdev);
 void vhost_vsock_common_unrealize(VirtIODevice *vdev);
 uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features,
                                          Error **errp);
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 2179b75703..afff9e158e 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -22,6 +22,7 @@
 #include "sysemu/vhost-user-backend.h"
 
 #include "standard-headers/linux/virtio_gpu.h"
+#include "standard-headers/linux/virtio_ids.h"
 #include "qom/object.h"
 
 #define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base"
@@ -37,8 +38,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL)
 #define TYPE_VHOST_USER_GPU "vhost-user-gpu"
 OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU)
 
-#define VIRTIO_ID_GPU 16
-
 struct virtio_gpu_simple_resource {
     uint32_t resource_id;
     uint32_t width;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index b31c4507f5..5d774684b1 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -165,8 +165,8 @@ struct VirtioDeviceClass {
 void virtio_instance_init_common(Object *proxy_obj, void *data,
                                  size_t vdev_size, const char *vdev_name);
 
-void virtio_init(VirtIODevice *vdev, const char *name,
-                         uint16_t device_id, size_t config_size);
+void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size);
+
 void virtio_cleanup(VirtIODevice *vdev);
 
 void virtio_error(VirtIODevice *vdev, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 2/8] virtio: add vhost support for virtio devices
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 1/8] virtio: drop name parameter for virtio_init() Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 3/8] qmp: add QMP command x-query-virtio Jonah Palmer
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

This patch adds a get_vhost() callback function for VirtIODevices that
returns the device's corresponding vhost_dev structure, if the vhost
device is running. This patch also adds a vhost_started flag for
VirtIODevices.

Previously, a VirtIODevice wouldn't be able to tell if its corresponding
vhost device was active or not.

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/block/vhost-user-blk.c      |  7 +++++++
 hw/display/vhost-user-gpu.c    |  7 +++++++
 hw/input/vhost-user-input.c    |  7 +++++++
 hw/net/virtio-net.c            |  9 +++++++++
 hw/scsi/vhost-scsi.c           |  8 ++++++++
 hw/virtio/vhost-user-fs.c      |  7 +++++++
 hw/virtio/vhost-user-rng.c     |  7 +++++++
 hw/virtio/vhost-vsock-common.c |  7 +++++++
 hw/virtio/vhost.c              |  4 +++-
 hw/virtio/virtio-crypto.c      | 10 ++++++++++
 hw/virtio/virtio.c             |  1 +
 include/hw/virtio/virtio.h     |  3 +++
 12 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index e8cb170032..5dca4eab09 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -569,6 +569,12 @@ static void vhost_user_blk_instance_init(Object *obj)
                                   "/disk@0,0", DEVICE(obj));
 }
 
+static struct vhost_dev *vhost_user_blk_get_vhost(VirtIODevice *vdev)
+{
+    VHostUserBlk *s = VHOST_USER_BLK(vdev);
+    return &s->dev;
+}
+
 static const VMStateDescription vmstate_vhost_user_blk = {
     .name = "vhost-user-blk",
     .minimum_version_id = 1,
@@ -603,6 +609,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
     vdc->get_features = vhost_user_blk_get_features;
     vdc->set_status = vhost_user_blk_set_status;
     vdc->reset = vhost_user_blk_reset;
+    vdc->get_vhost = vhost_user_blk_get_vhost;
 }
 
 static const TypeInfo vhost_user_blk_info = {
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 09818231bd..96e56c4467 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -565,6 +565,12 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
     g->vhost_gpu_fd = -1;
 }
 
+static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
+{
+    VhostUserGPU *g = VHOST_USER_GPU(vdev);
+    return &g->vhost->dev;
+}
+
 static Property vhost_user_gpu_properties[] = {
     VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf),
     DEFINE_PROP_END_OF_LIST(),
@@ -586,6 +592,7 @@ vhost_user_gpu_class_init(ObjectClass *klass, void *data)
     vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending;
     vdc->get_config = vhost_user_gpu_get_config;
     vdc->set_config = vhost_user_gpu_set_config;
+    vdc->get_vhost = vhost_user_gpu_get_vhost;
 
     device_class_set_props(dc, vhost_user_gpu_properties);
 }
diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c
index 273e96a7b1..43d2ff3816 100644
--- a/hw/input/vhost-user-input.c
+++ b/hw/input/vhost-user-input.c
@@ -79,6 +79,12 @@ static void vhost_input_set_config(VirtIODevice *vdev,
     virtio_notify_config(vdev);
 }
 
+static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev)
+{
+    VHostUserInput *vhi = VHOST_USER_INPUT(vdev);
+    return &vhi->vhost->dev;
+}
+
 static const VMStateDescription vmstate_vhost_input = {
     .name = "vhost-user-input",
     .unmigratable = 1,
@@ -93,6 +99,7 @@ static void vhost_input_class_init(ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_vhost_input;
     vdc->get_config = vhost_input_get_config;
     vdc->set_config = vhost_input_set_config;
+    vdc->get_vhost = vhost_input_get_vhost;
     vic->realize = vhost_input_realize;
     vic->change_active = vhost_input_change_active;
 }
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6fbcfd7cb7..027ce40c6f 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3619,6 +3619,14 @@ static bool dev_unplug_pending(void *opaque)
     return vdc->primary_unplug_pending(dev);
 }
 
+static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
+{
+    VirtIONet *n = VIRTIO_NET(vdev);
+    NetClientState *nc = qemu_get_queue(n->nic);
+    struct vhost_net *net = get_vhost_net(nc->peer);
+    return &net->dev;
+}
+
 static const VMStateDescription vmstate_virtio_net = {
     .name = "virtio-net",
     .minimum_version_id = VIRTIO_NET_VM_VERSION,
@@ -3721,6 +3729,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
     vdc->post_load = virtio_net_post_load_virtio;
     vdc->vmsd = &vmstate_virtio_net_device;
     vdc->primary_unplug_pending = primary_unplug_pending;
+    vdc->get_vhost = virtio_net_get_vhost;
 }
 
 static const TypeInfo virtio_net_info = {
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 778f43e4c1..3059068175 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -273,6 +273,13 @@ static void vhost_scsi_unrealize(DeviceState *dev)
     virtio_scsi_common_unrealize(dev);
 }
 
+static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev)
+{
+    VHostSCSI *s = VHOST_SCSI(vdev);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
+    return &vsc->dev;
+}
+
 static Property vhost_scsi_properties[] = {
     DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
     DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
@@ -307,6 +314,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
     vdc->get_features = vhost_scsi_common_get_features;
     vdc->set_config = vhost_scsi_common_set_config;
     vdc->set_status = vhost_scsi_set_status;
+    vdc->get_vhost = vhost_scsi_get_vhost;
     fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
 }
 
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index b875640147..e513e4fdda 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -276,6 +276,12 @@ static void vuf_device_unrealize(DeviceState *dev)
     fs->vhost_dev.vqs = NULL;
 }
 
+static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev)
+{
+    VHostUserFS *fs = VHOST_USER_FS(vdev);
+    return &fs->vhost_dev;
+}
+
 static const VMStateDescription vuf_vmstate = {
     .name = "vhost-user-fs",
     .unmigratable = 1,
@@ -313,6 +319,7 @@ static void vuf_class_init(ObjectClass *klass, void *data)
     vdc->set_status = vuf_set_status;
     vdc->guest_notifier_mask = vuf_guest_notifier_mask;
     vdc->guest_notifier_pending = vuf_guest_notifier_pending;
+    vdc->get_vhost = vuf_get_vhost;
 }
 
 static const TypeInfo vuf_info = {
diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c
index 08bccba9dc..3a7bf8e32d 100644
--- a/hw/virtio/vhost-user-rng.c
+++ b/hw/virtio/vhost-user-rng.c
@@ -247,6 +247,12 @@ static void vu_rng_device_unrealize(DeviceState *dev)
     vhost_user_cleanup(&rng->vhost_user);
 }
 
+static struct vhost_dev *vu_rng_get_vhost(VirtIODevice *vdev)
+{
+    VHostUserRNG *rng = VHOST_USER_RNG(vdev);
+    return &rng->vhost_dev;
+}
+
 static const VMStateDescription vu_rng_vmstate = {
     .name = "vhost-user-rng",
     .unmigratable = 1,
@@ -272,6 +278,7 @@ static void vu_rng_class_init(ObjectClass *klass, void *data)
     vdc->set_status = vu_rng_set_status;
     vdc->guest_notifier_mask = vu_rng_guest_notifier_mask;
     vdc->guest_notifier_pending = vu_rng_guest_notifier_pending;
+    vdc->get_vhost = vu_rng_get_vhost;
 }
 
 static const TypeInfo vu_rng_info = {
diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
index ad5c8ff5d5..7394818e00 100644
--- a/hw/virtio/vhost-vsock-common.c
+++ b/hw/virtio/vhost-vsock-common.c
@@ -258,6 +258,12 @@ void vhost_vsock_common_unrealize(VirtIODevice *vdev)
     virtio_cleanup(vdev);
 }
 
+static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev)
+{
+    VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
+    return &vvc->vhost_dev;
+}
+
 static Property vhost_vsock_common_properties[] = {
     DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket,
                             ON_OFF_AUTO_AUTO),
@@ -273,6 +279,7 @@ static void vhost_vsock_common_class_init(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
     vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask;
     vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending;
+    vdc->get_vhost = vhost_vsock_common_get_vhost;
 }
 
 static const TypeInfo vhost_vsock_common_info = {
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index b643f42ea4..a25ec5b032 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1739,6 +1739,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
     /* should only be called after backend is connected */
     assert(hdev->vhost_ops);
 
+    vdev->vhost_started = true;
     hdev->started = true;
     hdev->vdev = vdev;
 
@@ -1811,7 +1812,7 @@ fail_vq:
 
 fail_mem:
 fail_features:
-
+    vdev->vhost_started = false;
     hdev->started = false;
     return r;
 }
@@ -1842,6 +1843,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
     }
     vhost_log_put(hdev, true);
     hdev->started = false;
+    vdev->vhost_started = false;
     hdev->vdev = NULL;
 }
 
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 0a1f3dfdbe..947a11c3af 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -961,6 +961,15 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
     return cryptodev_vhost_virtqueue_pending(vdev, queue, idx);
 }
 
+static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev)
+{
+    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+    CryptoDevBackend *b = vcrypto->cryptodev;
+    CryptoDevBackendClient *cc = b->conf.peers.ccs[0];
+    CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0);
+    return &vhost_crypto->dev;
+}
+
 static void virtio_crypto_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -977,6 +986,7 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
     vdc->set_status = virtio_crypto_set_status;
     vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask;
     vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending;
+    vdc->get_vhost = virtio_crypto_get_vhost;
 }
 
 static void virtio_crypto_instance_init(Object *obj)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index cbb4920f49..80c7708c7e 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3271,6 +3271,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size)
 
     vdev->start_on_kick = false;
     vdev->started = false;
+    vdev->vhost_started = false;
     vdev->device_id = device_id;
     vdev->status = 0;
     qatomic_set(&vdev->isr, 0);
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 5d774684b1..8e12aeebc1 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -22,6 +22,7 @@
 #include "standard-headers/linux/virtio_config.h"
 #include "standard-headers/linux/virtio_ring.h"
 #include "qom/object.h"
+#include "hw/virtio/vhost.h"
 
 /* A guest should never accept this.  It implies negotiation is broken. */
 #define VIRTIO_F_BAD_FEATURE		30
@@ -102,6 +103,7 @@ struct VirtIODevice
     bool started;
     bool start_on_kick; /* when virtio 1.0 feature has not been negotiated */
     bool disable_legacy_check;
+    bool vhost_started;
     VMChangeStateEntry *vmstate;
     char *bus_name;
     uint8_t device_endian;
@@ -160,6 +162,7 @@ struct VirtioDeviceClass {
     int (*post_load)(VirtIODevice *vdev);
     const VMStateDescription *vmsd;
     bool (*primary_unplug_pending)(void *opaque);
+    struct vhost_dev *(*get_vhost)(VirtIODevice *vdev);
 };
 
 void virtio_instance_init_common(Object *proxy_obj, void *data,
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 3/8] qmp: add QMP command x-query-virtio
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 1/8] virtio: drop name parameter for virtio_init() Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 2/8] virtio: add vhost support for virtio devices Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 4/8] qmp: add QMP command x-query-virtio-status Jonah Palmer
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

This new command lists all the instances of VirtIODevices with
their canonical QOM path and name.

[Jonah: @virtio_list duplicates information that already exists in
 the QOM composition tree. However, extracting necessary information
 from this tree seems to be a bit convoluted.

 Instead, we still create our own list of realized virtio devices
 but use @qmp_qom_get with the device's canonical QOM path to confirm
 that the device exists and is realized. If the device exists but
 is actually not realized, then we remove it from our list (for
 synchronicity to the QOM composition tree).

 Also, the QMP command @x-query-virtio is redundant as @qom-list
 and @qom-get are sufficient to search '/machine/' for realized
 virtio devices. However, @x-query-virtio is much more convenient
 in listing realized virtio devices.]

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/virtio/meson.build      |  2 ++
 hw/virtio/virtio-stub.c    | 14 ++++++++
 hw/virtio/virtio.c         | 44 ++++++++++++++++++++++++
 include/hw/virtio/virtio.h |  1 +
 qapi/meson.build           |  1 +
 qapi/qapi-schema.json      |  1 +
 qapi/virtio.json           | 68 ++++++++++++++++++++++++++++++++++++++
 tests/qtest/qmp-cmd-test.c |  1 +
 8 files changed, 132 insertions(+)
 create mode 100644 hw/virtio/virtio-stub.c
 create mode 100644 qapi/virtio.json

diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 67dc77e00f..6fdc152780 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -6,8 +6,10 @@ softmmu_virtio_ss.add(when: 'CONFIG_VHOST', if_false: files('vhost-stub.c'))
 
 softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss)
 softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c'))
+softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c'))
 
 softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
+softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('virtio-stub.c'))
 
 virtio_ss = ss.source_set()
 virtio_ss.add(files('virtio.c'))
diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
new file mode 100644
index 0000000000..05a81edc92
--- /dev/null
+++ b/hw/virtio/virtio-stub.c
@@ -0,0 +1,14 @@
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-virtio.h"
+
+static void *qmp_virtio_unsupported(Error **errp)
+{
+    error_setg(errp, "Virtio is disabled");
+    return NULL;
+}
+
+VirtioInfoList *qmp_x_query_virtio(Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 80c7708c7e..28f25ff83a 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -13,12 +13,18 @@
 
 #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/error-report.h"
 #include "qemu/log.h"
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
+#include "qom/object_interfaces.h"
 #include "hw/virtio/virtio.h"
 #include "migration/qemu-file-types.h"
 #include "qemu/atomic.h"
@@ -29,6 +35,9 @@
 #include "sysemu/runstate.h"
 #include "standard-headers/linux/virtio_ids.h"
 
+/* QAPI list of realized VirtIODevices */
+static QTAILQ_HEAD(, VirtIODevice) virtio_list;
+
 /*
  * The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. This is the default, used by transports like PCI
@@ -3685,6 +3694,7 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
     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)
@@ -3699,6 +3709,7 @@ 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;
 }
@@ -3872,6 +3883,8 @@ static void virtio_device_class_init(ObjectClass *klass, void *data)
     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)
@@ -3882,6 +3895,37 @@ 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 const TypeInfo virtio_device_info = {
     .name = TYPE_VIRTIO_DEVICE,
     .parent = TYPE_DEVICE,
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 8e12aeebc1..ef99a626a8 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -110,6 +110,7 @@ struct VirtIODevice
     bool use_guest_notifier_mask;
     AddressSpace *dma_as;
     QLIST_HEAD(, VirtQueue) *vector_queues;
+    QTAILQ_ENTRY(VirtIODevice) next;
 };
 
 struct VirtioDeviceClass {
diff --git a/qapi/meson.build b/qapi/meson.build
index 656ef0e039..10c54d68e5 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -48,6 +48,7 @@ qapi_all_modules = [
   'sockets',
   'trace',
   'transaction',
+  'virtio',
   'yank',
 ]
 if have_system
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 4912b9744e..1512adaf92 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -93,3 +93,4 @@
 { 'include': 'audio.json' }
 { 'include': 'acpi.json' }
 { 'include': 'pci.json' }
+{ 'include': 'virtio.json' }
diff --git a/qapi/virtio.json b/qapi/virtio.json
new file mode 100644
index 0000000000..aee0e40daa
--- /dev/null
+++ b/qapi/virtio.json
@@ -0,0 +1,68 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+
+##
+# = Virtio devices
+##
+
+##
+# @VirtioInfo:
+#
+# Basic information about a given VirtIODevice
+#
+# @path: The VirtIODevice's canonical QOM path
+#
+# @name: Name of the VirtIODevice
+#
+# Since: 7.0
+#
+##
+{ 'struct': 'VirtioInfo',
+  'data': { 'path': 'str',
+            'name': 'str' } }
+
+##
+# @x-query-virtio:
+#
+# Returns a list of all realized VirtIODevices
+#
+# Features:
+# @unstable: This command is meant for debugging.
+#
+# Returns: List of gathered VirtIODevices
+#
+# Since: 7.0
+#
+# Example:
+#
+# -> { "execute": "x-query-virtio" }
+# <- { "return": [
+#        {
+#            "path": "/machine/peripheral-anon/device[4]/virtio-backend",
+#            "name": "virtio-input"
+#        },
+#        {
+#            "path": "/machine/peripheral/crypto0/virtio-backend",
+#            "name": "virtio-crypto"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[2]/virtio-backend",
+#            "name": "virtio-scsi"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[1]/virtio-backend",
+#            "name": "virtio-net"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[0]/virtio-backend",
+#            "name": "virtio-serial"
+#        }
+#      ]
+#    }
+#
+##
+
+{ 'command': 'x-query-virtio',
+  'returns': [ 'VirtioInfo' ],
+  'features': [ 'unstable' ] }
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index 7f103ea3fd..fd00ee2777 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -103,6 +103,7 @@ static bool query_is_ignored(const char *cmd)
         "query-gic-capabilities", /* arm */
         /* Success depends on target-specific build configuration: */
         "query-pci",              /* CONFIG_PCI */
+        "x-query-virtio",         /* CONFIG_VIRTIO */
         /* Success depends on launching SEV guest */
         "query-sev-launch-measure",
         /* Success depends on Host or Hypervisor SEV support */
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 4/8] qmp: add QMP command x-query-virtio-status
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
                   ` (2 preceding siblings ...)
  2022-04-01 13:23 ` [PATCH v14 3/8] qmp: add QMP command x-query-virtio Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status Jonah Palmer
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

This new command shows the status of a VirtIODevice, including
its corresponding vhost device's status (if active).

Next patch will improve output by decoding feature bits, including
vhost device's feature bits (backend, protocol, acked, and features).
Also will decode status bits of a VirtIODevice.

[Jonah: From patch v12; added a check to @virtio_device_find
 to ensure synchronicity between @virtio_list and the devices in the QOM
 composition tree.]

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/virtio/virtio-stub.c |   5 +
 hw/virtio/virtio.c      | 104 +++++++++++++++++++
 qapi/virtio.json        | 222 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 331 insertions(+)

diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
index 05a81edc92..0b432e8de7 100644
--- a/hw/virtio/virtio-stub.c
+++ b/hw/virtio/virtio-stub.c
@@ -12,3 +12,8 @@ VirtioInfoList *qmp_x_query_virtio(Error **errp)
 {
     return qmp_virtio_unsupported(errp);
 }
+
+VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 28f25ff83a..7f8eb29ced 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3926,6 +3926,110 @@ VirtioInfoList *qmp_x_query_virtio(Error **errp)
     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;
+}
+
+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 = vdev->guest_features;
+    status->host_features = vdev->host_features;
+    status->backend_features = 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 = 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;
+    status->has_vhost_dev = vdev->vhost_started;
+
+    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 = hdev->features;
+        status->vhost_dev->acked_features = hdev->acked_features;
+        status->vhost_dev->backend_features = hdev->backend_features;
+        status->vhost_dev->protocol_features = 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;
+}
+
 static const TypeInfo virtio_device_info = {
     .name = TYPE_VIRTIO_DEVICE,
     .parent = TYPE_DEVICE,
diff --git a/qapi/virtio.json b/qapi/virtio.json
index aee0e40daa..ba61d83df7 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -66,3 +66,225 @@
 { 'command': 'x-query-virtio',
   'returns': [ 'VirtioInfo' ],
   'features': [ 'unstable' ] }
+
+##
+# @VhostStatus:
+#
+# Information about a vhost device. This information will only be
+# displayed if the vhost device is active.
+#
+# @n-mem-sections: vhost_dev n_mem_sections
+#
+# @n-tmp-sections: vhost_dev n_tmp_sections
+#
+# @nvqs: vhost_dev nvqs (number of virtqueues being used)
+#
+# @vq-index: vhost_dev vq_index
+#
+# @features: vhost_dev features
+#
+# @acked-features: vhost_dev acked_features
+#
+# @backend-features: vhost_dev backend_features
+#
+# @protocol-features: vhost_dev protocol_features
+#
+# @max-queues: vhost_dev max_queues
+#
+# @backend-cap: vhost_dev backend_cap
+#
+# @log-enabled: vhost_dev log_enabled flag
+#
+# @log-size: vhost_dev log_size
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VhostStatus',
+  'data': { 'n-mem-sections': 'int',
+            'n-tmp-sections': 'int',
+            'nvqs': 'uint32',
+            'vq-index': 'int',
+            'features': 'uint64',
+            'acked-features': 'uint64',
+            'backend-features': 'uint64',
+            'protocol-features': 'uint64',
+            'max-queues': 'uint64',
+            'backend-cap': 'uint64',
+            'log-enabled': 'bool',
+            'log-size': 'uint64' } }
+
+##
+# @VirtioStatus:
+#
+# Full status of the virtio device with most VirtIODevice members.
+# Also includes the full status of the corresponding vhost device
+# if the vhost device is active.
+#
+# @name: VirtIODevice name
+#
+# @device-id: VirtIODevice ID
+#
+# @vhost-started: VirtIODevice vhost_started flag
+#
+# @guest-features: VirtIODevice guest_features
+#
+# @host-features: VirtIODevice host_features
+#
+# @backend-features: VirtIODevice backend_features
+#
+# @device-endian: VirtIODevice device_endian
+#
+# @num-vqs: VirtIODevice virtqueue count. This is the number of active
+#           virtqueues being used by the VirtIODevice.
+#
+# @status: VirtIODevice configuration status (VirtioDeviceStatus)
+#
+# @isr: VirtIODevice ISR
+#
+# @queue-sel: VirtIODevice queue_sel
+#
+# @vm-running: VirtIODevice vm_running flag
+#
+# @broken: VirtIODevice broken flag
+#
+# @disabled: VirtIODevice disabled flag
+#
+# @use-started: VirtIODevice use_started flag
+#
+# @started: VirtIODevice started flag
+#
+# @start-on-kick: VirtIODevice start_on_kick flag
+#
+# @disable-legacy-check: VirtIODevice disabled_legacy_check flag
+#
+# @bus-name: VirtIODevice bus_name
+#
+# @use-guest-notifier-mask: VirtIODevice use_guest_notifier_mask flag
+#
+# @vhost-dev: Corresponding vhost device info for a given VirtIODevice.
+#             Present if the given VirtIODevice has an active vhost
+#             device.
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtioStatus',
+  'data': { 'name': 'str',
+            'device-id': 'uint16',
+            'vhost-started': 'bool',
+            'device-endian': 'str',
+            'guest-features': 'uint64',
+            'host-features': 'uint64',
+            'backend-features': 'uint64',
+            'num-vqs': 'int',
+            'status': 'uint8',
+            'isr': 'uint8',
+            'queue-sel': 'uint16',
+            'vm-running': 'bool',
+            'broken': 'bool',
+            'disabled': 'bool',
+            'use-started': 'bool',
+            'started': 'bool',
+            'start-on-kick': 'bool',
+            'disable-legacy-check': 'bool',
+            'bus-name': 'str',
+            'use-guest-notifier-mask': 'bool',
+            '*vhost-dev': 'VhostStatus' } }
+
+##
+# @x-query-virtio-status:
+#
+# Poll for a comprehensive status of a given virtio device
+#
+# @path: Canonical QOM path of the VirtIODevice
+#
+# Features:
+# @unstable: This command is meant for debugging.
+#
+# Returns: VirtioStatus of the virtio device
+#
+# Since: 7.0
+#
+# Examples:
+#
+# 1. Poll for the status of virtio-crypto (no vhost-crypto active)
+#
+# -> { "execute": "x-query-virtio-status",
+#      "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend" }
+#    }
+# <- { "return": {
+#            "device-endian": "little",
+#            "bus-name": "",
+#            "disable-legacy-check": false,
+#            "name": "virtio-crypto",
+#            "started": true,
+#            "device-id": 20,
+#            "backend-features": 0,
+#            "start-on-kick": false,
+#            "isr": 1,
+#            "broken": false,
+#            "status": 15,
+#            "num-vqs": 2,
+#            "guest-features": 5100273664,
+#            "host-features": 6325010432,
+#            "use-guest-notifier-mask": true,
+#            "vm-running": true,
+#            "queue-sel": 1,
+#            "disabled": false,
+#            "vhost-started": false,
+#            "use-started": true
+#      }
+#    }
+#
+# 2. Poll for the status of virtio-net (vhost-net is active)
+#
+# -> { "execute": "x-query-virtio-status",
+#      "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend" }
+#    }
+# <- { "return": {
+#            "device-endian": "little",
+#            "bus-name": "",
+#            "disabled-legacy-check": false,
+#            "name": "virtio-net",
+#            "started": true,
+#            "device-id": 1,
+#            "vhost-dev": {
+#               "n-tmp-sections": 4,
+#               "n-mem-sections": 4,
+#               "max-queues": 1,
+#               "backend-cap": 2,
+#               "log-size": 0,
+#               "backend-features": 0,
+#               "nvqs": 2,
+#               "protocol-features": 0,
+#               "vq-index": 0,
+#               "log-enabled": false,
+#               "acked-features": 5100306432,
+#               "features": 13908344832
+#            },
+#            "backend-features": 6337593319,
+#            "start-on-kick": false,
+#            "isr": 1,
+#            "broken": false,
+#            "status": 15,
+#            "num-vqs": 3,
+#            "guest-features": 5111807911,
+#            "host-features": 6337593319,
+#            "use-guest-notifier-mask": true,
+#            "vm-running": true,
+#            "queue-sel": 2,
+#            "disabled": false,
+#            "vhost-started": true,
+#            "use-started": true
+#      }
+#    }
+#
+##
+
+{ 'command': 'x-query-virtio-status',
+  'data': { 'path': 'str' },
+  'returns': 'VirtioStatus',
+  'features': [ 'unstable' ] }
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
                   ` (3 preceding siblings ...)
  2022-04-01 13:23 ` [PATCH v14 4/8] qmp: add QMP command x-query-virtio-status Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-05-16 20:26   ` Michael S. Tsirkin
  2022-04-01 13:23 ` [PATCH v14 6/8] qmp: add QMP commands for virtio/vhost queue-status Jonah Palmer
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

Display feature names instead of bitmaps for host, guest, and
backend for VirtIODevices.

Display status names instead of bitmaps for VirtIODevices.

Display feature names instead of bitmaps for backend, protocol,
acked, and features (hdev->features) for vhost devices.

Decode features according to device ID. Decode statuses
according to configuration status bitmap (config_status_map).
Decode vhost user protocol features according to vhost user
protocol bitmap (vhost_user_protocol_map).

Transport features are on the first line. Undecoded bits (if
any) are stored in a separate field.

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/block/virtio-blk.c          |  29 ++++
 hw/char/virtio-serial-bus.c    |  11 ++
 hw/display/virtio-gpu.c        |  18 ++
 hw/input/virtio-input.c        |  10 ++
 hw/net/virtio-net.c            |  47 +++++
 hw/scsi/virtio-scsi.c          |  17 ++
 hw/virtio/vhost-user-fs.c      |  10 ++
 hw/virtio/vhost-user-i2c.c     |  14 ++
 hw/virtio/vhost-vsock-common.c |  10 ++
 hw/virtio/virtio-balloon.c     |  14 ++
 hw/virtio/virtio-crypto.c      |  10 ++
 hw/virtio/virtio-iommu.c       |  14 ++
 hw/virtio/virtio-mem.c         |  11 ++
 hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
 include/hw/virtio/vhost.h      |   3 +
 include/hw/virtio/virtio.h     |  19 +++
 qapi/virtio.json               | 156 ++++++++++++++---
 17 files changed, 667 insertions(+), 28 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 27c71ad316..f104603040 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -13,6 +13,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/iov.h"
 #include "qemu/module.h"
 #include "qemu/error-report.h"
@@ -33,10 +34,38 @@
 #include "migration/qemu-file-types.h"
 #include "hw/virtio/virtio-access.h"
 #include "qemu/coroutine.h"
+#include "standard-headers/linux/vhost_types.h"
 
 /* Config size before the discard support (hide associated config fields) */
 #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
                                      max_discard_sectors)
+
+qmp_virtio_feature_map_t blk_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_BLK_F_##name, #name }
+    FEATURE_ENTRY(SIZE_MAX),
+    FEATURE_ENTRY(SEG_MAX),
+    FEATURE_ENTRY(GEOMETRY),
+    FEATURE_ENTRY(RO),
+    FEATURE_ENTRY(BLK_SIZE),
+    FEATURE_ENTRY(TOPOLOGY),
+    FEATURE_ENTRY(MQ),
+    FEATURE_ENTRY(DISCARD),
+    FEATURE_ENTRY(WRITE_ZEROES),
+#ifndef VIRTIO_BLK_NO_LEGACY
+    FEATURE_ENTRY(BARRIER),
+    FEATURE_ENTRY(SCSI),
+    FEATURE_ENTRY(FLUSH),
+    FEATURE_ENTRY(CONFIG_WCE),
+#endif /* !VIRTIO_BLK_NO_LEGACY */
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 /*
  * Starting from the discard feature, we can use this array to properly
  * set the config size depending on the features enabled.
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 7d4601cb5d..fbb31a2b16 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -20,6 +20,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/iov.h"
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
@@ -32,6 +33,16 @@
 #include "hw/virtio/virtio-serial.h"
 #include "hw/virtio/virtio-access.h"
 
+qmp_virtio_feature_map_t serial_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_CONSOLE_F_##name, #name }
+    FEATURE_ENTRY(SIZE),
+    FEATURE_ENTRY(MULTIPORT),
+    FEATURE_ENTRY(EMERG_WRITE),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 static struct VirtIOSerialDevices {
     QLIST_HEAD(, VirtIOSerial) devices;
 } vserdevices;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 529b5246b2..0bd5dc6232 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -29,10 +29,28 @@
 #include "qemu/log.h"
 #include "qemu/module.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/error-report.h"
+#include "standard-headers/linux/vhost_types.h"
 
 #define VIRTIO_GPU_VM_VERSION 1
 
+qmp_virtio_feature_map_t gpu_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_GPU_F_##name, #name }
+    FEATURE_ENTRY(VIRGL),
+    FEATURE_ENTRY(EDID),
+    FEATURE_ENTRY(RESOURCE_UUID),
+    FEATURE_ENTRY(RESOURCE_BLOB),
+    FEATURE_ENTRY(CONTEXT_INIT),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 static struct virtio_gpu_simple_resource*
 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
 static struct virtio_gpu_simple_resource *
diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
index 5b5398b3ca..fe0ed6d5b4 100644
--- a/hw/input/virtio-input.c
+++ b/hw/input/virtio-input.c
@@ -6,6 +6,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/iov.h"
 #include "qemu/module.h"
 #include "trace.h"
@@ -14,10 +15,19 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-input.h"
 
+#include "standard-headers/linux/vhost_types.h"
 #include "standard-headers/linux/input.h"
 
 #define VIRTIO_INPUT_VM_VERSION 1
 
+qmp_virtio_feature_map_t input_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 /* ----------------------------------------------------------------- */
 
 void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 027ce40c6f..9356958fb6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -35,9 +35,11 @@
 #include "hw/qdev-properties.h"
 #include "qapi/qapi-types-migration.h"
 #include "qapi/qapi-events-migration.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "hw/virtio/virtio-access.h"
 #include "migration/misc.h"
 #include "standard-headers/linux/ethtool.h"
+#include "standard-headers/linux/vhost_types.h"
 #include "sysemu/sysemu.h"
 #include "trace.h"
 #include "monitor/qdev.h"
@@ -90,6 +92,51 @@
                                          VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
                                          VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
 
+qmp_virtio_feature_map_t net_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_NET_F_##name, #name }
+    FEATURE_ENTRY(CSUM),
+    FEATURE_ENTRY(GUEST_CSUM),
+    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
+    FEATURE_ENTRY(MTU),
+    FEATURE_ENTRY(MAC),
+    FEATURE_ENTRY(GUEST_TSO4),
+    FEATURE_ENTRY(GUEST_TSO6),
+    FEATURE_ENTRY(GUEST_ECN),
+    FEATURE_ENTRY(GUEST_UFO),
+    FEATURE_ENTRY(HOST_TSO4),
+    FEATURE_ENTRY(HOST_TSO6),
+    FEATURE_ENTRY(HOST_ECN),
+    FEATURE_ENTRY(HOST_UFO),
+    FEATURE_ENTRY(MRG_RXBUF),
+    FEATURE_ENTRY(STATUS),
+    FEATURE_ENTRY(CTRL_VQ),
+    FEATURE_ENTRY(CTRL_RX),
+    FEATURE_ENTRY(CTRL_VLAN),
+    FEATURE_ENTRY(CTRL_RX_EXTRA),
+    FEATURE_ENTRY(GUEST_ANNOUNCE),
+    FEATURE_ENTRY(MQ),
+    FEATURE_ENTRY(CTRL_MAC_ADDR),
+    FEATURE_ENTRY(HASH_REPORT),
+    FEATURE_ENTRY(RSS),
+    FEATURE_ENTRY(RSC_EXT),
+    FEATURE_ENTRY(STANDBY),
+    FEATURE_ENTRY(SPEED_DUPLEX),
+#ifndef VIRTIO_NET_NO_LEGACY
+    FEATURE_ENTRY(GSO),
+#endif /* VIRTIO_NET_NO_LEGACY */
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_NET_F_##name, #name }
+    FEATURE_ENTRY(VIRTIO_NET_HDR),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 static const VirtIOFeature feature_sizes[] = {
     {.flags = 1ULL << VIRTIO_NET_F_MAC,
      .end = endof(struct virtio_net_config, mac)},
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 2a6141d081..9ca8faa40e 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -15,7 +15,9 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/vhost_types.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "migration/qemu-file-types.h"
 #include "qemu/error-report.h"
@@ -29,6 +31,21 @@
 #include "hw/virtio/virtio-access.h"
 #include "trace.h"
 
+qmp_virtio_feature_map_t scsi_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_SCSI_F_##name, #name }
+    FEATURE_ENTRY(INOUT),
+    FEATURE_ENTRY(HOTPLUG),
+    FEATURE_ENTRY(CHANGE),
+    FEATURE_ENTRY(T10_PI),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 static inline int virtio_scsi_get_lun(uint8_t *lun)
 {
     return ((lun[2] << 8) | lun[3]) & 0x3FFF;
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index e513e4fdda..096cc07c44 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -15,6 +15,7 @@
 #include <sys/ioctl.h>
 #include "standard-headers/linux/virtio_fs.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties-system.h"
 #include "hw/virtio/virtio-bus.h"
@@ -23,6 +24,15 @@
 #include "hw/virtio/vhost-user-fs.h"
 #include "monitor/monitor.h"
 #include "sysemu/sysemu.h"
+#include "standard-headers/linux/vhost_types.h"
+
+qmp_virtio_feature_map_t fs_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
 
 static const int user_feature_bits[] = {
     VIRTIO_F_VERSION_1,
diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
index 6020eee093..931ec9836c 100644
--- a/hw/virtio/vhost-user-i2c.c
+++ b/hw/virtio/vhost-user-i2c.c
@@ -8,11 +8,25 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/vhost-user-i2c.h"
 #include "qemu/error-report.h"
 #include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/vhost_types.h"
+
+qmp_virtio_feature_map_t i2c_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_I2C_F_##name, #name }
+    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
 
 static const int feature_bits[] = {
     VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
index 7394818e00..b03f94d8f8 100644
--- a/hw/virtio/vhost-vsock-common.c
+++ b/hw/virtio/vhost-vsock-common.c
@@ -11,12 +11,22 @@
 #include "qemu/osdep.h"
 #include "standard-headers/linux/virtio_vsock.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "hw/virtio/virtio-access.h"
 #include "qemu/error-report.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-vsock.h"
 #include "qemu/iov.h"
 #include "monitor/monitor.h"
+#include "standard-headers/linux/vhost_types.h"
+
+qmp_virtio_feature_map_t vsock_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
 
 const int feature_bits[] = {
     VIRTIO_VSOCK_F_SEQPACKET,
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 193ff5261c..b2ae0a4d8c 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -28,6 +28,7 @@
 #include "qapi/error.h"
 #include "qapi/qapi-events-machine.h"
 #include "qapi/visitor.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "trace.h"
 #include "qemu/error-report.h"
 #include "migration/misc.h"
@@ -38,6 +39,19 @@
 
 #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
 
+qmp_virtio_feature_map_t balloon_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_BALLOON_F_##name, #name }
+    FEATURE_ENTRY(MUST_TELL_HOST),
+    FEATURE_ENTRY(STATS_VQ),
+    FEATURE_ENTRY(DEFLATE_ON_OOM),
+    FEATURE_ENTRY(FREE_PAGE_HINT),
+    FEATURE_ENTRY(PAGE_POISON),
+    FEATURE_ENTRY(REPORTING),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 typedef struct PartiallyBalloonedPage {
     ram_addr_t base_gpa;
     unsigned long *bitmap;
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 947a11c3af..5c9a3d045d 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -16,6 +16,7 @@
 #include "qemu/main-loop.h"
 #include "qemu/module.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/error-report.h"
 
 #include "hw/virtio/virtio.h"
@@ -23,10 +24,19 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-access.h"
 #include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/vhost_types.h"
 #include "sysemu/cryptodev-vhost.h"
 
 #define VIRTIO_CRYPTO_VM_VERSION 1
 
+qmp_virtio_feature_map_t crypto_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_F_##name, #name }
+    FEATURE_ENTRY(LOG_ALL),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 /*
  * Transfer virtqueue index to crypto queue index.
  * The control virtqueue is after the data virtqueues
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 4ed5bb16ba..d993106d10 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -26,6 +26,7 @@
 #include "sysemu/kvm.h"
 #include "sysemu/reset.h"
 #include "qapi/error.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qemu/error-report.h"
 #include "trace.h"
 
@@ -41,6 +42,19 @@
 #define VIOMMU_DEFAULT_QUEUE_SIZE 256
 #define VIOMMU_PROBE_SIZE 512
 
+qmp_virtio_feature_map_t iommu_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_IOMMU_F_##name, #name }
+    FEATURE_ENTRY(INPUT_RANGE),
+    FEATURE_ENTRY(DOMAIN_RANGE),
+    FEATURE_ENTRY(MAP_UNMAP),
+    FEATURE_ENTRY(BYPASS),
+    FEATURE_ENTRY(PROBE),
+    FEATURE_ENTRY(MMIO),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 typedef struct VirtIOIOMMUDomain {
     uint32_t id;
     bool bypass;
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index 465a996214..31e7af834e 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -25,6 +25,7 @@
 #include "hw/virtio/virtio-mem.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "exec/ram_addr.h"
 #include "migration/misc.h"
 #include "hw/boards.h"
@@ -32,6 +33,16 @@
 #include CONFIG_DEVICES
 #include "trace.h"
 
+qmp_virtio_feature_map_t mem_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_MEM_F_##name, #name }
+#ifndef CONFIG_ACPI
+    FEATURE_ENTRY(ACPI_PXM),
+#endif /* CONFIG_ACPI */
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
 /*
  * We only had legacy x86 guests that did not support
  * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7f8eb29ced..af376be933 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -34,10 +34,99 @@
 #include "sysemu/dma.h"
 #include "sysemu/runstate.h"
 #include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/vhost_types.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
+
+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
+};
+
+static qmp_virtio_feature_map_t transport_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_F_##name, #name }
+#ifndef VIRTIO_CONFIG_NO_LEGACY
+    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
+    FEATURE_ENTRY(ANY_LAYOUT),
+#endif /* VIRTIO_CONFIG_NO_LEGACY */
+    FEATURE_ENTRY(VERSION_1),
+    FEATURE_ENTRY(IOMMU_PLATFORM),
+    FEATURE_ENTRY(RING_PACKED),
+    FEATURE_ENTRY(ORDER_PLATFORM),
+    FEATURE_ENTRY(SR_IOV),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VIRTIO_RING_F_##name, #name }
+    FEATURE_ENTRY(INDIRECT_DESC),
+    FEATURE_ENTRY(EVENT_IDX),
+#undef FEATURE_ENTRY
+#define FEATURE_ENTRY(name) \
+    { VHOST_USER_F_##name, #name }
+    FEATURE_ENTRY(PROTOCOL_FEATURES),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
+static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
+#define FEATURE_ENTRY(name) \
+    { VHOST_USER_PROTOCOL_F_##name, #name }
+    FEATURE_ENTRY(MQ),
+    FEATURE_ENTRY(LOG_SHMFD),
+    FEATURE_ENTRY(RARP),
+    FEATURE_ENTRY(REPLY_ACK),
+    FEATURE_ENTRY(NET_MTU),
+    FEATURE_ENTRY(SLAVE_REQ),
+    FEATURE_ENTRY(CROSS_ENDIAN),
+    FEATURE_ENTRY(CRYPTO_SESSION),
+    FEATURE_ENTRY(PAGEFAULT),
+    FEATURE_ENTRY(CONFIG),
+    FEATURE_ENTRY(SLAVE_SEND_FD),
+    FEATURE_ENTRY(HOST_NOTIFIER),
+    FEATURE_ENTRY(INFLIGHT_SHMFD),
+    FEATURE_ENTRY(RESET_DEVICE),
+    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
+    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
+#undef FEATURE_ENTRY
+    { -1, "" }
+};
+
+/* virtio device configuration statuses */
+static qmp_virtio_feature_map_t config_status_map[] = {
+#define STATUS_ENTRY(name) \
+    { VIRTIO_CONFIG_S_##name, #name }
+    STATUS_ENTRY(DRIVER_OK),
+    STATUS_ENTRY(FEATURES_OK),
+    STATUS_ENTRY(DRIVER),
+    STATUS_ENTRY(NEEDS_RESET),
+    STATUS_ENTRY(FAILED),
+    STATUS_ENTRY(ACKNOWLEDGE),
+#undef STATUS_ENTRY
+    { -1, "" }
+};
+
 /*
  * The alignment to use between consumer and producer parts of vring.
  * x86 pagesize again. This is the default, used by transports like PCI
@@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
     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_name); \
+            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, 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, transport_map, 0, bitmap);
+
+    /* device features */
+    switch (device_id) {
+#ifdef CONFIG_VIRTIO_SERIAL
+    case VIRTIO_ID_CONSOLE:
+        features->dev_features =
+            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_BLK
+    case VIRTIO_ID_BLOCK:
+        features->dev_features =
+            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_GPU
+    case VIRTIO_ID_GPU:
+        features->dev_features =
+            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_NET
+    case VIRTIO_ID_NET:
+        features->dev_features =
+            CONVERT_FEATURES(strList, net_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_SCSI
+    case VIRTIO_ID_SCSI:
+        features->dev_features =
+            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_BALLOON
+    case VIRTIO_ID_BALLOON:
+        features->dev_features =
+            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_IOMMU
+    case VIRTIO_ID_IOMMU:
+        features->dev_features =
+            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_INPUT
+    case VIRTIO_ID_INPUT:
+        features->dev_features =
+            CONVERT_FEATURES(strList, input_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VHOST_USER_FS
+    case VIRTIO_ID_FS:
+        features->dev_features =
+            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VHOST_VSOCK
+    case VIRTIO_ID_VSOCK:
+        features->dev_features =
+            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_CRYPTO
+    case VIRTIO_ID_CRYPTO:
+        features->dev_features =
+            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_MEM
+    case VIRTIO_ID_MEM:
+        features->dev_features =
+            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
+        break;
+#endif
+#ifdef CONFIG_VIRTIO_I2C_ADAPTER
+    case VIRTIO_ID_I2C_ADAPTER:
+        features->dev_features =
+            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
+        break;
+#endif
+    /* No features */
+    case VIRTIO_ID_9P:
+    case VIRTIO_ID_PMEM:
+    case VIRTIO_ID_RNG:
+    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;
@@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
     status->name = g_strdup(vdev->name);
     status->device_id = vdev->device_id;
     status->vhost_started = vdev->vhost_started;
-    status->guest_features = vdev->guest_features;
-    status->host_features = vdev->host_features;
-    status->backend_features = vdev->backend_features;
+    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:
@@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
     }
 
     status->num_vqs = virtio_get_num_queues(vdev);
-    status->status = vdev->status;
+    status->status = qmp_decode_status(vdev->status);
     status->isr = vdev->isr;
     status->queue_sel = vdev->queue_sel;
     status->vm_running = vdev->vm_running;
@@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
         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 = hdev->features;
-        status->vhost_dev->acked_features = hdev->acked_features;
-        status->vhost_dev->backend_features = hdev->backend_features;
-        status->vhost_dev->protocol_features = hdev->protocol_features;
+        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;
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 58a73e7b7a..4aaa21faf6 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -5,6 +5,9 @@
 #include "hw/virtio/virtio.h"
 #include "exec/memory.h"
 
+#define VHOST_F_DEVICE_IOTLB 63
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+
 /* Generic structures common for any vhost based device. */
 
 struct vhost_inflight {
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index ef99a626a8..9df4e081c9 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -71,6 +71,25 @@ typedef struct VirtQueueElement
 #define TYPE_VIRTIO_DEVICE "virtio-device"
 OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
 
+typedef struct {
+    int virtio_bit;
+    const char *feature_name;
+} qmp_virtio_feature_map_t;
+
+extern qmp_virtio_feature_map_t serial_map[];
+extern qmp_virtio_feature_map_t blk_map[];
+extern qmp_virtio_feature_map_t gpu_map[];
+extern qmp_virtio_feature_map_t net_map[];
+extern qmp_virtio_feature_map_t scsi_map[];
+extern qmp_virtio_feature_map_t balloon_map[];
+extern qmp_virtio_feature_map_t iommu_map[];
+extern qmp_virtio_feature_map_t input_map[];
+extern qmp_virtio_feature_map_t fs_map[];
+extern qmp_virtio_feature_map_t vsock_map[];
+extern qmp_virtio_feature_map_t crypto_map[];
+extern qmp_virtio_feature_map_t mem_map[];
+extern qmp_virtio_feature_map_t i2c_map[];
+
 enum virtio_device_endian {
     VIRTIO_DEVICE_ENDIAN_UNKNOWN,
     VIRTIO_DEVICE_ENDIAN_LITTLE,
diff --git a/qapi/virtio.json b/qapi/virtio.json
index ba61d83df7..474a8bd64e 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -106,10 +106,10 @@
             'n-tmp-sections': 'int',
             'nvqs': 'uint32',
             'vq-index': 'int',
-            'features': 'uint64',
-            'acked-features': 'uint64',
-            'backend-features': 'uint64',
-            'protocol-features': 'uint64',
+            'features': 'VirtioDeviceFeatures',
+            'acked-features': 'VirtioDeviceFeatures',
+            'backend-features': 'VirtioDeviceFeatures',
+            'protocol-features': 'VhostDeviceProtocols',
             'max-queues': 'uint64',
             'backend-cap': 'uint64',
             'log-enabled': 'bool',
@@ -176,11 +176,11 @@
             'device-id': 'uint16',
             'vhost-started': 'bool',
             'device-endian': 'str',
-            'guest-features': 'uint64',
-            'host-features': 'uint64',
-            'backend-features': 'uint64',
+            'guest-features': 'VirtioDeviceFeatures',
+            'host-features': 'VirtioDeviceFeatures',
+            'backend-features': 'VirtioDeviceFeatures',
             'num-vqs': 'int',
-            'status': 'uint8',
+            'status': 'VirtioDeviceStatus',
             'isr': 'uint8',
             'queue-sel': 'uint16',
             'vm-running': 'bool',
@@ -222,14 +222,28 @@
 #            "name": "virtio-crypto",
 #            "started": true,
 #            "device-id": 20,
-#            "backend-features": 0,
+#            "backend-features": {
+#               "transports": [],
+#               "dev-features": []
+#            },
 #            "start-on-kick": false,
 #            "isr": 1,
 #            "broken": false,
-#            "status": 15,
+#            "status": {
+#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
+#                            "DRIVER_OK"]
+#            },
 #            "num-vqs": 2,
-#            "guest-features": 5100273664,
-#            "host-features": 6325010432,
+#            "guest-features": {
+#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
+#               "dev-features": []
+#            },
+#            "host-features": {
+#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
+#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
+#                              "NOTIFY_ON_EMPTY"],
+#               "dev-features": []
+#            },
 #            "use-guest-notifier-mask": true,
 #            "vm-running": true,
 #            "queue-sel": 1,
@@ -257,22 +271,65 @@
 #               "max-queues": 1,
 #               "backend-cap": 2,
 #               "log-size": 0,
-#               "backend-features": 0,
+#               "backend-features": {
+#                  "transports": [],
+#                  "dev-features": []
+#               },
 #               "nvqs": 2,
-#               "protocol-features": 0,
+#               "protocol-features": {
+#                  "protocols": []
+#               },
 #               "vq-index": 0,
 #               "log-enabled": false,
-#               "acked-features": 5100306432,
-#               "features": 13908344832
+#               "acked-features": {
+#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
+#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
+#                  "dev-features": ["MRG_RXBUF"]
+#               },
+#               "features": {
+#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
+#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
+#                                 "NOTIFY_ON_EMPTY"],
+#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
+#               }
+#            },
+#            "backend-features": {
+#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
+#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
+#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
+#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
+#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
+#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
+#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
 #            },
-#            "backend-features": 6337593319,
 #            "start-on-kick": false,
 #            "isr": 1,
 #            "broken": false,
-#            "status": 15,
+#            "status": {
+#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
+#            },
 #            "num-vqs": 3,
-#            "guest-features": 5111807911,
-#            "host-features": 6337593319,
+#            "guest-features": {
+#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
+#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
+#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
+#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
+#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
+#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
+#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
+#            },
+#            "host-features": {
+#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
+#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
+#                              "NOTIFY_ON_EMPTY"],
+#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
+#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
+#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
+#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
+#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
+#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
+#                                "GUEST_CSUM", "CSUM"]
+#            },
 #            "use-guest-notifier-mask": true,
 #            "vm-running": true,
 #            "queue-sel": 2,
@@ -288,3 +345,62 @@
   'data': { 'path': 'str' },
   'returns': 'VirtioStatus',
   'features': [ 'unstable' ] }
+
+##
+# @VirtioDeviceStatus:
+#
+# A structure defined to list the configuration statuses of a virtio
+# device
+#
+# @statuses: List of decoded configuration statuses of the virtio
+#            device
+#
+# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
+#
+# Since: 7.0
+##
+
+{ 'struct': 'VirtioDeviceStatus',
+  'data': { 'statuses': [ 'str' ],
+            '*unknown-statuses': 'uint8' } }
+
+##
+# @VhostDeviceProtocols:
+#
+# A structure defined to list the vhost user protocol features of a
+# Vhost User device
+#
+# @protocols: List of decoded vhost user protocol features of a vhost
+#             user device
+#
+# @unknown-protocols: Vhost user device protocol features bitmap that
+#                     have not been decoded
+#
+# Since: 7.0
+##
+
+{ 'struct': 'VhostDeviceProtocols',
+  'data': { 'protocols': [ 'str' ],
+            '*unknown-protocols': 'uint64' } }
+
+##
+# @VirtioDeviceFeatures:
+#
+# The common fields that apply to most Virtio devices. Some devices
+# may not have their own device-specific features (e.g. virtio-rng).
+#
+# @transports: List of transport features of the virtio device
+#
+# @dev-features: List of device-specific features (if the device has
+#                unique features)
+#
+# @unknown-dev-features: Virtio device features bitmap that have not
+#                        been decoded
+#
+# Since: 7.0
+##
+
+{ 'struct': 'VirtioDeviceFeatures',
+  'data': { 'transports': [ 'str' ],
+            '*dev-features': [ 'str' ],
+            '*unknown-dev-features': 'uint64' } }
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 6/8] qmp: add QMP commands for virtio/vhost queue-status
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
                   ` (4 preceding siblings ...)
  2022-04-01 13:23 ` [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 7/8] qmp: add QMP command x-query-virtio-queue-element Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 8/8] hmp: add virtio commands Jonah Palmer
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

These new commands show the internal status of a VirtIODevice's
VirtQueue and a vhost device's vhost_virtqueue (if active).

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/virtio/virtio-stub.c |  14 +++
 hw/virtio/virtio.c      | 103 ++++++++++++++++
 qapi/virtio.json        | 252 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 369 insertions(+)

diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
index 0b432e8de7..13e5f93652 100644
--- a/hw/virtio/virtio-stub.c
+++ b/hw/virtio/virtio-stub.c
@@ -17,3 +17,17 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
 {
     return qmp_virtio_unsupported(errp);
 }
+
+VirtVhostQueueStatus *qmp_x_query_virtio_vhost_queue_status(const char *path,
+                                                            uint16_t queue,
+                                                            Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
+
+VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path,
+                                                 uint16_t queue,
+                                                 Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index af376be933..6d718d4fea 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4316,6 +4316,109 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
     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);
+    if (vdev == NULL) {
+        error_setg(errp, "Path %s is not a VirtIODevice", path);
+        return NULL;
+    }
+
+    if (queue >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue)) {
+        error_setg(errp, "Invalid virtqueue number %d", queue);
+        return NULL;
+    }
+
+    status = g_new0(VirtQueueStatus, 1);
+    status->name = g_strdup(vdev->name);
+    status->queue_index = vdev->vq[queue].queue_index;
+    status->inuse = vdev->vq[queue].inuse;
+    status->vring_num = vdev->vq[queue].vring.num;
+    status->vring_num_default = vdev->vq[queue].vring.num_default;
+    status->vring_align = vdev->vq[queue].vring.align;
+    status->vring_desc = vdev->vq[queue].vring.desc;
+    status->vring_avail = vdev->vq[queue].vring.avail;
+    status->vring_used = vdev->vq[queue].vring.used;
+    status->used_idx = vdev->vq[queue].used_idx;
+    status->signalled_used = vdev->vq[queue].signalled_used;
+    status->signalled_used_valid = vdev->vq[queue].signalled_used_valid;
+
+    if (vdev->vhost_started) {
+        VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
+        struct vhost_dev *hdev = vdc->get_vhost(vdev);
+
+        /* check if vq index exists for vhost as well  */
+        if (queue >= hdev->vq_index && queue < hdev->vq_index + hdev->nvqs) {
+            status->has_last_avail_idx = true;
+
+            int vhost_vq_index =
+                hdev->vhost_ops->vhost_get_vq_index(hdev, queue);
+            struct vhost_vring_state state = {
+                .index = vhost_vq_index,
+            };
+
+            status->last_avail_idx =
+                hdev->vhost_ops->vhost_get_vring_base(hdev, &state);
+        }
+    } else {
+        status->has_shadow_avail_idx = true;
+        status->has_last_avail_idx = true;
+        status->last_avail_idx = vdev->vq[queue].last_avail_idx;
+        status->shadow_avail_idx = vdev->vq[queue].shadow_avail_idx;
+    }
+
+    return status;
+}
+
 static const TypeInfo virtio_device_info = {
     .name = TYPE_VIRTIO_DEVICE,
     .parent = TYPE_DEVICE,
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 474a8bd64e..44cc05ceeb 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -404,3 +404,255 @@
   'data': { 'transports': [ 'str' ],
             '*dev-features': [ 'str' ],
             '*unknown-dev-features': 'uint64' } }
+
+##
+# @VirtQueueStatus:
+#
+# Information of a VirtIODevice VirtQueue, including most members of
+# the VirtQueue data structure.
+#
+# @name: Name of the VirtIODevice that uses this VirtQueue
+#
+# @queue-index: VirtQueue queue_index
+#
+# @inuse: VirtQueue inuse
+#
+# @vring-num: VirtQueue vring.num
+#
+# @vring-num-default: VirtQueue vring.num_default
+#
+# @vring-align: VirtQueue vring.align
+#
+# @vring-desc: VirtQueue vring.desc (descriptor area)
+#
+# @vring-avail: VirtQueue vring.avail (driver area)
+#
+# @vring-used: VirtQueue vring.used (device area)
+#
+# @last-avail-idx: VirtQueue last_avail_idx or return of vhost_dev
+#                  vhost_get_vring_base (if vhost active)
+#
+# @shadow-avail-idx: VirtQueue shadow_avail_idx
+#
+# @used-idx: VirtQueue used_idx
+#
+# @signalled-used: VirtQueue signalled_used
+#
+# @signalled-used-valid: VirtQueue signalled_used_valid flag
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtQueueStatus',
+  'data': { 'name': 'str',
+            'queue-index': 'uint16',
+            'inuse': 'uint32',
+            'vring-num': 'uint32',
+            'vring-num-default': 'uint32',
+            'vring-align': 'uint32',
+            'vring-desc': 'uint64',
+            'vring-avail': 'uint64',
+            'vring-used': 'uint64',
+            '*last-avail-idx': 'uint16',
+            '*shadow-avail-idx': 'uint16',
+            'used-idx': 'uint16',
+            'signalled-used': 'uint16',
+            'signalled-used-valid': 'bool' } }
+
+##
+# @x-query-virtio-queue-status:
+#
+# Return the status of a given VirtIODevice's VirtQueue
+#
+# @path: VirtIODevice canonical QOM path
+#
+# @queue: VirtQueue index to examine
+#
+# Features:
+# @unstable: This command is meant for debugging.
+#
+# Returns: VirtQueueStatus of the VirtQueue
+#
+# Notes: last_avail_idx will not be displayed in the case where
+#        the selected VirtIODevice has a running vhost device and
+#        the VirtIODevice VirtQueue index (queue) does not exist for
+#        the corresponding vhost device vhost_virtqueue. Also,
+#        shadow_avail_idx will not be displayed in the case where
+#        the selected VirtIODevice has a running vhost device.
+#
+# Since: 7.0
+#
+# Examples:
+#
+# 1. Get VirtQueueStatus for virtio-vsock (vhost-vsock running)
+#
+# -> { "execute": "x-query-virtio-queue-status",
+#      "arguments": { "path": "/machine/peripheral/vsock0/virtio-backend",
+#                     "queue": 1 }
+#    }
+# <- { "return": {
+#            "signalled-used": 0,
+#            "inuse": 0,
+#            "vring-align": 4096,
+#            "vring-desc": 5217370112,
+#            "signalled-used-valid": false,
+#            "vring-num-default": 128,
+#            "vring-avail": 5217372160,
+#            "queue-index": 1,
+#            "last-avail-idx": 0,
+#            "vring-used": 5217372480,
+#            "used-idx": 0,
+#            "name": "vhost-vsock",
+#            "vring-num": 128 }
+#    }
+#
+# 2. Get VirtQueueStatus for virtio-serial (no vhost)
+#
+# -> { "execute": "x-query-virtio-queue-status",
+#      "arguments": { "path": "/machine/peripheral-anon/device[0]/virtio-backend",
+#                     "queue": 20 }
+#    }
+# <- { "return": {
+#            "signalled-used": 0,
+#            "inuse": 0,
+#            "vring-align": 4096,
+#            "vring-desc": 5182074880,
+#            "signalled-used-valid": false,
+#            "vring-num-default": 128,
+#            "vring-avail": 5182076928,
+#            "queue-index": 20,
+#            "last-avail-idx": 0,
+#            "vring-used": 5182077248,
+#            "used-idx": 0,
+#            "name": "virtio-serial",
+#            "shadow-avail-idx": 0,
+#            "vring-num": 128 }
+#    }
+#
+##
+
+{ 'command': 'x-query-virtio-queue-status',
+  'data': { 'path': 'str', 'queue': 'uint16' },
+  'returns': 'VirtQueueStatus',
+  'features': [ 'unstable' ] }
+
+##
+# @VirtVhostQueueStatus:
+#
+# Information of a vhost device's vhost_virtqueue, including most
+# members of the vhost_dev vhost_virtqueue data structure.
+#
+# @name: Name of the VirtIODevice that uses this vhost_virtqueue
+#
+# @kick: vhost_virtqueue kick
+#
+# @call: vhost_virtqueue call
+#
+# @desc: vhost_virtqueue desc
+#
+# @avail: vhost_virtqueue avail
+#
+# @used: vhost_virtqueue used
+#
+# @num: vhost_virtqueue num
+#
+# @desc-phys: vhost_virtqueue desc_phys (descriptor area phys. addr.)
+#
+# @desc-size: vhost_virtqueue desc_size
+#
+# @avail-phys: vhost_virtqueue avail_phys (driver area phys. addr.)
+#
+# @avail-size: vhost_virtqueue avail_size
+#
+# @used-phys: vhost_virtqueue used_phys (device area phys. addr.)
+#
+# @used-size: vhost_virtqueue used_size
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtVhostQueueStatus',
+  'data': { 'name': 'str',
+            'kick': 'int',
+            'call': 'int',
+            'desc': 'uint64',
+            'avail': 'uint64',
+            'used': 'uint64',
+            'num': 'int',
+            'desc-phys': 'uint64',
+            'desc-size': 'uint32',
+            'avail-phys': 'uint64',
+            'avail-size': 'uint32',
+            'used-phys': 'uint64',
+            'used-size': 'uint32' } }
+
+##
+# @x-query-virtio-vhost-queue-status:
+#
+# Return information of a given vhost device's vhost_virtqueue
+#
+# @path: VirtIODevice canonical QOM path
+#
+# @queue: vhost_virtqueue index to examine
+#
+# Features:
+# @unstable: This command is meant for debugging.
+#
+# Returns: VirtVhostQueueStatus of the vhost_virtqueue
+#
+# Since: 7.0
+#
+# Examples:
+#
+# 1. Get vhost_virtqueue status for vhost-crypto
+#
+# -> { "execute": "x-query-virtio-vhost-queue-status",
+#      "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend",
+#                     "queue": 0 }
+#    }
+# <- { "return": {
+#            "avail-phys": 5216124928,
+#            "used-phys": 5216127040,
+#            "avail-size": 2054,
+#            "desc-size": 16384,
+#            "used-size": 8198,
+#            "desc": 140141447430144,
+#            "num": 1024,
+#            "name": "virtio-crypto",
+#            "call": 0,
+#            "avail": 140141447446528,
+#            "desc-phys": 5216108544,
+#            "used": 140141447448640,
+#            "kick": 0 }
+#    }
+#
+# 2. Get vhost_virtqueue status for vhost-vsock
+#
+# -> { "execute": "x-query-virtio-vhost-queue-status",
+#      "arguments": { "path": "/machine/peripheral/vsock0/virtio-backend",
+#                     "queue": 0 }
+#    }
+# <- { "return": {
+#            "avail-phys": 5182261248,
+#            "used-phys": 5182261568,
+#            "avail-size": 262,
+#            "desc-size": 2048,
+#            "used-size": 1030,
+#            "desc": 140141413580800,
+#            "num": 128,
+#            "name": "vhost-vsock",
+#            "call": 0,
+#            "avail": 140141413582848,
+#            "desc-phys": 5182259200,
+#            "used": 140141413583168,
+#            "kick": 0 }
+#    }
+#
+##
+
+{ 'command': 'x-query-virtio-vhost-queue-status',
+  'data': { 'path': 'str', 'queue': 'uint16' },
+  'returns': 'VirtVhostQueueStatus',
+  'features': [ 'unstable' ] }
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 7/8] qmp: add QMP command x-query-virtio-queue-element
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
                   ` (5 preceding siblings ...)
  2022-04-01 13:23 ` [PATCH v14 6/8] qmp: add QMP commands for virtio/vhost queue-status Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  2022-04-01 13:23 ` [PATCH v14 8/8] hmp: add virtio commands Jonah Palmer
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

This new command shows the information of a VirtQueue element.

[Note: Up until v10 of this patch series, virtio.json had many (15+)
 enums defined (e.g. decoded device features, statuses, etc.). In v10
 most of these enums were removed and replaced with string literals.
 By doing this we get (1) simpler schema, (2) smaller generated code,
 and (3) less maintenance burden for when new things are added (e.g.
 devices, device features, etc.).]

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hw/virtio/virtio-stub.c |   9 ++
 hw/virtio/virtio.c      | 154 +++++++++++++++++++++++++++++++++
 qapi/virtio.json        | 183 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 346 insertions(+)

diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
index 13e5f93652..7ddb22cc5e 100644
--- a/hw/virtio/virtio-stub.c
+++ b/hw/virtio/virtio-stub.c
@@ -31,3 +31,12 @@ VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path,
 {
     return qmp_virtio_unsupported(errp);
 }
+
+VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path,
+                                                     uint16_t queue,
+                                                     bool has_index,
+                                                     uint16_t index,
+                                                     Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 6d718d4fea..8db6b435aa 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -489,6 +489,19 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem,
     address_space_cache_invalidate(&caches->used, pa, sizeof(VRingUsedElem));
 }
 
+/* Called within rcu_read_lock(). */
+static inline uint16_t vring_used_flags(VirtQueue *vq)
+{
+    VRingMemoryRegionCaches *caches = vring_get_region_caches(vq);
+    hwaddr pa = offsetof(VRingUsed, flags);
+
+    if (!caches) {
+        return 0;
+    }
+
+    return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa);
+}
+
 /* Called within rcu_read_lock().  */
 static uint16_t vring_used_idx(VirtQueue *vq)
 {
@@ -4419,6 +4432,147 @@ VirtQueueStatus *qmp_x_query_virtio_queue_status(const char *path,
     return status;
 }
 
+static strList *qmp_decode_vring_desc_flags(uint16_t flags)
+{
+    strList *list = NULL;
+    strList *node;
+    int i;
+
+    struct {
+        uint16_t flag;
+        const char *value;
+    } map[] = {
+        { VRING_DESC_F_NEXT, "next" },
+        { VRING_DESC_F_WRITE, "write" },
+        { VRING_DESC_F_INDIRECT, "indirect" },
+        { 1 << VRING_PACKED_DESC_F_AVAIL, "avail" },
+        { 1 << VRING_PACKED_DESC_F_USED, "used" },
+        { 0, "" }
+    };
+
+    for (i = 0; map[i].flag; i++) {
+        if ((map[i].flag & flags) == 0) {
+            continue;
+        }
+        node = g_malloc0(sizeof(strList));
+        node->value = g_strdup(map[i].value);
+        node->next = list;
+        list = node;
+    }
+
+    return list;
+}
+
+VirtioQueueElement *qmp_x_query_virtio_queue_element(const char *path,
+                                                     uint16_t queue,
+                                                     bool has_index,
+                                                     uint16_t index,
+                                                     Error **errp)
+{
+    VirtIODevice *vdev;
+    VirtQueue *vq;
+    VirtioQueueElement *element = NULL;
+
+    vdev = virtio_device_find(path);
+    if (vdev == NULL) {
+        error_setg(errp, "Path %s is not a VirtIO device", path);
+        return NULL;
+    }
+
+    if (queue >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue)) {
+        error_setg(errp, "Invalid virtqueue number %d", queue);
+        return NULL;
+    }
+    vq = &vdev->vq[queue];
+
+    if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
+        error_setg(errp, "Packed ring not supported");
+        return NULL;
+    } else {
+        unsigned int head, i, max;
+        VRingMemoryRegionCaches *caches;
+        MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+        MemoryRegionCache *desc_cache;
+        VRingDesc desc;
+        VirtioRingDescList *list = NULL;
+        VirtioRingDescList *node;
+        int rc; int ndescs;
+
+        RCU_READ_LOCK_GUARD();
+
+        max = vq->vring.num;
+
+        if (!has_index) {
+            head = vring_avail_ring(vq, vq->last_avail_idx % vq->vring.num);
+        } else {
+            head = vring_avail_ring(vq, index % vq->vring.num);
+        }
+        i = head;
+
+        caches = vring_get_region_caches(vq);
+        if (!caches) {
+            error_setg(errp, "Region caches not initialized");
+            return NULL;
+        }
+        if (caches->desc.len < max * sizeof(VRingDesc)) {
+            error_setg(errp, "Cannot map descriptor ring");
+            return NULL;
+        }
+
+        desc_cache = &caches->desc;
+        vring_split_desc_read(vdev, &desc, desc_cache, i);
+        if (desc.flags & VRING_DESC_F_INDIRECT) {
+            int64_t len;
+            len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as,
+                                           desc.addr, desc.len, false);
+            desc_cache = &indirect_desc_cache;
+            if (len < desc.len) {
+                error_setg(errp, "Cannot map indirect buffer");
+                goto done;
+            }
+
+            max = desc.len / sizeof(VRingDesc);
+            i = 0;
+            vring_split_desc_read(vdev, &desc, desc_cache, i);
+        }
+
+        element = g_new0(VirtioQueueElement, 1);
+        element->avail = g_new0(VirtioRingAvail, 1);
+        element->used = g_new0(VirtioRingUsed, 1);
+        element->name = g_strdup(vdev->name);
+        element->index = head;
+        element->avail->flags = vring_avail_flags(vq);
+        element->avail->idx = vring_avail_idx(vq);
+        element->avail->ring = head;
+        element->used->flags = vring_used_flags(vq);
+        element->used->idx = vring_used_idx(vq);
+        ndescs = 0;
+
+        do {
+            /* A buggy driver may produce an infinite loop */
+            if (ndescs >= max) {
+                break;
+            }
+            node = g_new0(VirtioRingDescList, 1);
+            node->value = g_new0(VirtioRingDesc, 1);
+            node->value->addr = desc.addr;
+            node->value->len = desc.len;
+            node->value->flags = qmp_decode_vring_desc_flags(desc.flags);
+            node->next = list;
+            list = node;
+
+            ndescs++;
+            rc = virtqueue_split_read_next_desc(vdev, &desc, desc_cache,
+                                                max, &i);
+        } while (rc == VIRTQUEUE_READ_DESC_MORE);
+        element->descs = list;
+done:
+        address_space_cache_destroy(&indirect_desc_cache);
+    }
+
+    return element;
+}
+
 static const TypeInfo virtio_device_info = {
     .name = TYPE_VIRTIO_DEVICE,
     .parent = TYPE_DEVICE,
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 44cc05ceeb..99b9064902 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -656,3 +656,186 @@
   'data': { 'path': 'str', 'queue': 'uint16' },
   'returns': 'VirtVhostQueueStatus',
   'features': [ 'unstable' ] }
+
+##
+# @VirtioRingDesc:
+#
+# Information regarding the vring descriptor area
+#
+# @addr: Guest physical address of the descriptor area
+#
+# @len: Length of the descriptor area
+#
+# @flags: List of descriptor flags
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtioRingDesc',
+  'data': { 'addr': 'uint64',
+            'len': 'uint32',
+            'flags': [ 'str' ] } }
+
+##
+# @VirtioRingAvail:
+#
+# Information regarding the avail vring (a.k.a. driver area)
+#
+# @flags: VRingAvail flags
+#
+# @idx: VRingAvail index
+#
+# @ring: VRingAvail ring[] entry at provided index
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtioRingAvail',
+  'data': { 'flags': 'uint16',
+            'idx': 'uint16',
+            'ring': 'uint16' } }
+
+##
+# @VirtioRingUsed:
+#
+# Information regarding the used vring (a.k.a. device area)
+#
+# @flags: VRingUsed flags
+#
+# @idx: VRingUsed index
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtioRingUsed',
+  'data': { 'flags': 'uint16',
+            'idx': 'uint16' } }
+
+##
+# @VirtioQueueElement:
+#
+# Information regarding a VirtQueue's VirtQueueElement including
+# descriptor, driver, and device areas
+#
+# @name: Name of the VirtIODevice that uses this VirtQueue
+#
+# @index: Index of the element in the queue
+#
+# @descs: List of descriptors (VirtioRingDesc)
+#
+# @avail: VRingAvail info
+#
+# @used: VRingUsed info
+#
+# Since: 7.0
+#
+##
+
+{ 'struct': 'VirtioQueueElement',
+  'data': { 'name': 'str',
+            'index': 'uint32',
+            'descs': [ 'VirtioRingDesc' ],
+            'avail': 'VirtioRingAvail',
+            'used': 'VirtioRingUsed' } }
+
+##
+# @x-query-virtio-queue-element:
+#
+# Return the information about a VirtQueue's VirtQueueElement
+#
+# @path: VirtIODevice canonical QOM path
+#
+# @queue: VirtQueue index to examine
+#
+# @index: Index of the element in the queue
+#         (default: head of the queue)
+#
+# Features:
+# @unstable: This command is meant for debugging.
+#
+# Returns: VirtioQueueElement information
+#
+# Since: 7.0
+#
+# Examples:
+#
+# 1. Introspect on virtio-net's VirtQueue 0 at index 5
+#
+# -> { "execute": "x-query-virtio-queue-element",
+#      "arguments": { "path": "/machine/peripheral-anon/device[1]/virtio-backend",
+#                     "queue": 0,
+#                     "index": 5 }
+#    }
+# <- { "return": {
+#            "index": 5,
+#            "name": "virtio-net",
+#            "descs": [
+#               { "flags": ["write"], "len": 1536, "addr": 5257305600 }
+#            ],
+#            "avail": {
+#               "idx": 256,
+#               "flags": 0,
+#               "ring": 5
+#            },
+#            "used": {
+#               "idx": 13,
+#               "flags": 0
+#            },
+#    }
+#
+# 2. Introspect on virtio-crypto's VirtQueue 1 at head
+#
+# -> { "execute": "x-query-virtio-queue-element",
+#      "arguments": { "path": "/machine/peripheral/crypto0/virtio-backend",
+#                     "queue": 1 }
+#    }
+# <- { "return": {
+#            "index": 0,
+#            "name": "virtio-crypto",
+#            "descs": [
+#               { "flags": [], "len": 0, "addr": 8080268923184214134 }
+#            ],
+#            "avail": {
+#               "idx": 280,
+#               "flags": 0,
+#               "ring": 0
+#            },
+#            "used": {
+#               "idx": 280,
+#               "flags": 0
+#            }
+#    }
+#
+# 3. Introspect on virtio-scsi's VirtQueue 2 at head
+#
+# -> { "execute": "x-query-virtio-queue-element",
+#      "arguments": { "path": "/machine/peripheral-anon/device[2]/virtio-backend",
+#                     "queue": 2 }
+#    }
+# <- { "return": {
+#            "index": 19,
+#            "name": "virtio-scsi",
+#            "descs": [
+#               { "flags": ["used", "indirect", "write"], "len": 4099327944,
+#                 "addr": 12055409292258155293 }
+#            ],
+#            "avail": {
+#               "idx": 1147,
+#               "flags": 0,
+#               "ring": 19
+#            },
+#            "used": {
+#               "idx": 280,
+#               "flags": 0
+#            }
+#    }
+#
+##
+
+{ 'command': 'x-query-virtio-queue-element',
+  'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
+  'returns': 'VirtioQueueElement',
+  'features': [ 'unstable' ] }
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v14 8/8] hmp: add virtio commands
  2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
                   ` (6 preceding siblings ...)
  2022-04-01 13:23 ` [PATCH v14 7/8] qmp: add QMP command x-query-virtio-queue-element Jonah Palmer
@ 2022-04-01 13:23 ` Jonah Palmer
  7 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-04-01 13:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: mst, qemu_oss, kraxel, si-wei.liu, joao.m.martins, eblake,
	qemu-block, david, armbru, arei.gonglei, marcandre.lureau,
	lvivier, thuth, michael.roth, groug, dgilbert, eric.auger,
	stefanha, boris.ostrovsky, kwolf, mathieu.poirier,
	raphael.norwitz, pbonzini

From: Laurent Vivier <lvivier@redhat.com>

This patch implements the HMP versions of the virtio QMP commands.

[Jonah: Fixed virtio hmp command output format (e.g. use PRI types).]

Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
 hmp-commands-info.hx  |  70 ++++++++++
 include/monitor/hmp.h |   5 +
 monitor/hmp-cmds.c    | 311 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 386 insertions(+)

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index adfa085a9b..8f204d9cb6 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -894,3 +894,73 @@ SRST
   ``info via``
     Show guest mos6522 VIA devices.
 ERST
+
+    {
+        .name      = "virtio",
+        .args_type = "",
+        .params    = "",
+        .help      = "List all available virtio devices",
+        .cmd       = hmp_virtio_query,
+        .flags     = "p",
+    },
+
+SRST
+  ``info virtio``
+    List all available virtio devices
+ERST
+
+    {
+        .name      = "virtio-status",
+        .args_type = "path:s",
+        .params    = "path",
+        .help      = "Display status of a given virtio device",
+        .cmd       = hmp_virtio_status,
+        .flags     = "p",
+    },
+
+SRST
+  ``info virtio-status`` *path*
+    Display status of a given virtio device
+ERST
+
+    {
+        .name      = "virtio-queue-status",
+        .args_type = "path:s,queue:i",
+        .params    = "path queue",
+        .help      = "Display status of a given virtio queue",
+        .cmd       = hmp_virtio_queue_status,
+        .flags     = "p",
+    },
+
+SRST
+  ``info virtio-queue-status`` *path* *queue*
+    Display status of a given virtio queue
+ERST
+
+    {
+        .name      = "virtio-vhost-queue-status",
+        .args_type = "path:s,queue:i",
+        .params    = "path queue",
+        .help      = "Display status of a given vhost queue",
+        .cmd       = hmp_vhost_queue_status,
+        .flags     = "p",
+    },
+
+SRST
+  ``info virtio-vhost-queue-status`` *path* *queue*
+    Display status of a given vhost queue
+ERST
+
+    {
+        .name       = "virtio-queue-element",
+        .args_type  = "path:s,queue:i,index:i?",
+        .params     = "path queue [index]",
+        .help       = "Display element of a given virtio queue",
+        .cmd        = hmp_virtio_queue_element,
+        .flags      = "p",
+    },
+
+SRST
+  ``info virtio-queue-element`` *path* *queue* [*index*]
+    Display element of a given virtio queue
+ERST
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 96d014826a..47446d8257 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -95,6 +95,11 @@ void hmp_qom_list(Monitor *mon, const QDict *qdict);
 void hmp_qom_get(Monitor *mon, const QDict *qdict);
 void hmp_qom_set(Monitor *mon, const QDict *qdict);
 void hmp_info_qom_tree(Monitor *mon, const QDict *dict);
+void hmp_virtio_query(Monitor *mon, const QDict *qdict);
+void hmp_virtio_status(Monitor *mon, const QDict *qdict);
+void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict);
+void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict);
+void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict);
 void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 634968498b..2689aca228 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -42,6 +42,8 @@
 #include "qapi/qapi-commands-run-state.h"
 #include "qapi/qapi-commands-tpm.h"
 #include "qapi/qapi-commands-ui.h"
+#include "qapi/qapi-commands-virtio.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "qapi/qapi-visit-net.h"
 #include "qapi/qapi-visit-migration.h"
 #include "qapi/qmp/qdict.h"
@@ -2221,3 +2223,312 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict)
     }
     hmp_handle_error(mon, err);
 }
+
+static void hmp_virtio_dump_protocols(Monitor *mon,
+                                      VhostDeviceProtocols *pcol)
+{
+    strList *pcol_list = pcol->protocols;
+    while (pcol_list) {
+        monitor_printf(mon, "%s", pcol_list->value);
+        pcol_list = pcol_list->next;
+        if (pcol_list != NULL) {
+            monitor_printf(mon, ", ");
+        }
+    }
+    monitor_printf(mon, "\n");
+    if (pcol->has_unknown_protocols) {
+        monitor_printf(mon, "  unknown-protocols(0x%016"PRIx64")\n",
+                       pcol->unknown_protocols);
+    }
+}
+
+static void hmp_virtio_dump_status(Monitor *mon,
+                                   VirtioDeviceStatus *status)
+{
+    strList *status_list = status->statuses;
+    while (status_list) {
+        monitor_printf(mon, "%s", status_list->value);
+        status_list = status_list->next;
+        if (status_list != NULL) {
+            monitor_printf(mon, ", ");
+        }
+    }
+    monitor_printf(mon, "\n");
+    if (status->has_unknown_statuses) {
+        monitor_printf(mon, "  unknown-statuses(0x%016"PRIx32")\n",
+                       status->unknown_statuses);
+    }
+}
+
+static void hmp_virtio_dump_features(Monitor *mon,
+                                     VirtioDeviceFeatures *features)
+{
+    strList *transport_list = features->transports;
+    while (transport_list) {
+        monitor_printf(mon, "%s", transport_list->value);
+        transport_list = transport_list->next;
+        if (transport_list != NULL) {
+            monitor_printf(mon, ", ");
+        }
+    }
+
+    monitor_printf(mon, "\n");
+    strList *list = features->dev_features;
+    if (list) {
+        monitor_printf(mon, "                    ");
+        while (list) {
+            monitor_printf(mon, "%s", list->value);
+            list = list->next;
+            if (list != NULL) {
+                monitor_printf(mon, ", ");
+            }
+        }
+        monitor_printf(mon, "\n");
+    }
+
+    if (features->has_unknown_dev_features) {
+        monitor_printf(mon, "  unknown-features(0x%016"PRIx64")\n",
+                       features->unknown_dev_features);
+    }
+}
+
+void hmp_virtio_query(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    VirtioInfoList *list = qmp_x_query_virtio(&err);
+    VirtioInfoList *node;
+
+    if (err != NULL) {
+        hmp_handle_error(mon, err);
+        return;
+    }
+
+    if (list == NULL) {
+        monitor_printf(mon, "No VirtIO devices\n");
+        return;
+    }
+
+    node = list;
+    while (node) {
+        monitor_printf(mon, "%s [%s]\n", node->value->path,
+                       node->value->name);
+        node = node->next;
+    }
+    qapi_free_VirtioInfoList(list);
+}
+
+void hmp_virtio_status(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    const char *path = qdict_get_try_str(qdict, "path");
+    VirtioStatus *s = qmp_x_query_virtio_status(path, &err);
+
+    if (err != NULL) {
+        hmp_handle_error(mon, err);
+        return;
+    }
+
+    monitor_printf(mon, "%s:\n", path);
+    monitor_printf(mon, "  device_name:             %s %s\n",
+                   s->name, s->has_vhost_dev ? "(vhost)" : "");
+    monitor_printf(mon, "  device_id:               %d\n", s->device_id);
+    monitor_printf(mon, "  vhost_started:           %s\n",
+                   s->vhost_started ? "true" : "false");
+    monitor_printf(mon, "  bus_name:                %s\n", s->bus_name);
+    monitor_printf(mon, "  broken:                  %s\n",
+                   s->broken ? "true" : "false");
+    monitor_printf(mon, "  disabled:                %s\n",
+                   s->disabled ? "true" : "false");
+    monitor_printf(mon, "  disable_legacy_check:    %s\n",
+                   s->disable_legacy_check ? "true" : "false");
+    monitor_printf(mon, "  started:                 %s\n",
+                   s->started ? "true" : "false");
+    monitor_printf(mon, "  use_started:             %s\n",
+                   s->use_started ? "true" : "false");
+    monitor_printf(mon, "  start_on_kick:           %s\n",
+                   s->start_on_kick ? "true" : "false");
+    monitor_printf(mon, "  use_guest_notifier_mask: %s\n",
+                   s->use_guest_notifier_mask ? "true" : "false");
+    monitor_printf(mon, "  vm_running:              %s\n",
+                   s->vm_running ? "true" : "false");
+    monitor_printf(mon, "  num_vqs:                 %"PRId64"\n", s->num_vqs);
+    monitor_printf(mon, "  queue_sel:               %d\n",
+                   s->queue_sel);
+    monitor_printf(mon, "  isr:                     %d\n", s->isr);
+    monitor_printf(mon, "  endianness:              %s\n",
+                   s->device_endian);
+    monitor_printf(mon, "  status: ");
+    hmp_virtio_dump_status(mon, s->status);
+    monitor_printf(mon, "  Guest features:   ");
+    hmp_virtio_dump_features(mon, s->guest_features);
+    monitor_printf(mon, "  Host features:    ");
+    hmp_virtio_dump_features(mon, s->host_features);
+    monitor_printf(mon, "  Backend features: ");
+    hmp_virtio_dump_features(mon, s->backend_features);
+
+    if (s->has_vhost_dev) {
+        monitor_printf(mon, "  VHost:\n");
+        monitor_printf(mon, "    nvqs:           %d\n",
+                       s->vhost_dev->nvqs);
+        monitor_printf(mon, "    vq_index:       %"PRId64"\n",
+                       s->vhost_dev->vq_index);
+        monitor_printf(mon, "    max_queues:     %"PRId64"\n",
+                       s->vhost_dev->max_queues);
+        monitor_printf(mon, "    n_mem_sections: %"PRId64"\n",
+                       s->vhost_dev->n_mem_sections);
+        monitor_printf(mon, "    n_tmp_sections: %"PRId64"\n",
+                       s->vhost_dev->n_tmp_sections);
+        monitor_printf(mon, "    backend_cap:    %"PRId64"\n",
+                       s->vhost_dev->backend_cap);
+        monitor_printf(mon, "    log_enabled:    %s\n",
+                       s->vhost_dev->log_enabled ? "true" : "false");
+        monitor_printf(mon, "    log_size:       %"PRId64"\n",
+                       s->vhost_dev->log_size);
+        monitor_printf(mon, "    Features:          ");
+        hmp_virtio_dump_features(mon, s->vhost_dev->features);
+        monitor_printf(mon, "    Acked features:    ");
+        hmp_virtio_dump_features(mon, s->vhost_dev->acked_features);
+        monitor_printf(mon, "    Backend features:  ");
+        hmp_virtio_dump_features(mon, s->vhost_dev->backend_features);
+        monitor_printf(mon, "    Protocol features: ");
+        hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features);
+    }
+
+    qapi_free_VirtioStatus(s);
+}
+
+void hmp_vhost_queue_status(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    const char *path = qdict_get_try_str(qdict, "path");
+    int queue = qdict_get_int(qdict, "queue");
+    VirtVhostQueueStatus *s =
+        qmp_x_query_virtio_vhost_queue_status(path, queue, &err);
+
+    if (err != NULL) {
+        hmp_handle_error(mon, err);
+        return;
+    }
+
+    monitor_printf(mon, "%s:\n", path);
+    monitor_printf(mon, "  device_name:          %s (vhost)\n",
+                   s->name);
+    monitor_printf(mon, "  kick:                 %"PRId64"\n", s->kick);
+    monitor_printf(mon, "  call:                 %"PRId64"\n", s->call);
+    monitor_printf(mon, "  VRing:\n");
+    monitor_printf(mon, "    num:         %"PRId64"\n", s->num);
+    monitor_printf(mon, "    desc:        0x%016"PRIx64"\n", s->desc);
+    monitor_printf(mon, "    desc_phys:   0x%016"PRIx64"\n",
+                   s->desc_phys);
+    monitor_printf(mon, "    desc_size:   %"PRId32"\n", s->desc_size);
+    monitor_printf(mon, "    avail:       0x%016"PRIx64"\n", s->avail);
+    monitor_printf(mon, "    avail_phys:  0x%016"PRIx64"\n",
+                   s->avail_phys);
+    monitor_printf(mon, "    avail_size:  %"PRId32"\n", s->avail_size);
+    monitor_printf(mon, "    used:        0x%016"PRIx64"\n", s->used);
+    monitor_printf(mon, "    used_phys:   0x%016"PRIx64"\n",
+                   s->used_phys);
+    monitor_printf(mon, "    used_size:   %"PRId32"\n", s->used_size);
+
+    qapi_free_VirtVhostQueueStatus(s);
+}
+
+void hmp_virtio_queue_status(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    const char *path = qdict_get_try_str(qdict, "path");
+    int queue = qdict_get_int(qdict, "queue");
+    VirtQueueStatus *s = qmp_x_query_virtio_queue_status(path, queue, &err);
+
+    if (err != NULL) {
+        hmp_handle_error(mon, err);
+        return;
+    }
+
+    monitor_printf(mon, "%s:\n", path);
+    monitor_printf(mon, "  device_name:          %s\n", s->name);
+    monitor_printf(mon, "  queue_index:          %d\n", s->queue_index);
+    monitor_printf(mon, "  inuse:                %d\n", s->inuse);
+    monitor_printf(mon, "  used_idx:             %d\n", s->used_idx);
+    monitor_printf(mon, "  signalled_used:       %d\n",
+                   s->signalled_used);
+    monitor_printf(mon, "  signalled_used_valid: %s\n",
+                   s->signalled_used_valid ? "true" : "false");
+    if (s->has_last_avail_idx) {
+        monitor_printf(mon, "  last_avail_idx:       %d\n",
+                       s->last_avail_idx);
+    }
+    if (s->has_shadow_avail_idx) {
+        monitor_printf(mon, "  shadow_avail_idx:     %d\n",
+                       s->shadow_avail_idx);
+    }
+    monitor_printf(mon, "  VRing:\n");
+    monitor_printf(mon, "    num:          %"PRId32"\n", s->vring_num);
+    monitor_printf(mon, "    num_default:  %"PRId32"\n",
+                   s->vring_num_default);
+    monitor_printf(mon, "    align:        %"PRId32"\n",
+                   s->vring_align);
+    monitor_printf(mon, "    desc:         0x%016"PRIx64"\n",
+                   s->vring_desc);
+    monitor_printf(mon, "    avail:        0x%016"PRIx64"\n",
+                   s->vring_avail);
+    monitor_printf(mon, "    used:         0x%016"PRIx64"\n",
+                   s->vring_used);
+
+    qapi_free_VirtQueueStatus(s);
+}
+
+void hmp_virtio_queue_element(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+    const char *path = qdict_get_try_str(qdict, "path");
+    int queue = qdict_get_int(qdict, "queue");
+    int index = qdict_get_try_int(qdict, "index", -1);
+    VirtioQueueElement *e;
+    VirtioRingDescList *list;
+
+    e = qmp_x_query_virtio_queue_element(path, queue, index != -1,
+                                         index, &err);
+    if (err != NULL) {
+        hmp_handle_error(mon, err);
+        return;
+    }
+
+    monitor_printf(mon, "%s:\n", path);
+    monitor_printf(mon, "  device_name: %s\n", e->name);
+    monitor_printf(mon, "  index:       %d\n", e->index);
+    monitor_printf(mon, "  desc:\n");
+    monitor_printf(mon, "    descs:   ");
+
+    list = e->descs;
+    while (list) {
+        monitor_printf(mon, "addr 0x%"PRIx64" len %d", list->value->addr,
+                       list->value->len);
+        if (list->value->flags) {
+            strList *flag = list->value->flags;
+            monitor_printf(mon, " (");
+            while (flag) {
+                monitor_printf(mon, "%s", flag->value);
+                flag = flag->next;
+                if (flag) {
+                    monitor_printf(mon, ", ");
+                }
+            }
+            monitor_printf(mon, ")");
+        }
+        list = list->next;
+        if (list) {
+            monitor_printf(mon, ", ");
+        }
+    }
+    monitor_printf(mon, "\n");
+    monitor_printf(mon, "  avail:\n");
+    monitor_printf(mon, "    flags: %d\n", e->avail->flags);
+    monitor_printf(mon, "    idx:   %d\n", e->avail->idx);
+    monitor_printf(mon, "    ring:  %d\n", e->avail->ring);
+    monitor_printf(mon, "  used:\n");
+    monitor_printf(mon, "    flags: %d\n", e->used->flags);
+    monitor_printf(mon, "    idx:   %d\n", e->used->idx);
+
+    qapi_free_VirtioQueueElement(e);
+}
-- 
2.35.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 1/8] virtio: drop name parameter for virtio_init()
  2022-04-01 13:23 ` [PATCH v14 1/8] virtio: drop name parameter for virtio_init() Jonah Palmer
@ 2022-04-21 17:47   ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 15+ messages in thread
From: Dr. David Alan Gilbert @ 2022-04-21 17:47 UTC (permalink / raw)
  To: Jonah Palmer, mst, stefanha
  Cc: lvivier, kwolf, thuth, mathieu.poirier, qemu-block, david,
	armbru, pbonzini, qemu_oss, qemu-devel, groug, eric.auger,
	arei.gonglei, kraxel, michael.roth, si-wei.liu, marcandre.lureau,
	joao.m.martins, raphael.norwitz, eblake, boris.ostrovsky

* Jonah Palmer (jonah.palmer@oracle.com) wrote:
> This patch drops the name parameter for the virtio_init function.
> 
> The pair between the numeric device ID and the string device ID
> (name) of a virtio device already exists, but not in a way that
> lets us map between them.
> 
> This patch lets us do this and removes the need for the name
> parameter in the virtio_init function.
> 
> Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>

So this looks OK to me, but is really a question for the virtio folk
rather than hmp/qmp that a lot of the rest of this series does.

Dave

> ---
>  hw/9pfs/virtio-9p-device.c             |  2 +-
>  hw/block/vhost-user-blk.c              |  2 +-
>  hw/block/virtio-blk.c                  |  2 +-
>  hw/char/virtio-serial-bus.c            |  3 +-
>  hw/display/virtio-gpu-base.c           |  2 +-
>  hw/input/virtio-input.c                |  3 +-
>  hw/net/virtio-net.c                    |  2 +-
>  hw/scsi/virtio-scsi.c                  |  3 +-
>  hw/virtio/vhost-user-fs.c              |  3 +-
>  hw/virtio/vhost-user-i2c.c             |  7 +---
>  hw/virtio/vhost-user-rng.c             |  2 +-
>  hw/virtio/vhost-user-vsock.c           |  2 +-
>  hw/virtio/vhost-vsock-common.c         |  5 +--
>  hw/virtio/vhost-vsock.c                |  2 +-
>  hw/virtio/virtio-balloon.c             |  3 +-
>  hw/virtio/virtio-crypto.c              |  2 +-
>  hw/virtio/virtio-iommu.c               |  3 +-
>  hw/virtio/virtio-mem.c                 |  3 +-
>  hw/virtio/virtio-pmem.c                |  3 +-
>  hw/virtio/virtio-rng.c                 |  2 +-
>  hw/virtio/virtio.c                     | 55 ++++++++++++++++++++++++--
>  include/hw/virtio/vhost-vsock-common.h |  2 +-
>  include/hw/virtio/virtio-gpu.h         |  3 +-
>  include/hw/virtio/virtio.h             |  4 +-
>  24 files changed, 77 insertions(+), 43 deletions(-)
> 
> diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
> index 54ee93b71f..5f522e68e9 100644
> --- a/hw/9pfs/virtio-9p-device.c
> +++ b/hw/9pfs/virtio-9p-device.c
> @@ -216,7 +216,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
>      }
>  
>      v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
> -    virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
> +    virtio_init(vdev, VIRTIO_ID_9P, v->config_size);
>      v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
>  }
>  
> diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
> index 1a42ae9187..e8cb170032 100644
> --- a/hw/block/vhost-user-blk.c
> +++ b/hw/block/vhost-user-blk.c
> @@ -491,7 +491,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
> +    virtio_init(vdev, VIRTIO_ID_BLOCK,
>                  sizeof(struct virtio_blk_config));
>  
>      s->virtqs = g_new(VirtQueue *, s->num_queues);
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index 540c38f829..27c71ad316 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -1206,7 +1206,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
>  
>      virtio_blk_set_config_size(s, s->host_features);
>  
> -    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, s->config_size);
> +    virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
>  
>      s->blk = conf->conf.blk;
>      s->rq = NULL;
> diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
> index 6048d408b8..7d4601cb5d 100644
> --- a/hw/char/virtio-serial-bus.c
> +++ b/hw/char/virtio-serial-bus.c
> @@ -1044,8 +1044,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
>                              VIRTIO_CONSOLE_F_EMERG_WRITE)) {
>          config_size = offsetof(struct virtio_console_config, emerg_wr);
>      }
> -    virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
> -                config_size);
> +    virtio_init(vdev, VIRTIO_ID_CONSOLE, config_size);
>  
>      /* Spawn a new virtio-serial bus on which the ports will ride as devices */
>      qbus_init(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
> diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
> index fff0fb4a82..8ba5da4312 100644
> --- a/hw/display/virtio-gpu-base.c
> +++ b/hw/display/virtio-gpu-base.c
> @@ -173,7 +173,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
>      }
>  
>      g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs);
> -    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
> +    virtio_init(VIRTIO_DEVICE(g), VIRTIO_ID_GPU,
>                  sizeof(struct virtio_gpu_config));
>  
>      if (virtio_gpu_virgl_enabled(g->conf)) {
> diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
> index 54bcb46c74..5b5398b3ca 100644
> --- a/hw/input/virtio-input.c
> +++ b/hw/input/virtio-input.c
> @@ -257,8 +257,7 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp)
>      vinput->cfg_size += 8;
>      assert(vinput->cfg_size <= sizeof(virtio_input_config));
>  
> -    virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
> -                vinput->cfg_size);
> +    virtio_init(vdev, VIRTIO_ID_INPUT, vinput->cfg_size);
>      vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
>      vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
>  }
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 1067e72b39..6fbcfd7cb7 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -3392,7 +3392,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
>      }
>  
>      virtio_net_set_config_size(n, n->host_features);
> -    virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
> +    virtio_init(vdev, VIRTIO_ID_NET, n->config_size);
>  
>      /*
>       * We set a lower limit on RX queue size to what it always was.
> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 34a968ecfb..2a6141d081 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -972,8 +972,7 @@ void virtio_scsi_common_realize(DeviceState *dev,
>      VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
>      int i;
>  
> -    virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
> -                sizeof(VirtIOSCSIConfig));
> +    virtio_init(vdev, VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig));
>  
>      if (s->conf.num_queues == VIRTIO_SCSI_AUTO_NUM_QUEUES) {
>          s->conf.num_queues = 1;
> diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
> index c595957983..b875640147 100644
> --- a/hw/virtio/vhost-user-fs.c
> +++ b/hw/virtio/vhost-user-fs.c
> @@ -219,8 +219,7 @@ static void vuf_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS,
> -                sizeof(struct virtio_fs_config));
> +    virtio_init(vdev, VIRTIO_ID_FS, sizeof(struct virtio_fs_config));
>  
>      /* Hiprio queue */
>      fs->hiprio_vq = virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
> diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
> index 42c7f6d9e5..6020eee093 100644
> --- a/hw/virtio/vhost-user-i2c.c
> +++ b/hw/virtio/vhost-user-i2c.c
> @@ -14,11 +14,6 @@
>  #include "qemu/error-report.h"
>  #include "standard-headers/linux/virtio_ids.h"
>  
> -/* Remove this once the header is updated in Linux kernel */
> -#ifndef VIRTIO_ID_I2C_ADAPTER
> -#define VIRTIO_ID_I2C_ADAPTER                34
> -#endif
> -
>  static const int feature_bits[] = {
>      VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
>      VHOST_INVALID_FEATURE_BIT
> @@ -227,7 +222,7 @@ static void vu_i2c_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "vhost-user-i2c", VIRTIO_ID_I2C_ADAPTER, 0);
> +    virtio_init(vdev, VIRTIO_ID_I2C_ADAPTER, 0);
>  
>      i2c->vhost_dev.nvqs = 1;
>      i2c->vq = virtio_add_queue(vdev, 4, vu_i2c_handle_output);
> diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c
> index 209ee5bf9a..08bccba9dc 100644
> --- a/hw/virtio/vhost-user-rng.c
> +++ b/hw/virtio/vhost-user-rng.c
> @@ -203,7 +203,7 @@ static void vu_rng_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "vhost-user-rng", VIRTIO_ID_RNG, 0);
> +    virtio_init(vdev, VIRTIO_ID_RNG, 0);
>  
>      rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output);
>      if (!rng->req_vq) {
> diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c
> index 52bd682c34..0f8ff99f85 100644
> --- a/hw/virtio/vhost-user-vsock.c
> +++ b/hw/virtio/vhost-user-vsock.c
> @@ -107,7 +107,7 @@ static void vuv_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    vhost_vsock_common_realize(vdev, "vhost-user-vsock");
> +    vhost_vsock_common_realize(vdev);
>  
>      vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops);
>  
> diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
> index ed706681ac..ad5c8ff5d5 100644
> --- a/hw/virtio/vhost-vsock-common.c
> +++ b/hw/virtio/vhost-vsock-common.c
> @@ -224,12 +224,11 @@ int vhost_vsock_common_post_load(void *opaque, int version_id)
>      return 0;
>  }
>  
> -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name)
> +void vhost_vsock_common_realize(VirtIODevice *vdev)
>  {
>      VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
>  
> -    virtio_init(vdev, name, VIRTIO_ID_VSOCK,
> -                sizeof(struct virtio_vsock_config));
> +    virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config));
>  
>      /* Receive and transmit queues belong to vhost */
>      vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
> diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c
> index 433d42d897..696635b1f7 100644
> --- a/hw/virtio/vhost-vsock.c
> +++ b/hw/virtio/vhost-vsock.c
> @@ -166,7 +166,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp)
>          qemu_set_nonblock(vhostfd);
>      }
>  
> -    vhost_vsock_common_realize(vdev, "vhost-vsock");
> +    vhost_vsock_common_realize(vdev);
>  
>      ret = vhost_dev_init(&vvc->vhost_dev, (void *)(uintptr_t)vhostfd,
>                           VHOST_BACKEND_TYPE_KERNEL, 0, errp);
> diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
> index 163d244eb4..193ff5261c 100644
> --- a/hw/virtio/virtio-balloon.c
> +++ b/hw/virtio/virtio-balloon.c
> @@ -889,8 +889,7 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
>      VirtIOBalloon *s = VIRTIO_BALLOON(dev);
>      int ret;
>  
> -    virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON,
> -                virtio_balloon_config_size(s));
> +    virtio_init(vdev, VIRTIO_ID_BALLOON, virtio_balloon_config_size(s));
>  
>      ret = qemu_add_balloon_handler(virtio_balloon_to_target,
>                                     virtio_balloon_stat, s);
> diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
> index dcd80b904d..0a1f3dfdbe 100644
> --- a/hw/virtio/virtio-crypto.c
> +++ b/hw/virtio/virtio-crypto.c
> @@ -810,7 +810,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "virtio-crypto", VIRTIO_ID_CRYPTO, vcrypto->config_size);
> +    virtio_init(vdev, VIRTIO_ID_CRYPTO, vcrypto->config_size);
>      vcrypto->curr_queues = 1;
>      vcrypto->vqs = g_new0(VirtIOCryptoQueue, vcrypto->max_queues);
>      for (i = 0; i < vcrypto->max_queues; i++) {
> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
> index 664cbd9583..4ed5bb16ba 100644
> --- a/hw/virtio/virtio-iommu.c
> +++ b/hw/virtio/virtio-iommu.c
> @@ -1033,8 +1033,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
>      VirtIODevice *vdev = VIRTIO_DEVICE(dev);
>      VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
>  
> -    virtio_init(vdev, "virtio-iommu", VIRTIO_ID_IOMMU,
> -                sizeof(struct virtio_iommu_config));
> +    virtio_init(vdev, VIRTIO_ID_IOMMU, sizeof(struct virtio_iommu_config));
>  
>      memset(s->iommu_pcibus_by_bus_num, 0, sizeof(s->iommu_pcibus_by_bus_num));
>  
> diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
> index f55dcf61f2..465a996214 100644
> --- a/hw/virtio/virtio-mem.c
> +++ b/hw/virtio/virtio-mem.c
> @@ -868,8 +868,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
>                          vmem->block_size;
>      vmem->bitmap = bitmap_new(vmem->bitmap_size);
>  
> -    virtio_init(vdev, TYPE_VIRTIO_MEM, VIRTIO_ID_MEM,
> -                sizeof(struct virtio_mem_config));
> +    virtio_init(vdev, VIRTIO_ID_MEM, sizeof(struct virtio_mem_config));
>      vmem->vq = virtio_add_queue(vdev, 128, virtio_mem_handle_request);
>  
>      host_memory_backend_set_mapped(vmem->memdev, true);
> diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
> index 5419dca75e..ec74890676 100644
> --- a/hw/virtio/virtio-pmem.c
> +++ b/hw/virtio/virtio-pmem.c
> @@ -123,8 +123,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp)
>      }
>  
>      host_memory_backend_set_mapped(pmem->memdev, true);
> -    virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM,
> -                sizeof(struct virtio_pmem_config));
> +    virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config));
>      pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush);
>  }
>  
> diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
> index cc8e9f775d..7e12fc03bf 100644
> --- a/hw/virtio/virtio-rng.c
> +++ b/hw/virtio/virtio-rng.c
> @@ -215,7 +215,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
> +    virtio_init(vdev, VIRTIO_ID_RNG, 0);
>  
>      vrng->vq = virtio_add_queue(vdev, 8, handle_input);
>      vrng->quota_remaining = vrng->conf.max_bytes;
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 9d637e043e..cbb4920f49 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -132,6 +132,56 @@ struct VirtQueue
>      QLIST_ENTRY(VirtQueue) node;
>  };
>  
> +const char *virtio_device_names[] = {
> +    [VIRTIO_ID_NET] = "virtio-net",
> +    [VIRTIO_ID_BLOCK] = "virtio-blk",
> +    [VIRTIO_ID_CONSOLE] = "virtio-serial",
> +    [VIRTIO_ID_RNG] = "virtio-rng",
> +    [VIRTIO_ID_BALLOON] = "virtio-balloon",
> +    [VIRTIO_ID_IOMEM] = "virtio-iomem",
> +    [VIRTIO_ID_RPMSG] = "virtio-rpmsg",
> +    [VIRTIO_ID_SCSI] = "virtio-scsi",
> +    [VIRTIO_ID_9P] = "virtio-9p",
> +    [VIRTIO_ID_MAC80211_WLAN] = "virtio-mac-wlan",
> +    [VIRTIO_ID_RPROC_SERIAL] = "virtio-rproc-serial",
> +    [VIRTIO_ID_CAIF] = "virtio-caif",
> +    [VIRTIO_ID_MEMORY_BALLOON] = "virtio-mem-balloon",
> +    [VIRTIO_ID_GPU] = "virtio-gpu",
> +    [VIRTIO_ID_CLOCK] = "virtio-clk",
> +    [VIRTIO_ID_INPUT] = "virtio-input",
> +    [VIRTIO_ID_VSOCK] = "vhost-vsock",
> +    [VIRTIO_ID_CRYPTO] = "virtio-crypto",
> +    [VIRTIO_ID_SIGNAL_DIST] = "virtio-signal",
> +    [VIRTIO_ID_PSTORE] = "virtio-pstore",
> +    [VIRTIO_ID_IOMMU] = "virtio-iommu",
> +    [VIRTIO_ID_MEM] = "virtio-mem",
> +    [VIRTIO_ID_SOUND] = "virtio-sound",
> +    [VIRTIO_ID_FS] = "virtio-user-fs",
> +    [VIRTIO_ID_PMEM] = "virtio-pmem",
> +    [VIRTIO_ID_RPMB] = "virtio-rpmb",
> +    [VIRTIO_ID_MAC80211_HWSIM] = "virtio-mac-hwsim",
> +    [VIRTIO_ID_VIDEO_ENCODER] = "virtio-vid-encoder",
> +    [VIRTIO_ID_VIDEO_DECODER] = "virtio-vid-decoder",
> +    [VIRTIO_ID_SCMI] = "virtio-scmi",
> +    [VIRTIO_ID_NITRO_SEC_MOD] = "virtio-nitro-sec-mod",
> +    [VIRTIO_ID_I2C_ADAPTER] = "vhost-user-i2c",
> +    [VIRTIO_ID_WATCHDOG] = "virtio-watchdog",
> +    [VIRTIO_ID_CAN] = "virtio-can",
> +    [VIRTIO_ID_DMABUF] = "virtio-dmabuf",
> +    [VIRTIO_ID_PARAM_SERV] = "virtio-param-serv",
> +    [VIRTIO_ID_AUDIO_POLICY] = "virtio-audio-pol",
> +    [VIRTIO_ID_BT] = "virtio-bluetooth",
> +    [VIRTIO_ID_GPIO] = "virtio-gpio"
> +};
> +
> +static const char *virtio_id_to_name(uint16_t device_id)
> +{
> +    assert(device_id < G_N_ELEMENTS(virtio_device_names));
> +    const char *name = virtio_device_names[device_id];
> +    assert(name != NULL);
> +    return name;
> +}
> +
>  /* Called within call_rcu().  */
>  static void virtio_free_region_cache(VRingMemoryRegionCaches *caches)
>  {
> @@ -3207,8 +3257,7 @@ void virtio_instance_init_common(Object *proxy_obj, void *data,
>      qdev_alias_all_properties(vdev, proxy_obj);
>  }
>  
> -void virtio_init(VirtIODevice *vdev, const char *name,
> -                 uint16_t device_id, size_t config_size)
> +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size)
>  {
>      BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
>      VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
> @@ -3237,7 +3286,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
>          vdev->vq[i].host_notifier_enabled = false;
>      }
>  
> -    vdev->name = name;
> +    vdev->name = virtio_id_to_name(device_id);
>      vdev->config_len = config_size;
>      if (vdev->config_len) {
>          vdev->config = g_malloc0(config_size);
> diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h
> index d8b565b4da..076b7ab779 100644
> --- a/include/hw/virtio/vhost-vsock-common.h
> +++ b/include/hw/virtio/vhost-vsock-common.h
> @@ -44,7 +44,7 @@ int vhost_vsock_common_start(VirtIODevice *vdev);
>  void vhost_vsock_common_stop(VirtIODevice *vdev);
>  int vhost_vsock_common_pre_save(void *opaque);
>  int vhost_vsock_common_post_load(void *opaque, int version_id);
> -void vhost_vsock_common_realize(VirtIODevice *vdev, const char *name);
> +void vhost_vsock_common_realize(VirtIODevice *vdev);
>  void vhost_vsock_common_unrealize(VirtIODevice *vdev);
>  uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features,
>                                           Error **errp);
> diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
> index 2179b75703..afff9e158e 100644
> --- a/include/hw/virtio/virtio-gpu.h
> +++ b/include/hw/virtio/virtio-gpu.h
> @@ -22,6 +22,7 @@
>  #include "sysemu/vhost-user-backend.h"
>  
>  #include "standard-headers/linux/virtio_gpu.h"
> +#include "standard-headers/linux/virtio_ids.h"
>  #include "qom/object.h"
>  
>  #define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base"
> @@ -37,8 +38,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL)
>  #define TYPE_VHOST_USER_GPU "vhost-user-gpu"
>  OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU)
>  
> -#define VIRTIO_ID_GPU 16
> -
>  struct virtio_gpu_simple_resource {
>      uint32_t resource_id;
>      uint32_t width;
> diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
> index b31c4507f5..5d774684b1 100644
> --- a/include/hw/virtio/virtio.h
> +++ b/include/hw/virtio/virtio.h
> @@ -165,8 +165,8 @@ struct VirtioDeviceClass {
>  void virtio_instance_init_common(Object *proxy_obj, void *data,
>                                   size_t vdev_size, const char *vdev_name);
>  
> -void virtio_init(VirtIODevice *vdev, const char *name,
> -                         uint16_t device_id, size_t config_size);
> +void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size);
> +
>  void virtio_cleanup(VirtIODevice *vdev);
>  
>  void virtio_error(VirtIODevice *vdev, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
> -- 
> 2.35.1
> 
-- 
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-04-01 13:23 ` [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status Jonah Palmer
@ 2022-05-16 20:26   ` Michael S. Tsirkin
  2022-05-19  6:30     ` Jonah Palmer
  0 siblings, 1 reply; 15+ messages in thread
From: Michael S. Tsirkin @ 2022-05-16 20:26 UTC (permalink / raw)
  To: Jonah Palmer
  Cc: qemu-devel, boris.ostrovsky, si-wei.liu, joao.m.martins,
	qemu-block, groug, qemu_oss, stefanha, lvivier, mathieu.poirier,
	arei.gonglei, eric.auger, kraxel, dgilbert, david,
	marcandre.lureau, armbru, michael.roth, eblake, thuth, pbonzini,
	kwolf, raphael.norwitz

On Fri, Apr 01, 2022 at 09:23:22AM -0400, Jonah Palmer wrote:
> From: Laurent Vivier <lvivier@redhat.com>
> 
> Display feature names instead of bitmaps for host, guest, and
> backend for VirtIODevices.
> 
> Display status names instead of bitmaps for VirtIODevices.
> 
> Display feature names instead of bitmaps for backend, protocol,
> acked, and features (hdev->features) for vhost devices.
> 
> Decode features according to device ID. Decode statuses
> according to configuration status bitmap (config_status_map).
> Decode vhost user protocol features according to vhost user
> protocol bitmap (vhost_user_protocol_map).
> 
> Transport features are on the first line. Undecoded bits (if
> any) are stored in a separate field.
> 
> Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>


So this has several problems that I missed previously.
First, sign off from poster is missing.



> ---
>  hw/block/virtio-blk.c          |  29 ++++
>  hw/char/virtio-serial-bus.c    |  11 ++
>  hw/display/virtio-gpu.c        |  18 ++
>  hw/input/virtio-input.c        |  10 ++
>  hw/net/virtio-net.c            |  47 +++++
>  hw/scsi/virtio-scsi.c          |  17 ++
>  hw/virtio/vhost-user-fs.c      |  10 ++
>  hw/virtio/vhost-user-i2c.c     |  14 ++
>  hw/virtio/vhost-vsock-common.c |  10 ++
>  hw/virtio/virtio-balloon.c     |  14 ++
>  hw/virtio/virtio-crypto.c      |  10 ++
>  hw/virtio/virtio-iommu.c       |  14 ++
>  hw/virtio/virtio-mem.c         |  11 ++
>  hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
>  include/hw/virtio/vhost.h      |   3 +
>  include/hw/virtio/virtio.h     |  19 +++
>  qapi/virtio.json               | 156 ++++++++++++++---
>  17 files changed, 667 insertions(+), 28 deletions(-)
> 
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index 27c71ad316..f104603040 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -13,6 +13,7 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/iov.h"
>  #include "qemu/module.h"
>  #include "qemu/error-report.h"
> @@ -33,10 +34,38 @@
>  #include "migration/qemu-file-types.h"
>  #include "hw/virtio/virtio-access.h"
>  #include "qemu/coroutine.h"
> +#include "standard-headers/linux/vhost_types.h"
>  
>  /* Config size before the discard support (hide associated config fields) */
>  #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
>                                       max_discard_sectors)
> +
> +qmp_virtio_feature_map_t blk_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_BLK_F_##name, #name }
> +    FEATURE_ENTRY(SIZE_MAX),
> +    FEATURE_ENTRY(SEG_MAX),
> +    FEATURE_ENTRY(GEOMETRY),
> +    FEATURE_ENTRY(RO),
> +    FEATURE_ENTRY(BLK_SIZE),
> +    FEATURE_ENTRY(TOPOLOGY),
> +    FEATURE_ENTRY(MQ),
> +    FEATURE_ENTRY(DISCARD),
> +    FEATURE_ENTRY(WRITE_ZEROES),
> +#ifndef VIRTIO_BLK_NO_LEGACY
> +    FEATURE_ENTRY(BARRIER),
> +    FEATURE_ENTRY(SCSI),
> +    FEATURE_ENTRY(FLUSH),
> +    FEATURE_ENTRY(CONFIG_WCE),
> +#endif /* !VIRTIO_BLK_NO_LEGACY */
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  /*
>   * Starting from the discard feature, we can use this array to properly
>   * set the config size depending on the features enabled.
> diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
> index 7d4601cb5d..fbb31a2b16 100644
> --- a/hw/char/virtio-serial-bus.c
> +++ b/hw/char/virtio-serial-bus.c
> @@ -20,6 +20,7 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/iov.h"
>  #include "qemu/main-loop.h"
>  #include "qemu/module.h"
> @@ -32,6 +33,16 @@
>  #include "hw/virtio/virtio-serial.h"
>  #include "hw/virtio/virtio-access.h"
>  
> +qmp_virtio_feature_map_t serial_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_CONSOLE_F_##name, #name }
> +    FEATURE_ENTRY(SIZE),
> +    FEATURE_ENTRY(MULTIPORT),
> +    FEATURE_ENTRY(EMERG_WRITE),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  static struct VirtIOSerialDevices {
>      QLIST_HEAD(, VirtIOSerial) devices;
>  } vserdevices;
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 529b5246b2..0bd5dc6232 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -29,10 +29,28 @@
>  #include "qemu/log.h"
>  #include "qemu/module.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/error-report.h"
> +#include "standard-headers/linux/vhost_types.h"
>  
>  #define VIRTIO_GPU_VM_VERSION 1
>  
> +qmp_virtio_feature_map_t gpu_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_GPU_F_##name, #name }
> +    FEATURE_ENTRY(VIRGL),
> +    FEATURE_ENTRY(EDID),
> +    FEATURE_ENTRY(RESOURCE_UUID),
> +    FEATURE_ENTRY(RESOURCE_BLOB),
> +    FEATURE_ENTRY(CONTEXT_INIT),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +


Now I had some experience with this, the trick makes it
harder to find where is a given macro used, and at the same
time saves very little. Also should a macro name change, we
do not want the name to change.
Let's just keep it simple please.
Plain array of macros and strings with no tricks.


>  static struct virtio_gpu_simple_resource*
>  virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
>  static struct virtio_gpu_simple_resource *
> diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
> index 5b5398b3ca..fe0ed6d5b4 100644
> --- a/hw/input/virtio-input.c
> +++ b/hw/input/virtio-input.c
> @@ -6,6 +6,7 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/iov.h"
>  #include "qemu/module.h"
>  #include "trace.h"
> @@ -14,10 +15,19 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/virtio/virtio-input.h"
>  
> +#include "standard-headers/linux/vhost_types.h"
>  #include "standard-headers/linux/input.h"
>  
>  #define VIRTIO_INPUT_VM_VERSION 1
>  
> +qmp_virtio_feature_map_t input_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  /* ----------------------------------------------------------------- */
>  
>  void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 027ce40c6f..9356958fb6 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -35,9 +35,11 @@
>  #include "hw/qdev-properties.h"
>  #include "qapi/qapi-types-migration.h"
>  #include "qapi/qapi-events-migration.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "hw/virtio/virtio-access.h"
>  #include "migration/misc.h"
>  #include "standard-headers/linux/ethtool.h"
> +#include "standard-headers/linux/vhost_types.h"
>  #include "sysemu/sysemu.h"
>  #include "trace.h"
>  #include "monitor/qdev.h"
> @@ -90,6 +92,51 @@
>                                           VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
>                                           VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
>  
> +qmp_virtio_feature_map_t net_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_NET_F_##name, #name }
> +    FEATURE_ENTRY(CSUM),
> +    FEATURE_ENTRY(GUEST_CSUM),
> +    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
> +    FEATURE_ENTRY(MTU),
> +    FEATURE_ENTRY(MAC),
> +    FEATURE_ENTRY(GUEST_TSO4),
> +    FEATURE_ENTRY(GUEST_TSO6),
> +    FEATURE_ENTRY(GUEST_ECN),
> +    FEATURE_ENTRY(GUEST_UFO),
> +    FEATURE_ENTRY(HOST_TSO4),
> +    FEATURE_ENTRY(HOST_TSO6),
> +    FEATURE_ENTRY(HOST_ECN),
> +    FEATURE_ENTRY(HOST_UFO),
> +    FEATURE_ENTRY(MRG_RXBUF),
> +    FEATURE_ENTRY(STATUS),
> +    FEATURE_ENTRY(CTRL_VQ),
> +    FEATURE_ENTRY(CTRL_RX),
> +    FEATURE_ENTRY(CTRL_VLAN),
> +    FEATURE_ENTRY(CTRL_RX_EXTRA),
> +    FEATURE_ENTRY(GUEST_ANNOUNCE),
> +    FEATURE_ENTRY(MQ),
> +    FEATURE_ENTRY(CTRL_MAC_ADDR),
> +    FEATURE_ENTRY(HASH_REPORT),
> +    FEATURE_ENTRY(RSS),
> +    FEATURE_ENTRY(RSC_EXT),
> +    FEATURE_ENTRY(STANDBY),
> +    FEATURE_ENTRY(SPEED_DUPLEX),
> +#ifndef VIRTIO_NET_NO_LEGACY
> +    FEATURE_ENTRY(GSO),
> +#endif /* VIRTIO_NET_NO_LEGACY */
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_NET_F_##name, #name }
> +    FEATURE_ENTRY(VIRTIO_NET_HDR),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  static const VirtIOFeature feature_sizes[] = {
>      {.flags = 1ULL << VIRTIO_NET_F_MAC,
>       .end = endof(struct virtio_net_config, mac)},
> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index 2a6141d081..9ca8faa40e 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -15,7 +15,9 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/vhost_types.h"
>  #include "hw/virtio/virtio-scsi.h"
>  #include "migration/qemu-file-types.h"
>  #include "qemu/error-report.h"
> @@ -29,6 +31,21 @@
>  #include "hw/virtio/virtio-access.h"
>  #include "trace.h"
>  
> +qmp_virtio_feature_map_t scsi_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_SCSI_F_##name, #name }
> +    FEATURE_ENTRY(INOUT),
> +    FEATURE_ENTRY(HOTPLUG),
> +    FEATURE_ENTRY(CHANGE),
> +    FEATURE_ENTRY(T10_PI),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  static inline int virtio_scsi_get_lun(uint8_t *lun)
>  {
>      return ((lun[2] << 8) | lun[3]) & 0x3FFF;
> diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
> index e513e4fdda..096cc07c44 100644
> --- a/hw/virtio/vhost-user-fs.c
> +++ b/hw/virtio/vhost-user-fs.c
> @@ -15,6 +15,7 @@
>  #include <sys/ioctl.h>
>  #include "standard-headers/linux/virtio_fs.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/qdev-properties-system.h"
>  #include "hw/virtio/virtio-bus.h"
> @@ -23,6 +24,15 @@
>  #include "hw/virtio/vhost-user-fs.h"
>  #include "monitor/monitor.h"
>  #include "sysemu/sysemu.h"
> +#include "standard-headers/linux/vhost_types.h"
> +
> +qmp_virtio_feature_map_t fs_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
>  
>  static const int user_feature_bits[] = {
>      VIRTIO_F_VERSION_1,
> diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
> index 6020eee093..931ec9836c 100644
> --- a/hw/virtio/vhost-user-i2c.c
> +++ b/hw/virtio/vhost-user-i2c.c
> @@ -8,11 +8,25 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/virtio/virtio-bus.h"
>  #include "hw/virtio/vhost-user-i2c.h"
>  #include "qemu/error-report.h"
>  #include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/vhost_types.h"
> +
> +qmp_virtio_feature_map_t i2c_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_I2C_F_##name, #name }
> +    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
>  
>  static const int feature_bits[] = {
>      VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
> diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
> index 7394818e00..b03f94d8f8 100644
> --- a/hw/virtio/vhost-vsock-common.c
> +++ b/hw/virtio/vhost-vsock-common.c
> @@ -11,12 +11,22 @@
>  #include "qemu/osdep.h"
>  #include "standard-headers/linux/virtio_vsock.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "hw/virtio/virtio-access.h"
>  #include "qemu/error-report.h"
>  #include "hw/qdev-properties.h"
>  #include "hw/virtio/vhost-vsock.h"
>  #include "qemu/iov.h"
>  #include "monitor/monitor.h"
> +#include "standard-headers/linux/vhost_types.h"
> +
> +qmp_virtio_feature_map_t vsock_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
>  
>  const int feature_bits[] = {
>      VIRTIO_VSOCK_F_SEQPACKET,
> diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
> index 193ff5261c..b2ae0a4d8c 100644
> --- a/hw/virtio/virtio-balloon.c
> +++ b/hw/virtio/virtio-balloon.c
> @@ -28,6 +28,7 @@
>  #include "qapi/error.h"
>  #include "qapi/qapi-events-machine.h"
>  #include "qapi/visitor.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "trace.h"
>  #include "qemu/error-report.h"
>  #include "migration/misc.h"
> @@ -38,6 +39,19 @@
>  
>  #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
>  
> +qmp_virtio_feature_map_t balloon_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_BALLOON_F_##name, #name }
> +    FEATURE_ENTRY(MUST_TELL_HOST),
> +    FEATURE_ENTRY(STATS_VQ),
> +    FEATURE_ENTRY(DEFLATE_ON_OOM),
> +    FEATURE_ENTRY(FREE_PAGE_HINT),
> +    FEATURE_ENTRY(PAGE_POISON),
> +    FEATURE_ENTRY(REPORTING),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  typedef struct PartiallyBalloonedPage {
>      ram_addr_t base_gpa;
>      unsigned long *bitmap;
> diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
> index 947a11c3af..5c9a3d045d 100644
> --- a/hw/virtio/virtio-crypto.c
> +++ b/hw/virtio/virtio-crypto.c
> @@ -16,6 +16,7 @@
>  #include "qemu/main-loop.h"
>  #include "qemu/module.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/error-report.h"
>  
>  #include "hw/virtio/virtio.h"
> @@ -23,10 +24,19 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/virtio/virtio-access.h"
>  #include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/vhost_types.h"
>  #include "sysemu/cryptodev-vhost.h"
>  
>  #define VIRTIO_CRYPTO_VM_VERSION 1
>  
> +qmp_virtio_feature_map_t crypto_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_F_##name, #name }
> +    FEATURE_ENTRY(LOG_ALL),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  /*
>   * Transfer virtqueue index to crypto queue index.
>   * The control virtqueue is after the data virtqueues
> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
> index 4ed5bb16ba..d993106d10 100644
> --- a/hw/virtio/virtio-iommu.c
> +++ b/hw/virtio/virtio-iommu.c
> @@ -26,6 +26,7 @@
>  #include "sysemu/kvm.h"
>  #include "sysemu/reset.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "qemu/error-report.h"
>  #include "trace.h"
>  
> @@ -41,6 +42,19 @@
>  #define VIOMMU_DEFAULT_QUEUE_SIZE 256
>  #define VIOMMU_PROBE_SIZE 512
>  
> +qmp_virtio_feature_map_t iommu_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_IOMMU_F_##name, #name }
> +    FEATURE_ENTRY(INPUT_RANGE),
> +    FEATURE_ENTRY(DOMAIN_RANGE),
> +    FEATURE_ENTRY(MAP_UNMAP),
> +    FEATURE_ENTRY(BYPASS),
> +    FEATURE_ENTRY(PROBE),
> +    FEATURE_ENTRY(MMIO),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  typedef struct VirtIOIOMMUDomain {
>      uint32_t id;
>      bool bypass;
> diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
> index 465a996214..31e7af834e 100644
> --- a/hw/virtio/virtio-mem.c
> +++ b/hw/virtio/virtio-mem.c
> @@ -25,6 +25,7 @@
>  #include "hw/virtio/virtio-mem.h"
>  #include "qapi/error.h"
>  #include "qapi/visitor.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "exec/ram_addr.h"
>  #include "migration/misc.h"
>  #include "hw/boards.h"
> @@ -32,6 +33,16 @@
>  #include CONFIG_DEVICES
>  #include "trace.h"
>  
> +qmp_virtio_feature_map_t mem_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_MEM_F_##name, #name }
> +#ifndef CONFIG_ACPI
> +    FEATURE_ENTRY(ACPI_PXM),
> +#endif /* CONFIG_ACPI */
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
>  /*
>   * We only had legacy x86 guests that did not support
>   * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 7f8eb29ced..af376be933 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -34,10 +34,99 @@
>  #include "sysemu/dma.h"
>  #include "sysemu/runstate.h"
>  #include "standard-headers/linux/virtio_ids.h"
> +#include "standard-headers/linux/vhost_types.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
> +
> +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
> +};
> +
> +static qmp_virtio_feature_map_t transport_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_F_##name, #name }
> +#ifndef VIRTIO_CONFIG_NO_LEGACY
> +    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
> +    FEATURE_ENTRY(ANY_LAYOUT),
> +#endif /* VIRTIO_CONFIG_NO_LEGACY */
> +    FEATURE_ENTRY(VERSION_1),
> +    FEATURE_ENTRY(IOMMU_PLATFORM),
> +    FEATURE_ENTRY(RING_PACKED),
> +    FEATURE_ENTRY(ORDER_PLATFORM),
> +    FEATURE_ENTRY(SR_IOV),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VIRTIO_RING_F_##name, #name }
> +    FEATURE_ENTRY(INDIRECT_DESC),
> +    FEATURE_ENTRY(EVENT_IDX),
> +#undef FEATURE_ENTRY
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_USER_F_##name, #name }
> +    FEATURE_ENTRY(PROTOCOL_FEATURES),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
> +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
> +#define FEATURE_ENTRY(name) \
> +    { VHOST_USER_PROTOCOL_F_##name, #name }
> +    FEATURE_ENTRY(MQ),
> +    FEATURE_ENTRY(LOG_SHMFD),
> +    FEATURE_ENTRY(RARP),
> +    FEATURE_ENTRY(REPLY_ACK),
> +    FEATURE_ENTRY(NET_MTU),
> +    FEATURE_ENTRY(SLAVE_REQ),
> +    FEATURE_ENTRY(CROSS_ENDIAN),
> +    FEATURE_ENTRY(CRYPTO_SESSION),
> +    FEATURE_ENTRY(PAGEFAULT),
> +    FEATURE_ENTRY(CONFIG),
> +    FEATURE_ENTRY(SLAVE_SEND_FD),
> +    FEATURE_ENTRY(HOST_NOTIFIER),
> +    FEATURE_ENTRY(INFLIGHT_SHMFD),
> +    FEATURE_ENTRY(RESET_DEVICE),
> +    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
> +    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
> +#undef FEATURE_ENTRY
> +    { -1, "" }
> +};
> +
> +/* virtio device configuration statuses */
> +static qmp_virtio_feature_map_t config_status_map[] = {
> +#define STATUS_ENTRY(name) \
> +    { VIRTIO_CONFIG_S_##name, #name }
> +    STATUS_ENTRY(DRIVER_OK),
> +    STATUS_ENTRY(FEATURES_OK),
> +    STATUS_ENTRY(DRIVER),
> +    STATUS_ENTRY(NEEDS_RESET),
> +    STATUS_ENTRY(FAILED),
> +    STATUS_ENTRY(ACKNOWLEDGE),
> +#undef STATUS_ENTRY
> +    { -1, "" }
> +};
> +
>  /*
>   * The alignment to use between consumer and producer parts of vring.
>   * x86 pagesize again. This is the default, used by transports like PCI
> @@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
>      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_name); \
> +            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, 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, transport_map, 0, bitmap);
> +
> +    /* device features */
> +    switch (device_id) {
> +#ifdef CONFIG_VIRTIO_SERIAL
> +    case VIRTIO_ID_CONSOLE:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_BLK
> +    case VIRTIO_ID_BLOCK:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_GPU
> +    case VIRTIO_ID_GPU:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_NET
> +    case VIRTIO_ID_NET:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, net_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_SCSI
> +    case VIRTIO_ID_SCSI:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_BALLOON
> +    case VIRTIO_ID_BALLOON:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_IOMMU
> +    case VIRTIO_ID_IOMMU:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_INPUT
> +    case VIRTIO_ID_INPUT:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, input_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VHOST_USER_FS
> +    case VIRTIO_ID_FS:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VHOST_VSOCK
> +    case VIRTIO_ID_VSOCK:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_CRYPTO
> +    case VIRTIO_ID_CRYPTO:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_MEM
> +    case VIRTIO_ID_MEM:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
> +        break;
> +#endif
> +#ifdef CONFIG_VIRTIO_I2C_ADAPTER
> +    case VIRTIO_ID_I2C_ADAPTER:
> +        features->dev_features =
> +            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
> +        break;
> +#endif
> +    /* No features */
> +    case VIRTIO_ID_9P:
> +    case VIRTIO_ID_PMEM:
> +    case VIRTIO_ID_RNG:
> +    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;
> @@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>      status->name = g_strdup(vdev->name);
>      status->device_id = vdev->device_id;
>      status->vhost_started = vdev->vhost_started;
> -    status->guest_features = vdev->guest_features;
> -    status->host_features = vdev->host_features;
> -    status->backend_features = vdev->backend_features;
> +    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:
> @@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>      }
>  
>      status->num_vqs = virtio_get_num_queues(vdev);
> -    status->status = vdev->status;
> +    status->status = qmp_decode_status(vdev->status);
>      status->isr = vdev->isr;
>      status->queue_sel = vdev->queue_sel;
>      status->vm_running = vdev->vm_running;
> @@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>          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 = hdev->features;
> -        status->vhost_dev->acked_features = hdev->acked_features;
> -        status->vhost_dev->backend_features = hdev->backend_features;
> -        status->vhost_dev->protocol_features = hdev->protocol_features;
> +        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;
> diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
> index 58a73e7b7a..4aaa21faf6 100644
> --- a/include/hw/virtio/vhost.h
> +++ b/include/hw/virtio/vhost.h
> @@ -5,6 +5,9 @@
>  #include "hw/virtio/virtio.h"
>  #include "exec/memory.h"
>  
> +#define VHOST_F_DEVICE_IOTLB 63
> +#define VHOST_USER_F_PROTOCOL_FEATURES 30
> +
>  /* Generic structures common for any vhost based device. */
>  
>  struct vhost_inflight {
> diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
> index ef99a626a8..9df4e081c9 100644
> --- a/include/hw/virtio/virtio.h
> +++ b/include/hw/virtio/virtio.h
> @@ -71,6 +71,25 @@ typedef struct VirtQueueElement
>  #define TYPE_VIRTIO_DEVICE "virtio-device"
>  OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
>  
> +typedef struct {
> +    int virtio_bit;
> +    const char *feature_name;
> +} qmp_virtio_feature_map_t;
> +
> +extern qmp_virtio_feature_map_t serial_map[];
> +extern qmp_virtio_feature_map_t blk_map[];
> +extern qmp_virtio_feature_map_t gpu_map[];
> +extern qmp_virtio_feature_map_t net_map[];
> +extern qmp_virtio_feature_map_t scsi_map[];
> +extern qmp_virtio_feature_map_t balloon_map[];
> +extern qmp_virtio_feature_map_t iommu_map[];
> +extern qmp_virtio_feature_map_t input_map[];
> +extern qmp_virtio_feature_map_t fs_map[];
> +extern qmp_virtio_feature_map_t vsock_map[];
> +extern qmp_virtio_feature_map_t crypto_map[];
> +extern qmp_virtio_feature_map_t mem_map[];
> +extern qmp_virtio_feature_map_t i2c_map[];
> +


So this hack where extern is in a common header, but the
actual values are spread in individual C files is not really
acceptable.


Also, the names are too generic and are not prefixed with
virtio which is a problem for a generic virtio.h header.
this kind of name is only ok as a static variable.

And, it seems to be causing problems when some devices
are disabled at config time. E.g. with virtio gpu disabled
we get:

https://gitlab.com/qemu-project/qemu/-/jobs/2463276202
https://gitlab.com/qemu-project/qemu/-/jobs/2463276291

libqemu-ppc64-softmmu.fa.p/hw_virtio_virtio.c.o: In function `qmp_decode_features':
/builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
/builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'


I could not figure it out from a quick look, please debug.


>  enum virtio_device_endian {
>      VIRTIO_DEVICE_ENDIAN_UNKNOWN,
>      VIRTIO_DEVICE_ENDIAN_LITTLE,
> diff --git a/qapi/virtio.json b/qapi/virtio.json
> index ba61d83df7..474a8bd64e 100644
> --- a/qapi/virtio.json
> +++ b/qapi/virtio.json
> @@ -106,10 +106,10 @@
>              'n-tmp-sections': 'int',
>              'nvqs': 'uint32',
>              'vq-index': 'int',
> -            'features': 'uint64',
> -            'acked-features': 'uint64',
> -            'backend-features': 'uint64',
> -            'protocol-features': 'uint64',
> +            'features': 'VirtioDeviceFeatures',
> +            'acked-features': 'VirtioDeviceFeatures',
> +            'backend-features': 'VirtioDeviceFeatures',
> +            'protocol-features': 'VhostDeviceProtocols',
>              'max-queues': 'uint64',
>              'backend-cap': 'uint64',
>              'log-enabled': 'bool',
> @@ -176,11 +176,11 @@
>              'device-id': 'uint16',
>              'vhost-started': 'bool',
>              'device-endian': 'str',
> -            'guest-features': 'uint64',
> -            'host-features': 'uint64',
> -            'backend-features': 'uint64',
> +            'guest-features': 'VirtioDeviceFeatures',
> +            'host-features': 'VirtioDeviceFeatures',
> +            'backend-features': 'VirtioDeviceFeatures',
>              'num-vqs': 'int',
> -            'status': 'uint8',
> +            'status': 'VirtioDeviceStatus',
>              'isr': 'uint8',
>              'queue-sel': 'uint16',
>              'vm-running': 'bool',
> @@ -222,14 +222,28 @@
>  #            "name": "virtio-crypto",
>  #            "started": true,
>  #            "device-id": 20,
> -#            "backend-features": 0,
> +#            "backend-features": {
> +#               "transports": [],
> +#               "dev-features": []
> +#            },
>  #            "start-on-kick": false,
>  #            "isr": 1,
>  #            "broken": false,
> -#            "status": 15,
> +#            "status": {
> +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
> +#                            "DRIVER_OK"]
> +#            },
>  #            "num-vqs": 2,
> -#            "guest-features": 5100273664,
> -#            "host-features": 6325010432,
> +#            "guest-features": {
> +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
> +#               "dev-features": []
> +#            },
> +#            "host-features": {
> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
> +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
> +#                              "NOTIFY_ON_EMPTY"],
> +#               "dev-features": []
> +#            },
>  #            "use-guest-notifier-mask": true,
>  #            "vm-running": true,
>  #            "queue-sel": 1,
> @@ -257,22 +271,65 @@
>  #               "max-queues": 1,
>  #               "backend-cap": 2,
>  #               "log-size": 0,
> -#               "backend-features": 0,
> +#               "backend-features": {
> +#                  "transports": [],
> +#                  "dev-features": []
> +#               },
>  #               "nvqs": 2,
> -#               "protocol-features": 0,
> +#               "protocol-features": {
> +#                  "protocols": []
> +#               },
>  #               "vq-index": 0,
>  #               "log-enabled": false,
> -#               "acked-features": 5100306432,
> -#               "features": 13908344832
> +#               "acked-features": {
> +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
> +#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
> +#                  "dev-features": ["MRG_RXBUF"]
> +#               },
> +#               "features": {
> +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
> +#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
> +#                                 "NOTIFY_ON_EMPTY"],
> +#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
> +#               }
> +#            },
> +#            "backend-features": {
> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
> +#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
> +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
> +#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
> +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
> +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
> +#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>  #            },
> -#            "backend-features": 6337593319,
>  #            "start-on-kick": false,
>  #            "isr": 1,
>  #            "broken": false,
> -#            "status": 15,
> +#            "status": {
> +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
> +#            },
>  #            "num-vqs": 3,
> -#            "guest-features": 5111807911,
> -#            "host-features": 6337593319,
> +#            "guest-features": {
> +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
> +#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
> +#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
> +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
> +#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
> +#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
> +#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
> +#            },
> +#            "host-features": {
> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
> +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
> +#                              "NOTIFY_ON_EMPTY"],
> +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
> +#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
> +#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
> +#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
> +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
> +#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
> +#                                "GUEST_CSUM", "CSUM"]
> +#            },
>  #            "use-guest-notifier-mask": true,
>  #            "vm-running": true,
>  #            "queue-sel": 2,
> @@ -288,3 +345,62 @@
>    'data': { 'path': 'str' },
>    'returns': 'VirtioStatus',
>    'features': [ 'unstable' ] }
> +
> +##
> +# @VirtioDeviceStatus:
> +#
> +# A structure defined to list the configuration statuses of a virtio
> +# device
> +#
> +# @statuses: List of decoded configuration statuses of the virtio
> +#            device
> +#
> +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
> +#
> +# Since: 7.0
> +##
> +
> +{ 'struct': 'VirtioDeviceStatus',
> +  'data': { 'statuses': [ 'str' ],
> +            '*unknown-statuses': 'uint8' } }
> +
> +##
> +# @VhostDeviceProtocols:
> +#
> +# A structure defined to list the vhost user protocol features of a
> +# Vhost User device
> +#
> +# @protocols: List of decoded vhost user protocol features of a vhost
> +#             user device
> +#
> +# @unknown-protocols: Vhost user device protocol features bitmap that
> +#                     have not been decoded
> +#
> +# Since: 7.0
> +##
> +
> +{ 'struct': 'VhostDeviceProtocols',
> +  'data': { 'protocols': [ 'str' ],
> +            '*unknown-protocols': 'uint64' } }
> +
> +##
> +# @VirtioDeviceFeatures:
> +#
> +# The common fields that apply to most Virtio devices. Some devices
> +# may not have their own device-specific features (e.g. virtio-rng).
> +#
> +# @transports: List of transport features of the virtio device
> +#
> +# @dev-features: List of device-specific features (if the device has
> +#                unique features)
> +#
> +# @unknown-dev-features: Virtio device features bitmap that have not
> +#                        been decoded
> +#
> +# Since: 7.0
> +##
> +
> +{ 'struct': 'VirtioDeviceFeatures',
> +  'data': { 'transports': [ 'str' ],
> +            '*dev-features': [ 'str' ],
> +            '*unknown-dev-features': 'uint64' } }
> -- 
> 2.35.1



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-05-16 20:26   ` Michael S. Tsirkin
@ 2022-05-19  6:30     ` Jonah Palmer
  2022-05-26 15:11       ` Michael S. Tsirkin
  2022-06-10  5:41       ` Michael S. Tsirkin
  0 siblings, 2 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-05-19  6:30 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu-devel, boris.ostrovsky, si-wei.liu, joao.m.martins,
	qemu-block, groug, qemu_oss, stefanha, lvivier, mathieu.poirier,
	arei.gonglei, eric.auger, kraxel, dgilbert, david,
	marcandre.lureau, armbru, michael.roth, eblake, thuth, pbonzini,
	kwolf, raphael.norwitz

[-- Attachment #1: Type: text/plain, Size: 42615 bytes --]


On 5/16/22 16:26, Michael S. Tsirkin wrote:
> On Fri, Apr 01, 2022 at 09:23:22AM -0400, Jonah Palmer wrote:
>> From: Laurent Vivier<lvivier@redhat.com>
>>
>> Display feature names instead of bitmaps for host, guest, and
>> backend for VirtIODevices.
>>
>> Display status names instead of bitmaps for VirtIODevices.
>>
>> Display feature names instead of bitmaps for backend, protocol,
>> acked, and features (hdev->features) for vhost devices.
>>
>> Decode features according to device ID. Decode statuses
>> according to configuration status bitmap (config_status_map).
>> Decode vhost user protocol features according to vhost user
>> protocol bitmap (vhost_user_protocol_map).
>>
>> Transport features are on the first line. Undecoded bits (if
>> any) are stored in a separate field.
>>
>> Signed-off-by: Jonah Palmer<jonah.palmer@oracle.com>
>
> So this has several problems that I missed previously.
> First, sign off from poster is missing.

My apologies, will add missing Laurent's SOB in correct order for
patches 3-8.

>
>
>
>> ---
>>   hw/block/virtio-blk.c          |  29 ++++
>>   hw/char/virtio-serial-bus.c    |  11 ++
>>   hw/display/virtio-gpu.c        |  18 ++
>>   hw/input/virtio-input.c        |  10 ++
>>   hw/net/virtio-net.c            |  47 +++++
>>   hw/scsi/virtio-scsi.c          |  17 ++
>>   hw/virtio/vhost-user-fs.c      |  10 ++
>>   hw/virtio/vhost-user-i2c.c     |  14 ++
>>   hw/virtio/vhost-vsock-common.c |  10 ++
>>   hw/virtio/virtio-balloon.c     |  14 ++
>>   hw/virtio/virtio-crypto.c      |  10 ++
>>   hw/virtio/virtio-iommu.c       |  14 ++
>>   hw/virtio/virtio-mem.c         |  11 ++
>>   hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
>>   include/hw/virtio/vhost.h      |   3 +
>>   include/hw/virtio/virtio.h     |  19 +++
>>   qapi/virtio.json               | 156 ++++++++++++++---
>>   17 files changed, 667 insertions(+), 28 deletions(-)
>>
>> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
>> index 27c71ad316..f104603040 100644
>> --- a/hw/block/virtio-blk.c
>> +++ b/hw/block/virtio-blk.c
>> @@ -13,6 +13,7 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/iov.h"
>>   #include "qemu/module.h"
>>   #include "qemu/error-report.h"
>> @@ -33,10 +34,38 @@
>>   #include "migration/qemu-file-types.h"
>>   #include "hw/virtio/virtio-access.h"
>>   #include "qemu/coroutine.h"
>> +#include "standard-headers/linux/vhost_types.h"
>>   
>>   /* Config size before the discard support (hide associated config fields) */
>>   #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
>>                                        max_discard_sectors)
>> +
>> +qmp_virtio_feature_map_t blk_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_BLK_F_##name, #name }
>> +    FEATURE_ENTRY(SIZE_MAX),
>> +    FEATURE_ENTRY(SEG_MAX),
>> +    FEATURE_ENTRY(GEOMETRY),
>> +    FEATURE_ENTRY(RO),
>> +    FEATURE_ENTRY(BLK_SIZE),
>> +    FEATURE_ENTRY(TOPOLOGY),
>> +    FEATURE_ENTRY(MQ),
>> +    FEATURE_ENTRY(DISCARD),
>> +    FEATURE_ENTRY(WRITE_ZEROES),
>> +#ifndef VIRTIO_BLK_NO_LEGACY
>> +    FEATURE_ENTRY(BARRIER),
>> +    FEATURE_ENTRY(SCSI),
>> +    FEATURE_ENTRY(FLUSH),
>> +    FEATURE_ENTRY(CONFIG_WCE),
>> +#endif /* !VIRTIO_BLK_NO_LEGACY */
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   /*
>>    * Starting from the discard feature, we can use this array to properly
>>    * set the config size depending on the features enabled.
>> diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
>> index 7d4601cb5d..fbb31a2b16 100644
>> --- a/hw/char/virtio-serial-bus.c
>> +++ b/hw/char/virtio-serial-bus.c
>> @@ -20,6 +20,7 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/iov.h"
>>   #include "qemu/main-loop.h"
>>   #include "qemu/module.h"
>> @@ -32,6 +33,16 @@
>>   #include "hw/virtio/virtio-serial.h"
>>   #include "hw/virtio/virtio-access.h"
>>   
>> +qmp_virtio_feature_map_t serial_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_CONSOLE_F_##name, #name }
>> +    FEATURE_ENTRY(SIZE),
>> +    FEATURE_ENTRY(MULTIPORT),
>> +    FEATURE_ENTRY(EMERG_WRITE),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   static struct VirtIOSerialDevices {
>>       QLIST_HEAD(, VirtIOSerial) devices;
>>   } vserdevices;
>> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
>> index 529b5246b2..0bd5dc6232 100644
>> --- a/hw/display/virtio-gpu.c
>> +++ b/hw/display/virtio-gpu.c
>> @@ -29,10 +29,28 @@
>>   #include "qemu/log.h"
>>   #include "qemu/module.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/error-report.h"
>> +#include "standard-headers/linux/vhost_types.h"
>>   
>>   #define VIRTIO_GPU_VM_VERSION 1
>>   
>> +qmp_virtio_feature_map_t gpu_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_GPU_F_##name, #name }
>> +    FEATURE_ENTRY(VIRGL),
>> +    FEATURE_ENTRY(EDID),
>> +    FEATURE_ENTRY(RESOURCE_UUID),
>> +    FEATURE_ENTRY(RESOURCE_BLOB),
>> +    FEATURE_ENTRY(CONTEXT_INIT),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>
> Now I had some experience with this, the trick makes it
> harder to find where is a given macro used, and at the same
> time saves very little. Also should a macro name change, we
> do not want the name to change.
> Let's just keep it simple please.
> Plain array of macros and strings with no tricks.

Sure thing. Should I define the macro outside of the map
definition? E.g:

#define FEATURE_ENTRY(name) { ##name, #name }
qmp_virtio_feature_map_t virtio_gpu_feature_map[] = {
     FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL),
     FEATURE_ENTRY(VIRTIO_GPU_F_EDID),
     ...
     { -1, "" }
};

Also, is that what you were thinking as a "plain array of macros
and strings"? Or was there something more simple you had in mind?

>
>
>>   static struct virtio_gpu_simple_resource*
>>   virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
>>   static struct virtio_gpu_simple_resource *
>> diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
>> index 5b5398b3ca..fe0ed6d5b4 100644
>> --- a/hw/input/virtio-input.c
>> +++ b/hw/input/virtio-input.c
>> @@ -6,6 +6,7 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/iov.h"
>>   #include "qemu/module.h"
>>   #include "trace.h"
>> @@ -14,10 +15,19 @@
>>   #include "hw/qdev-properties.h"
>>   #include "hw/virtio/virtio-input.h"
>>   
>> +#include "standard-headers/linux/vhost_types.h"
>>   #include "standard-headers/linux/input.h"
>>   
>>   #define VIRTIO_INPUT_VM_VERSION 1
>>   
>> +qmp_virtio_feature_map_t input_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   /* ----------------------------------------------------------------- */
>>   
>>   void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index 027ce40c6f..9356958fb6 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -35,9 +35,11 @@
>>   #include "hw/qdev-properties.h"
>>   #include "qapi/qapi-types-migration.h"
>>   #include "qapi/qapi-events-migration.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "hw/virtio/virtio-access.h"
>>   #include "migration/misc.h"
>>   #include "standard-headers/linux/ethtool.h"
>> +#include "standard-headers/linux/vhost_types.h"
>>   #include "sysemu/sysemu.h"
>>   #include "trace.h"
>>   #include "monitor/qdev.h"
>> @@ -90,6 +92,51 @@
>>                                            VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
>>                                            VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
>>   
>> +qmp_virtio_feature_map_t net_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_NET_F_##name, #name }
>> +    FEATURE_ENTRY(CSUM),
>> +    FEATURE_ENTRY(GUEST_CSUM),
>> +    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
>> +    FEATURE_ENTRY(MTU),
>> +    FEATURE_ENTRY(MAC),
>> +    FEATURE_ENTRY(GUEST_TSO4),
>> +    FEATURE_ENTRY(GUEST_TSO6),
>> +    FEATURE_ENTRY(GUEST_ECN),
>> +    FEATURE_ENTRY(GUEST_UFO),
>> +    FEATURE_ENTRY(HOST_TSO4),
>> +    FEATURE_ENTRY(HOST_TSO6),
>> +    FEATURE_ENTRY(HOST_ECN),
>> +    FEATURE_ENTRY(HOST_UFO),
>> +    FEATURE_ENTRY(MRG_RXBUF),
>> +    FEATURE_ENTRY(STATUS),
>> +    FEATURE_ENTRY(CTRL_VQ),
>> +    FEATURE_ENTRY(CTRL_RX),
>> +    FEATURE_ENTRY(CTRL_VLAN),
>> +    FEATURE_ENTRY(CTRL_RX_EXTRA),
>> +    FEATURE_ENTRY(GUEST_ANNOUNCE),
>> +    FEATURE_ENTRY(MQ),
>> +    FEATURE_ENTRY(CTRL_MAC_ADDR),
>> +    FEATURE_ENTRY(HASH_REPORT),
>> +    FEATURE_ENTRY(RSS),
>> +    FEATURE_ENTRY(RSC_EXT),
>> +    FEATURE_ENTRY(STANDBY),
>> +    FEATURE_ENTRY(SPEED_DUPLEX),
>> +#ifndef VIRTIO_NET_NO_LEGACY
>> +    FEATURE_ENTRY(GSO),
>> +#endif /* VIRTIO_NET_NO_LEGACY */
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_NET_F_##name, #name }
>> +    FEATURE_ENTRY(VIRTIO_NET_HDR),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   static const VirtIOFeature feature_sizes[] = {
>>       {.flags = 1ULL << VIRTIO_NET_F_MAC,
>>        .end = endof(struct virtio_net_config, mac)},
>> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
>> index 2a6141d081..9ca8faa40e 100644
>> --- a/hw/scsi/virtio-scsi.c
>> +++ b/hw/scsi/virtio-scsi.c
>> @@ -15,7 +15,9 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "standard-headers/linux/virtio_ids.h"
>> +#include "standard-headers/linux/vhost_types.h"
>>   #include "hw/virtio/virtio-scsi.h"
>>   #include "migration/qemu-file-types.h"
>>   #include "qemu/error-report.h"
>> @@ -29,6 +31,21 @@
>>   #include "hw/virtio/virtio-access.h"
>>   #include "trace.h"
>>   
>> +qmp_virtio_feature_map_t scsi_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_SCSI_F_##name, #name }
>> +    FEATURE_ENTRY(INOUT),
>> +    FEATURE_ENTRY(HOTPLUG),
>> +    FEATURE_ENTRY(CHANGE),
>> +    FEATURE_ENTRY(T10_PI),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   static inline int virtio_scsi_get_lun(uint8_t *lun)
>>   {
>>       return ((lun[2] << 8) | lun[3]) & 0x3FFF;
>> diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
>> index e513e4fdda..096cc07c44 100644
>> --- a/hw/virtio/vhost-user-fs.c
>> +++ b/hw/virtio/vhost-user-fs.c
>> @@ -15,6 +15,7 @@
>>   #include <sys/ioctl.h>
>>   #include "standard-headers/linux/virtio_fs.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "hw/qdev-properties.h"
>>   #include "hw/qdev-properties-system.h"
>>   #include "hw/virtio/virtio-bus.h"
>> @@ -23,6 +24,15 @@
>>   #include "hw/virtio/vhost-user-fs.h"
>>   #include "monitor/monitor.h"
>>   #include "sysemu/sysemu.h"
>> +#include "standard-headers/linux/vhost_types.h"
>> +
>> +qmp_virtio_feature_map_t fs_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>>   
>>   static const int user_feature_bits[] = {
>>       VIRTIO_F_VERSION_1,
>> diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
>> index 6020eee093..931ec9836c 100644
>> --- a/hw/virtio/vhost-user-i2c.c
>> +++ b/hw/virtio/vhost-user-i2c.c
>> @@ -8,11 +8,25 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "hw/qdev-properties.h"
>>   #include "hw/virtio/virtio-bus.h"
>>   #include "hw/virtio/vhost-user-i2c.h"
>>   #include "qemu/error-report.h"
>>   #include "standard-headers/linux/virtio_ids.h"
>> +#include "standard-headers/linux/vhost_types.h"
>> +
>> +qmp_virtio_feature_map_t i2c_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_I2C_F_##name, #name }
>> +    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>>   
>>   static const int feature_bits[] = {
>>       VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
>> diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
>> index 7394818e00..b03f94d8f8 100644
>> --- a/hw/virtio/vhost-vsock-common.c
>> +++ b/hw/virtio/vhost-vsock-common.c
>> @@ -11,12 +11,22 @@
>>   #include "qemu/osdep.h"
>>   #include "standard-headers/linux/virtio_vsock.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "hw/virtio/virtio-access.h"
>>   #include "qemu/error-report.h"
>>   #include "hw/qdev-properties.h"
>>   #include "hw/virtio/vhost-vsock.h"
>>   #include "qemu/iov.h"
>>   #include "monitor/monitor.h"
>> +#include "standard-headers/linux/vhost_types.h"
>> +
>> +qmp_virtio_feature_map_t vsock_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>>   
>>   const int feature_bits[] = {
>>       VIRTIO_VSOCK_F_SEQPACKET,
>> diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
>> index 193ff5261c..b2ae0a4d8c 100644
>> --- a/hw/virtio/virtio-balloon.c
>> +++ b/hw/virtio/virtio-balloon.c
>> @@ -28,6 +28,7 @@
>>   #include "qapi/error.h"
>>   #include "qapi/qapi-events-machine.h"
>>   #include "qapi/visitor.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "trace.h"
>>   #include "qemu/error-report.h"
>>   #include "migration/misc.h"
>> @@ -38,6 +39,19 @@
>>   
>>   #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
>>   
>> +qmp_virtio_feature_map_t balloon_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_BALLOON_F_##name, #name }
>> +    FEATURE_ENTRY(MUST_TELL_HOST),
>> +    FEATURE_ENTRY(STATS_VQ),
>> +    FEATURE_ENTRY(DEFLATE_ON_OOM),
>> +    FEATURE_ENTRY(FREE_PAGE_HINT),
>> +    FEATURE_ENTRY(PAGE_POISON),
>> +    FEATURE_ENTRY(REPORTING),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   typedef struct PartiallyBalloonedPage {
>>       ram_addr_t base_gpa;
>>       unsigned long *bitmap;
>> diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
>> index 947a11c3af..5c9a3d045d 100644
>> --- a/hw/virtio/virtio-crypto.c
>> +++ b/hw/virtio/virtio-crypto.c
>> @@ -16,6 +16,7 @@
>>   #include "qemu/main-loop.h"
>>   #include "qemu/module.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/error-report.h"
>>   
>>   #include "hw/virtio/virtio.h"
>> @@ -23,10 +24,19 @@
>>   #include "hw/qdev-properties.h"
>>   #include "hw/virtio/virtio-access.h"
>>   #include "standard-headers/linux/virtio_ids.h"
>> +#include "standard-headers/linux/vhost_types.h"
>>   #include "sysemu/cryptodev-vhost.h"
>>   
>>   #define VIRTIO_CRYPTO_VM_VERSION 1
>>   
>> +qmp_virtio_feature_map_t crypto_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_F_##name, #name }
>> +    FEATURE_ENTRY(LOG_ALL),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   /*
>>    * Transfer virtqueue index to crypto queue index.
>>    * The control virtqueue is after the data virtqueues
>> diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>> index 4ed5bb16ba..d993106d10 100644
>> --- a/hw/virtio/virtio-iommu.c
>> +++ b/hw/virtio/virtio-iommu.c
>> @@ -26,6 +26,7 @@
>>   #include "sysemu/kvm.h"
>>   #include "sysemu/reset.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "qemu/error-report.h"
>>   #include "trace.h"
>>   
>> @@ -41,6 +42,19 @@
>>   #define VIOMMU_DEFAULT_QUEUE_SIZE 256
>>   #define VIOMMU_PROBE_SIZE 512
>>   
>> +qmp_virtio_feature_map_t iommu_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_IOMMU_F_##name, #name }
>> +    FEATURE_ENTRY(INPUT_RANGE),
>> +    FEATURE_ENTRY(DOMAIN_RANGE),
>> +    FEATURE_ENTRY(MAP_UNMAP),
>> +    FEATURE_ENTRY(BYPASS),
>> +    FEATURE_ENTRY(PROBE),
>> +    FEATURE_ENTRY(MMIO),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   typedef struct VirtIOIOMMUDomain {
>>       uint32_t id;
>>       bool bypass;
>> diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
>> index 465a996214..31e7af834e 100644
>> --- a/hw/virtio/virtio-mem.c
>> +++ b/hw/virtio/virtio-mem.c
>> @@ -25,6 +25,7 @@
>>   #include "hw/virtio/virtio-mem.h"
>>   #include "qapi/error.h"
>>   #include "qapi/visitor.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "exec/ram_addr.h"
>>   #include "migration/misc.h"
>>   #include "hw/boards.h"
>> @@ -32,6 +33,16 @@
>>   #include CONFIG_DEVICES
>>   #include "trace.h"
>>   
>> +qmp_virtio_feature_map_t mem_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_MEM_F_##name, #name }
>> +#ifndef CONFIG_ACPI
>> +    FEATURE_ENTRY(ACPI_PXM),
>> +#endif /* CONFIG_ACPI */
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   /*
>>    * We only had legacy x86 guests that did not support
>>    * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>> index 7f8eb29ced..af376be933 100644
>> --- a/hw/virtio/virtio.c
>> +++ b/hw/virtio/virtio.c
>> @@ -34,10 +34,99 @@
>>   #include "sysemu/dma.h"
>>   #include "sysemu/runstate.h"
>>   #include "standard-headers/linux/virtio_ids.h"
>> +#include "standard-headers/linux/vhost_types.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
>> +
>> +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
>> +};
>> +
>> +static qmp_virtio_feature_map_t transport_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_F_##name, #name }
>> +#ifndef VIRTIO_CONFIG_NO_LEGACY
>> +    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
>> +    FEATURE_ENTRY(ANY_LAYOUT),
>> +#endif /* VIRTIO_CONFIG_NO_LEGACY */
>> +    FEATURE_ENTRY(VERSION_1),
>> +    FEATURE_ENTRY(IOMMU_PLATFORM),
>> +    FEATURE_ENTRY(RING_PACKED),
>> +    FEATURE_ENTRY(ORDER_PLATFORM),
>> +    FEATURE_ENTRY(SR_IOV),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VIRTIO_RING_F_##name, #name }
>> +    FEATURE_ENTRY(INDIRECT_DESC),
>> +    FEATURE_ENTRY(EVENT_IDX),
>> +#undef FEATURE_ENTRY
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_USER_F_##name, #name }
>> +    FEATURE_ENTRY(PROTOCOL_FEATURES),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>> +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
>> +#define FEATURE_ENTRY(name) \
>> +    { VHOST_USER_PROTOCOL_F_##name, #name }
>> +    FEATURE_ENTRY(MQ),
>> +    FEATURE_ENTRY(LOG_SHMFD),
>> +    FEATURE_ENTRY(RARP),
>> +    FEATURE_ENTRY(REPLY_ACK),
>> +    FEATURE_ENTRY(NET_MTU),
>> +    FEATURE_ENTRY(SLAVE_REQ),
>> +    FEATURE_ENTRY(CROSS_ENDIAN),
>> +    FEATURE_ENTRY(CRYPTO_SESSION),
>> +    FEATURE_ENTRY(PAGEFAULT),
>> +    FEATURE_ENTRY(CONFIG),
>> +    FEATURE_ENTRY(SLAVE_SEND_FD),
>> +    FEATURE_ENTRY(HOST_NOTIFIER),
>> +    FEATURE_ENTRY(INFLIGHT_SHMFD),
>> +    FEATURE_ENTRY(RESET_DEVICE),
>> +    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
>> +    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
>> +#undef FEATURE_ENTRY
>> +    { -1, "" }
>> +};
>> +
>> +/* virtio device configuration statuses */
>> +static qmp_virtio_feature_map_t config_status_map[] = {
>> +#define STATUS_ENTRY(name) \
>> +    { VIRTIO_CONFIG_S_##name, #name }
>> +    STATUS_ENTRY(DRIVER_OK),
>> +    STATUS_ENTRY(FEATURES_OK),
>> +    STATUS_ENTRY(DRIVER),
>> +    STATUS_ENTRY(NEEDS_RESET),
>> +    STATUS_ENTRY(FAILED),
>> +    STATUS_ENTRY(ACKNOWLEDGE),
>> +#undef STATUS_ENTRY
>> +    { -1, "" }
>> +};
>> +
>>   /*
>>    * The alignment to use between consumer and producer parts of vring.
>>    * x86 pagesize again. This is the default, used by transports like PCI
>> @@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
>>       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_name); \
>> +            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, 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, transport_map, 0, bitmap);
>> +
>> +    /* device features */
>> +    switch (device_id) {
>> +#ifdef CONFIG_VIRTIO_SERIAL
>> +    case VIRTIO_ID_CONSOLE:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_BLK
>> +    case VIRTIO_ID_BLOCK:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_GPU
>> +    case VIRTIO_ID_GPU:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_NET
>> +    case VIRTIO_ID_NET:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, net_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_SCSI
>> +    case VIRTIO_ID_SCSI:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_BALLOON
>> +    case VIRTIO_ID_BALLOON:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_IOMMU
>> +    case VIRTIO_ID_IOMMU:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_INPUT
>> +    case VIRTIO_ID_INPUT:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, input_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VHOST_USER_FS
>> +    case VIRTIO_ID_FS:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VHOST_VSOCK
>> +    case VIRTIO_ID_VSOCK:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_CRYPTO
>> +    case VIRTIO_ID_CRYPTO:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_MEM
>> +    case VIRTIO_ID_MEM:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
>> +        break;
>> +#endif
>> +#ifdef CONFIG_VIRTIO_I2C_ADAPTER
>> +    case VIRTIO_ID_I2C_ADAPTER:
>> +        features->dev_features =
>> +            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
>> +        break;
>> +#endif
>> +    /* No features */
>> +    case VIRTIO_ID_9P:
>> +    case VIRTIO_ID_PMEM:
>> +    case VIRTIO_ID_RNG:
>> +    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;
>> @@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>       status->name = g_strdup(vdev->name);
>>       status->device_id = vdev->device_id;
>>       status->vhost_started = vdev->vhost_started;
>> -    status->guest_features = vdev->guest_features;
>> -    status->host_features = vdev->host_features;
>> -    status->backend_features = vdev->backend_features;
>> +    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:
>> @@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>       }
>>   
>>       status->num_vqs = virtio_get_num_queues(vdev);
>> -    status->status = vdev->status;
>> +    status->status = qmp_decode_status(vdev->status);
>>       status->isr = vdev->isr;
>>       status->queue_sel = vdev->queue_sel;
>>       status->vm_running = vdev->vm_running;
>> @@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>           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 = hdev->features;
>> -        status->vhost_dev->acked_features = hdev->acked_features;
>> -        status->vhost_dev->backend_features = hdev->backend_features;
>> -        status->vhost_dev->protocol_features = hdev->protocol_features;
>> +        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;
>> diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
>> index 58a73e7b7a..4aaa21faf6 100644
>> --- a/include/hw/virtio/vhost.h
>> +++ b/include/hw/virtio/vhost.h
>> @@ -5,6 +5,9 @@
>>   #include "hw/virtio/virtio.h"
>>   #include "exec/memory.h"
>>   
>> +#define VHOST_F_DEVICE_IOTLB 63
>> +#define VHOST_USER_F_PROTOCOL_FEATURES 30
>> +
>>   /* Generic structures common for any vhost based device. */
>>   
>>   struct vhost_inflight {
>> diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
>> index ef99a626a8..9df4e081c9 100644
>> --- a/include/hw/virtio/virtio.h
>> +++ b/include/hw/virtio/virtio.h
>> @@ -71,6 +71,25 @@ typedef struct VirtQueueElement
>>   #define TYPE_VIRTIO_DEVICE "virtio-device"
>>   OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
>>   
>> +typedef struct {
>> +    int virtio_bit;
>> +    const char *feature_name;
>> +} qmp_virtio_feature_map_t;
>> +
>> +extern qmp_virtio_feature_map_t serial_map[];
>> +extern qmp_virtio_feature_map_t blk_map[];
>> +extern qmp_virtio_feature_map_t gpu_map[];
>> +extern qmp_virtio_feature_map_t net_map[];
>> +extern qmp_virtio_feature_map_t scsi_map[];
>> +extern qmp_virtio_feature_map_t balloon_map[];
>> +extern qmp_virtio_feature_map_t iommu_map[];
>> +extern qmp_virtio_feature_map_t input_map[];
>> +extern qmp_virtio_feature_map_t fs_map[];
>> +extern qmp_virtio_feature_map_t vsock_map[];
>> +extern qmp_virtio_feature_map_t crypto_map[];
>> +extern qmp_virtio_feature_map_t mem_map[];
>> +extern qmp_virtio_feature_map_t i2c_map[];
>> +
>
> So this hack where extern is in a common header, but the
> actual values are spread in individual C files is not really
> acceptable.

Understood. Will move these map definitions into virtio.c
instead.

>
> Also, the names are too generic and are not prefixed with
> virtio which is a problem for a generic virtio.h header.
> this kind of name is only ok as a static variable.

No problem, I can change them to something like
'virtio_x_feature_map'.

>
> And, it seems to be causing problems when some devices
> are disabled at config time. E.g. with virtio gpu disabled
> we get:
>
> https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276202__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvABmkhnR$  
> https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276291__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvK89VWxr$  
>
> libqemu-ppc64-softmmu.fa.p/hw_virtio_virtio.c.o: In function `qmp_decode_features':
> /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
> /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
>
>
> I could not figure it out from a quick look, please debug.

Got it, will debug. May be missing an #ifdef somewhere I suspect...

It will take some time for me to get the next series (v15) out since
I'll be away next week but hopefully I'll be able to get them out sooner
rather than later once I'm back.

Thanks,

Jonah

>
>
>>   enum virtio_device_endian {
>>       VIRTIO_DEVICE_ENDIAN_UNKNOWN,
>>       VIRTIO_DEVICE_ENDIAN_LITTLE,
>> diff --git a/qapi/virtio.json b/qapi/virtio.json
>> index ba61d83df7..474a8bd64e 100644
>> --- a/qapi/virtio.json
>> +++ b/qapi/virtio.json
>> @@ -106,10 +106,10 @@
>>               'n-tmp-sections': 'int',
>>               'nvqs': 'uint32',
>>               'vq-index': 'int',
>> -            'features': 'uint64',
>> -            'acked-features': 'uint64',
>> -            'backend-features': 'uint64',
>> -            'protocol-features': 'uint64',
>> +            'features': 'VirtioDeviceFeatures',
>> +            'acked-features': 'VirtioDeviceFeatures',
>> +            'backend-features': 'VirtioDeviceFeatures',
>> +            'protocol-features': 'VhostDeviceProtocols',
>>               'max-queues': 'uint64',
>>               'backend-cap': 'uint64',
>>               'log-enabled': 'bool',
>> @@ -176,11 +176,11 @@
>>               'device-id': 'uint16',
>>               'vhost-started': 'bool',
>>               'device-endian': 'str',
>> -            'guest-features': 'uint64',
>> -            'host-features': 'uint64',
>> -            'backend-features': 'uint64',
>> +            'guest-features': 'VirtioDeviceFeatures',
>> +            'host-features': 'VirtioDeviceFeatures',
>> +            'backend-features': 'VirtioDeviceFeatures',
>>               'num-vqs': 'int',
>> -            'status': 'uint8',
>> +            'status': 'VirtioDeviceStatus',
>>               'isr': 'uint8',
>>               'queue-sel': 'uint16',
>>               'vm-running': 'bool',
>> @@ -222,14 +222,28 @@
>>   #            "name": "virtio-crypto",
>>   #            "started": true,
>>   #            "device-id": 20,
>> -#            "backend-features": 0,
>> +#            "backend-features": {
>> +#               "transports": [],
>> +#               "dev-features": []
>> +#            },
>>   #            "start-on-kick": false,
>>   #            "isr": 1,
>>   #            "broken": false,
>> -#            "status": 15,
>> +#            "status": {
>> +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
>> +#                            "DRIVER_OK"]
>> +#            },
>>   #            "num-vqs": 2,
>> -#            "guest-features": 5100273664,
>> -#            "host-features": 6325010432,
>> +#            "guest-features": {
>> +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>> +#               "dev-features": []
>> +#            },
>> +#            "host-features": {
>> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>> +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>> +#                              "NOTIFY_ON_EMPTY"],
>> +#               "dev-features": []
>> +#            },
>>   #            "use-guest-notifier-mask": true,
>>   #            "vm-running": true,
>>   #            "queue-sel": 1,
>> @@ -257,22 +271,65 @@
>>   #               "max-queues": 1,
>>   #               "backend-cap": 2,
>>   #               "log-size": 0,
>> -#               "backend-features": 0,
>> +#               "backend-features": {
>> +#                  "transports": [],
>> +#                  "dev-features": []
>> +#               },
>>   #               "nvqs": 2,
>> -#               "protocol-features": 0,
>> +#               "protocol-features": {
>> +#                  "protocols": []
>> +#               },
>>   #               "vq-index": 0,
>>   #               "log-enabled": false,
>> -#               "acked-features": 5100306432,
>> -#               "features": 13908344832
>> +#               "acked-features": {
>> +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
>> +#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>> +#                  "dev-features": ["MRG_RXBUF"]
>> +#               },
>> +#               "features": {
>> +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
>> +#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
>> +#                                 "NOTIFY_ON_EMPTY"],
>> +#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
>> +#               }
>> +#            },
>> +#            "backend-features": {
>> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
>> +#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>> +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
>> +#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>> +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
>> +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
>> +#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>>   #            },
>> -#            "backend-features": 6337593319,
>>   #            "start-on-kick": false,
>>   #            "isr": 1,
>>   #            "broken": false,
>> -#            "status": 15,
>> +#            "status": {
>> +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
>> +#            },
>>   #            "num-vqs": 3,
>> -#            "guest-features": 5111807911,
>> -#            "host-features": 6337593319,
>> +#            "guest-features": {
>> +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>> +#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
>> +#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>> +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
>> +#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
>> +#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
>> +#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>> +#            },
>> +#            "host-features": {
>> +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>> +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>> +#                              "NOTIFY_ON_EMPTY"],
>> +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
>> +#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
>> +#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
>> +#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
>> +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
>> +#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
>> +#                                "GUEST_CSUM", "CSUM"]
>> +#            },
>>   #            "use-guest-notifier-mask": true,
>>   #            "vm-running": true,
>>   #            "queue-sel": 2,
>> @@ -288,3 +345,62 @@
>>     'data': { 'path': 'str' },
>>     'returns': 'VirtioStatus',
>>     'features': [ 'unstable' ] }
>> +
>> +##
>> +# @VirtioDeviceStatus:
>> +#
>> +# A structure defined to list the configuration statuses of a virtio
>> +# device
>> +#
>> +# @statuses: List of decoded configuration statuses of the virtio
>> +#            device
>> +#
>> +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
>> +#
>> +# Since: 7.0
>> +##
>> +
>> +{ 'struct': 'VirtioDeviceStatus',
>> +  'data': { 'statuses': [ 'str' ],
>> +            '*unknown-statuses': 'uint8' } }
>> +
>> +##
>> +# @VhostDeviceProtocols:
>> +#
>> +# A structure defined to list the vhost user protocol features of a
>> +# Vhost User device
>> +#
>> +# @protocols: List of decoded vhost user protocol features of a vhost
>> +#             user device
>> +#
>> +# @unknown-protocols: Vhost user device protocol features bitmap that
>> +#                     have not been decoded
>> +#
>> +# Since: 7.0
>> +##
>> +
>> +{ 'struct': 'VhostDeviceProtocols',
>> +  'data': { 'protocols': [ 'str' ],
>> +            '*unknown-protocols': 'uint64' } }
>> +
>> +##
>> +# @VirtioDeviceFeatures:
>> +#
>> +# The common fields that apply to most Virtio devices. Some devices
>> +# may not have their own device-specific features (e.g. virtio-rng).
>> +#
>> +# @transports: List of transport features of the virtio device
>> +#
>> +# @dev-features: List of device-specific features (if the device has
>> +#                unique features)
>> +#
>> +# @unknown-dev-features: Virtio device features bitmap that have not
>> +#                        been decoded
>> +#
>> +# Since: 7.0
>> +##
>> +
>> +{ 'struct': 'VirtioDeviceFeatures',
>> +  'data': { 'transports': [ 'str' ],
>> +            '*dev-features': [ 'str' ],
>> +            '*unknown-dev-features': 'uint64' } }
>> -- 
>> 2.35.1

[-- Attachment #2: Type: text/html, Size: 44923 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-05-19  6:30     ` Jonah Palmer
@ 2022-05-26 15:11       ` Michael S. Tsirkin
  2022-06-10  5:41       ` Michael S. Tsirkin
  1 sibling, 0 replies; 15+ messages in thread
From: Michael S. Tsirkin @ 2022-05-26 15:11 UTC (permalink / raw)
  To: Jonah Palmer
  Cc: qemu-devel, boris.ostrovsky, si-wei.liu, joao.m.martins,
	qemu-block, groug, qemu_oss, stefanha, lvivier, mathieu.poirier,
	arei.gonglei, eric.auger, kraxel, dgilbert, david,
	marcandre.lureau, armbru, michael.roth, eblake, thuth, pbonzini,
	kwolf, raphael.norwitz

On Thu, May 19, 2022 at 02:30:43AM -0400, Jonah Palmer wrote:
> 
> On 5/16/22 16:26, Michael S. Tsirkin wrote:
> 
>     On Fri, Apr 01, 2022 at 09:23:22AM -0400, Jonah Palmer wrote:
> 
>         From: Laurent Vivier <lvivier@redhat.com>
> 
>         Display feature names instead of bitmaps for host, guest, and
>         backend for VirtIODevices.
> 
>         Display status names instead of bitmaps for VirtIODevices.
> 
>         Display feature names instead of bitmaps for backend, protocol,
>         acked, and features (hdev->features) for vhost devices.
> 
>         Decode features according to device ID. Decode statuses
>         according to configuration status bitmap (config_status_map).
>         Decode vhost user protocol features according to vhost user
>         protocol bitmap (vhost_user_protocol_map).
> 
>         Transport features are on the first line. Undecoded bits (if
>         any) are stored in a separate field.
> 
>         Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
> 
> 
>     So this has several problems that I missed previously.
>     First, sign off from poster is missing.
> 
> My apologies, will add missing Laurent's SOB in correct order for
> patches 3-8.
> 
> 
> 
> 
> 
>         ---
>          hw/block/virtio-blk.c          |  29 ++++
>          hw/char/virtio-serial-bus.c    |  11 ++
>          hw/display/virtio-gpu.c        |  18 ++
>          hw/input/virtio-input.c        |  10 ++
>          hw/net/virtio-net.c            |  47 +++++
>          hw/scsi/virtio-scsi.c          |  17 ++
>          hw/virtio/vhost-user-fs.c      |  10 ++
>          hw/virtio/vhost-user-i2c.c     |  14 ++
>          hw/virtio/vhost-vsock-common.c |  10 ++
>          hw/virtio/virtio-balloon.c     |  14 ++
>          hw/virtio/virtio-crypto.c      |  10 ++
>          hw/virtio/virtio-iommu.c       |  14 ++
>          hw/virtio/virtio-mem.c         |  11 ++
>          hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
>          include/hw/virtio/vhost.h      |   3 +
>          include/hw/virtio/virtio.h     |  19 +++
>          qapi/virtio.json               | 156 ++++++++++++++---
>          17 files changed, 667 insertions(+), 28 deletions(-)
> 
>         diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
>         index 27c71ad316..f104603040 100644
>         --- a/hw/block/virtio-blk.c
>         +++ b/hw/block/virtio-blk.c
>         @@ -13,6 +13,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/module.h"
>          #include "qemu/error-report.h"
>         @@ -33,10 +34,38 @@
>          #include "migration/qemu-file-types.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "qemu/coroutine.h"
>         +#include "standard-headers/linux/vhost_types.h"
> 
>          /* Config size before the discard support (hide associated config fields) */
>          #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
>                                               max_discard_sectors)
>         +
>         +qmp_virtio_feature_map_t blk_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_BLK_F_##name, #name }
>         +    FEATURE_ENTRY(SIZE_MAX),
>         +    FEATURE_ENTRY(SEG_MAX),
>         +    FEATURE_ENTRY(GEOMETRY),
>         +    FEATURE_ENTRY(RO),
>         +    FEATURE_ENTRY(BLK_SIZE),
>         +    FEATURE_ENTRY(TOPOLOGY),
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(DISCARD),
>         +    FEATURE_ENTRY(WRITE_ZEROES),
>         +#ifndef VIRTIO_BLK_NO_LEGACY
>         +    FEATURE_ENTRY(BARRIER),
>         +    FEATURE_ENTRY(SCSI),
>         +    FEATURE_ENTRY(FLUSH),
>         +    FEATURE_ENTRY(CONFIG_WCE),
>         +#endif /* !VIRTIO_BLK_NO_LEGACY */
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * Starting from the discard feature, we can use this array to properly
>           * set the config size depending on the features enabled.
>         diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
>         index 7d4601cb5d..fbb31a2b16 100644
>         --- a/hw/char/virtio-serial-bus.c
>         +++ b/hw/char/virtio-serial-bus.c
>         @@ -20,6 +20,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/main-loop.h"
>          #include "qemu/module.h"
>         @@ -32,6 +33,16 @@
>          #include "hw/virtio/virtio-serial.h"
>          #include "hw/virtio/virtio-access.h"
> 
>         +qmp_virtio_feature_map_t serial_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_CONSOLE_F_##name, #name }
>         +    FEATURE_ENTRY(SIZE),
>         +    FEATURE_ENTRY(MULTIPORT),
>         +    FEATURE_ENTRY(EMERG_WRITE),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static struct VirtIOSerialDevices {
>              QLIST_HEAD(, VirtIOSerial) devices;
>          } vserdevices;
>         diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
>         index 529b5246b2..0bd5dc6232 100644
>         --- a/hw/display/virtio-gpu.c
>         +++ b/hw/display/virtio-gpu.c
>         @@ -29,10 +29,28 @@
>          #include "qemu/log.h"
>          #include "qemu/module.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
>         +#include "standard-headers/linux/vhost_types.h"
> 
>          #define VIRTIO_GPU_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t gpu_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_GPU_F_##name, #name }
>         +    FEATURE_ENTRY(VIRGL),
>         +    FEATURE_ENTRY(EDID),
>         +    FEATURE_ENTRY(RESOURCE_UUID),
>         +    FEATURE_ENTRY(RESOURCE_BLOB),
>         +    FEATURE_ENTRY(CONTEXT_INIT),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
> 
> 
>     Now I had some experience with this, the trick makes it
>     harder to find where is a given macro used, and at the same
>     time saves very little. Also should a macro name change, we
>     do not want the name to change.
>     Let's just keep it simple please.
>     Plain array of macros and strings with no tricks.
> 
> Sure thing. Should I define the macro outside of the map
> definition? E.g:
> 
> #define FEATURE_ENTRY(name) { ##name, #name }
> qmp_virtio_feature_map_t virtio_gpu_feature_map[] = {
>     FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL),
>     FEATURE_ENTRY(VIRTIO_GPU_F_EDID),
>     ...
>     { -1, "" }
> };
> Also, is that what you were thinking as a "plain array of macros
> and strings"? Or was there something more simple you had in mind?
> 

That's not too bad, yes.
But I think open-coding is even better since then you can add the
description:

VIRTIO_GPU_F_VIRGL, "VIRTIO_GPU_F_VIRGL: virgl 3D mode is supported"

I would advise against string concatenation for this since it
again makes it harder to find the string.


> 
> 
> 
>          static struct virtio_gpu_simple_resource*
>          virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
>          static struct virtio_gpu_simple_resource *
>         diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
>         index 5b5398b3ca..fe0ed6d5b4 100644
>         --- a/hw/input/virtio-input.c
>         +++ b/hw/input/virtio-input.c
>         @@ -6,6 +6,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/module.h"
>          #include "trace.h"
>         @@ -14,10 +15,19 @@
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-input.h"
> 
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "standard-headers/linux/input.h"
> 
>          #define VIRTIO_INPUT_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t input_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /* ----------------------------------------------------------------- */
> 
>          void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
>         diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>         index 027ce40c6f..9356958fb6 100644
>         --- a/hw/net/virtio-net.c
>         +++ b/hw/net/virtio-net.c
>         @@ -35,9 +35,11 @@
>          #include "hw/qdev-properties.h"
>          #include "qapi/qapi-types-migration.h"
>          #include "qapi/qapi-events-migration.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "migration/misc.h"
>          #include "standard-headers/linux/ethtool.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "sysemu/sysemu.h"
>          #include "trace.h"
>          #include "monitor/qdev.h"
>         @@ -90,6 +92,51 @@
>                                                   VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
>                                                   VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
> 
>         +qmp_virtio_feature_map_t net_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_NET_F_##name, #name }
>         +    FEATURE_ENTRY(CSUM),
>         +    FEATURE_ENTRY(GUEST_CSUM),
>         +    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
>         +    FEATURE_ENTRY(MTU),
>         +    FEATURE_ENTRY(MAC),
>         +    FEATURE_ENTRY(GUEST_TSO4),
>         +    FEATURE_ENTRY(GUEST_TSO6),
>         +    FEATURE_ENTRY(GUEST_ECN),
>         +    FEATURE_ENTRY(GUEST_UFO),
>         +    FEATURE_ENTRY(HOST_TSO4),
>         +    FEATURE_ENTRY(HOST_TSO6),
>         +    FEATURE_ENTRY(HOST_ECN),
>         +    FEATURE_ENTRY(HOST_UFO),
>         +    FEATURE_ENTRY(MRG_RXBUF),
>         +    FEATURE_ENTRY(STATUS),
>         +    FEATURE_ENTRY(CTRL_VQ),
>         +    FEATURE_ENTRY(CTRL_RX),
>         +    FEATURE_ENTRY(CTRL_VLAN),
>         +    FEATURE_ENTRY(CTRL_RX_EXTRA),
>         +    FEATURE_ENTRY(GUEST_ANNOUNCE),
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(CTRL_MAC_ADDR),
>         +    FEATURE_ENTRY(HASH_REPORT),
>         +    FEATURE_ENTRY(RSS),
>         +    FEATURE_ENTRY(RSC_EXT),
>         +    FEATURE_ENTRY(STANDBY),
>         +    FEATURE_ENTRY(SPEED_DUPLEX),
>         +#ifndef VIRTIO_NET_NO_LEGACY
>         +    FEATURE_ENTRY(GSO),
>         +#endif /* VIRTIO_NET_NO_LEGACY */
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_NET_F_##name, #name }
>         +    FEATURE_ENTRY(VIRTIO_NET_HDR),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static const VirtIOFeature feature_sizes[] = {
>              {.flags = 1ULL << VIRTIO_NET_F_MAC,
>               .end = endof(struct virtio_net_config, mac)},
>         diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
>         index 2a6141d081..9ca8faa40e 100644
>         --- a/hw/scsi/virtio-scsi.c
>         +++ b/hw/scsi/virtio-scsi.c
>         @@ -15,7 +15,9 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "hw/virtio/virtio-scsi.h"
>          #include "migration/qemu-file-types.h"
>          #include "qemu/error-report.h"
>         @@ -29,6 +31,21 @@
>          #include "hw/virtio/virtio-access.h"
>          #include "trace.h"
> 
>         +qmp_virtio_feature_map_t scsi_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_SCSI_F_##name, #name }
>         +    FEATURE_ENTRY(INOUT),
>         +    FEATURE_ENTRY(HOTPLUG),
>         +    FEATURE_ENTRY(CHANGE),
>         +    FEATURE_ENTRY(T10_PI),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static inline int virtio_scsi_get_lun(uint8_t *lun)
>          {
>              return ((lun[2] << 8) | lun[3]) & 0x3FFF;
>         diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
>         index e513e4fdda..096cc07c44 100644
>         --- a/hw/virtio/vhost-user-fs.c
>         +++ b/hw/virtio/vhost-user-fs.c
>         @@ -15,6 +15,7 @@
>          #include <sys/ioctl.h>
>          #include "standard-headers/linux/virtio_fs.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/qdev-properties-system.h"
>          #include "hw/virtio/virtio-bus.h"
>         @@ -23,6 +24,15 @@
>          #include "hw/virtio/vhost-user-fs.h"
>          #include "monitor/monitor.h"
>          #include "sysemu/sysemu.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t fs_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          static const int user_feature_bits[] = {
>              VIRTIO_F_VERSION_1,
>         diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
>         index 6020eee093..931ec9836c 100644
>         --- a/hw/virtio/vhost-user-i2c.c
>         +++ b/hw/virtio/vhost-user-i2c.c
>         @@ -8,11 +8,25 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-bus.h"
>          #include "hw/virtio/vhost-user-i2c.h"
>          #include "qemu/error-report.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t i2c_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_I2C_F_##name, #name }
>         +    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          static const int feature_bits[] = {
>              VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
>         diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
>         index 7394818e00..b03f94d8f8 100644
>         --- a/hw/virtio/vhost-vsock-common.c
>         +++ b/hw/virtio/vhost-vsock-common.c
>         @@ -11,12 +11,22 @@
>          #include "qemu/osdep.h"
>          #include "standard-headers/linux/virtio_vsock.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "qemu/error-report.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/vhost-vsock.h"
>          #include "qemu/iov.h"
>          #include "monitor/monitor.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t vsock_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          const int feature_bits[] = {
>              VIRTIO_VSOCK_F_SEQPACKET,
>         diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
>         index 193ff5261c..b2ae0a4d8c 100644
>         --- a/hw/virtio/virtio-balloon.c
>         +++ b/hw/virtio/virtio-balloon.c
>         @@ -28,6 +28,7 @@
>          #include "qapi/error.h"
>          #include "qapi/qapi-events-machine.h"
>          #include "qapi/visitor.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "trace.h"
>          #include "qemu/error-report.h"
>          #include "migration/misc.h"
>         @@ -38,6 +39,19 @@
> 
>          #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
> 
>         +qmp_virtio_feature_map_t balloon_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_BALLOON_F_##name, #name }
>         +    FEATURE_ENTRY(MUST_TELL_HOST),
>         +    FEATURE_ENTRY(STATS_VQ),
>         +    FEATURE_ENTRY(DEFLATE_ON_OOM),
>         +    FEATURE_ENTRY(FREE_PAGE_HINT),
>         +    FEATURE_ENTRY(PAGE_POISON),
>         +    FEATURE_ENTRY(REPORTING),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          typedef struct PartiallyBalloonedPage {
>              ram_addr_t base_gpa;
>              unsigned long *bitmap;
>         diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
>         index 947a11c3af..5c9a3d045d 100644
>         --- a/hw/virtio/virtio-crypto.c
>         +++ b/hw/virtio/virtio-crypto.c
>         @@ -16,6 +16,7 @@
>          #include "qemu/main-loop.h"
>          #include "qemu/module.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
> 
>          #include "hw/virtio/virtio.h"
>         @@ -23,10 +24,19 @@
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "sysemu/cryptodev-vhost.h"
> 
>          #define VIRTIO_CRYPTO_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t crypto_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * Transfer virtqueue index to crypto queue index.
>           * The control virtqueue is after the data virtqueues
>         diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>         index 4ed5bb16ba..d993106d10 100644
>         --- a/hw/virtio/virtio-iommu.c
>         +++ b/hw/virtio/virtio-iommu.c
>         @@ -26,6 +26,7 @@
>          #include "sysemu/kvm.h"
>          #include "sysemu/reset.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
>          #include "trace.h"
> 
>         @@ -41,6 +42,19 @@
>          #define VIOMMU_DEFAULT_QUEUE_SIZE 256
>          #define VIOMMU_PROBE_SIZE 512
> 
>         +qmp_virtio_feature_map_t iommu_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_IOMMU_F_##name, #name }
>         +    FEATURE_ENTRY(INPUT_RANGE),
>         +    FEATURE_ENTRY(DOMAIN_RANGE),
>         +    FEATURE_ENTRY(MAP_UNMAP),
>         +    FEATURE_ENTRY(BYPASS),
>         +    FEATURE_ENTRY(PROBE),
>         +    FEATURE_ENTRY(MMIO),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          typedef struct VirtIOIOMMUDomain {
>              uint32_t id;
>              bool bypass;
>         diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
>         index 465a996214..31e7af834e 100644
>         --- a/hw/virtio/virtio-mem.c
>         +++ b/hw/virtio/virtio-mem.c
>         @@ -25,6 +25,7 @@
>          #include "hw/virtio/virtio-mem.h"
>          #include "qapi/error.h"
>          #include "qapi/visitor.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "exec/ram_addr.h"
>          #include "migration/misc.h"
>          #include "hw/boards.h"
>         @@ -32,6 +33,16 @@
>          #include CONFIG_DEVICES
>          #include "trace.h"
> 
>         +qmp_virtio_feature_map_t mem_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_MEM_F_##name, #name }
>         +#ifndef CONFIG_ACPI
>         +    FEATURE_ENTRY(ACPI_PXM),
>         +#endif /* CONFIG_ACPI */
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * We only had legacy x86 guests that did not support
>           * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
>         diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>         index 7f8eb29ced..af376be933 100644
>         --- a/hw/virtio/virtio.c
>         +++ b/hw/virtio/virtio.c
>         @@ -34,10 +34,99 @@
>          #include "sysemu/dma.h"
>          #include "sysemu/runstate.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.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
>         +
>         +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
>         +};
>         +
>         +static qmp_virtio_feature_map_t transport_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_F_##name, #name }
>         +#ifndef VIRTIO_CONFIG_NO_LEGACY
>         +    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
>         +    FEATURE_ENTRY(ANY_LAYOUT),
>         +#endif /* VIRTIO_CONFIG_NO_LEGACY */
>         +    FEATURE_ENTRY(VERSION_1),
>         +    FEATURE_ENTRY(IOMMU_PLATFORM),
>         +    FEATURE_ENTRY(RING_PACKED),
>         +    FEATURE_ENTRY(ORDER_PLATFORM),
>         +    FEATURE_ENTRY(SR_IOV),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_RING_F_##name, #name }
>         +    FEATURE_ENTRY(INDIRECT_DESC),
>         +    FEATURE_ENTRY(EVENT_IDX),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_USER_F_##name, #name }
>         +    FEATURE_ENTRY(PROTOCOL_FEATURES),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>         +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_USER_PROTOCOL_F_##name, #name }
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(LOG_SHMFD),
>         +    FEATURE_ENTRY(RARP),
>         +    FEATURE_ENTRY(REPLY_ACK),
>         +    FEATURE_ENTRY(NET_MTU),
>         +    FEATURE_ENTRY(SLAVE_REQ),
>         +    FEATURE_ENTRY(CROSS_ENDIAN),
>         +    FEATURE_ENTRY(CRYPTO_SESSION),
>         +    FEATURE_ENTRY(PAGEFAULT),
>         +    FEATURE_ENTRY(CONFIG),
>         +    FEATURE_ENTRY(SLAVE_SEND_FD),
>         +    FEATURE_ENTRY(HOST_NOTIFIER),
>         +    FEATURE_ENTRY(INFLIGHT_SHMFD),
>         +    FEATURE_ENTRY(RESET_DEVICE),
>         +    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
>         +    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>         +/* virtio device configuration statuses */
>         +static qmp_virtio_feature_map_t config_status_map[] = {
>         +#define STATUS_ENTRY(name) \
>         +    { VIRTIO_CONFIG_S_##name, #name }
>         +    STATUS_ENTRY(DRIVER_OK),
>         +    STATUS_ENTRY(FEATURES_OK),
>         +    STATUS_ENTRY(DRIVER),
>         +    STATUS_ENTRY(NEEDS_RESET),
>         +    STATUS_ENTRY(FAILED),
>         +    STATUS_ENTRY(ACKNOWLEDGE),
>         +#undef STATUS_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * The alignment to use between consumer and producer parts of vring.
>           * x86 pagesize again. This is the default, used by transports like PCI
>         @@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
>              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_name); \
>         +            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, 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, transport_map, 0, bitmap);
>         +
>         +    /* device features */
>         +    switch (device_id) {
>         +#ifdef CONFIG_VIRTIO_SERIAL
>         +    case VIRTIO_ID_CONSOLE:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_BLK
>         +    case VIRTIO_ID_BLOCK:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_GPU
>         +    case VIRTIO_ID_GPU:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_NET
>         +    case VIRTIO_ID_NET:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, net_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_SCSI
>         +    case VIRTIO_ID_SCSI:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_BALLOON
>         +    case VIRTIO_ID_BALLOON:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_IOMMU
>         +    case VIRTIO_ID_IOMMU:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_INPUT
>         +    case VIRTIO_ID_INPUT:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, input_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VHOST_USER_FS
>         +    case VIRTIO_ID_FS:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VHOST_VSOCK
>         +    case VIRTIO_ID_VSOCK:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_CRYPTO
>         +    case VIRTIO_ID_CRYPTO:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_MEM
>         +    case VIRTIO_ID_MEM:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_I2C_ADAPTER
>         +    case VIRTIO_ID_I2C_ADAPTER:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
>         +        break;
>         +#endif
>         +    /* No features */
>         +    case VIRTIO_ID_9P:
>         +    case VIRTIO_ID_PMEM:
>         +    case VIRTIO_ID_RNG:
>         +    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;
>         @@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>              status->name = g_strdup(vdev->name);
>              status->device_id = vdev->device_id;
>              status->vhost_started = vdev->vhost_started;
>         -    status->guest_features = vdev->guest_features;
>         -    status->host_features = vdev->host_features;
>         -    status->backend_features = vdev->backend_features;
>         +    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:
>         @@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>              }
> 
>              status->num_vqs = virtio_get_num_queues(vdev);
>         -    status->status = vdev->status;
>         +    status->status = qmp_decode_status(vdev->status);
>              status->isr = vdev->isr;
>              status->queue_sel = vdev->queue_sel;
>              status->vm_running = vdev->vm_running;
>         @@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>                  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 = hdev->features;
>         -        status->vhost_dev->acked_features = hdev->acked_features;
>         -        status->vhost_dev->backend_features = hdev->backend_features;
>         -        status->vhost_dev->protocol_features = hdev->protocol_features;
>         +        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;
>         diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
>         index 58a73e7b7a..4aaa21faf6 100644
>         --- a/include/hw/virtio/vhost.h
>         +++ b/include/hw/virtio/vhost.h
>         @@ -5,6 +5,9 @@
>          #include "hw/virtio/virtio.h"
>          #include "exec/memory.h"
> 
>         +#define VHOST_F_DEVICE_IOTLB 63
>         +#define VHOST_USER_F_PROTOCOL_FEATURES 30
>         +
>          /* Generic structures common for any vhost based device. */
> 
>          struct vhost_inflight {
>         diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
>         index ef99a626a8..9df4e081c9 100644
>         --- a/include/hw/virtio/virtio.h
>         +++ b/include/hw/virtio/virtio.h
>         @@ -71,6 +71,25 @@ typedef struct VirtQueueElement
>          #define TYPE_VIRTIO_DEVICE "virtio-device"
>          OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
> 
>         +typedef struct {
>         +    int virtio_bit;
>         +    const char *feature_name;
>         +} qmp_virtio_feature_map_t;
>         +
>         +extern qmp_virtio_feature_map_t serial_map[];
>         +extern qmp_virtio_feature_map_t blk_map[];
>         +extern qmp_virtio_feature_map_t gpu_map[];
>         +extern qmp_virtio_feature_map_t net_map[];
>         +extern qmp_virtio_feature_map_t scsi_map[];
>         +extern qmp_virtio_feature_map_t balloon_map[];
>         +extern qmp_virtio_feature_map_t iommu_map[];
>         +extern qmp_virtio_feature_map_t input_map[];
>         +extern qmp_virtio_feature_map_t fs_map[];
>         +extern qmp_virtio_feature_map_t vsock_map[];
>         +extern qmp_virtio_feature_map_t crypto_map[];
>         +extern qmp_virtio_feature_map_t mem_map[];
>         +extern qmp_virtio_feature_map_t i2c_map[];
>         +
> 
> 
>     So this hack where extern is in a common header, but the
>     actual values are spread in individual C files is not really
>     acceptable.
> 
> Understood. Will move these map definitions into virtio.c
> instead.
> 
> 
>     Also, the names are too generic and are not prefixed with
>     virtio which is a problem for a generic virtio.h header.
>     this kind of name is only ok as a static variable.
> 
> No problem, I can change them to something like
> 'virtio_x_feature_map'.
> 
> 
>     And, it seems to be causing problems when some devices
>     are disabled at config time. E.g. with virtio gpu disabled
>     we get:
> 
>     https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276202__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvABmkhnR$
>     https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276291__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvK89VWxr$
> 
>     libqemu-ppc64-softmmu.fa.p/hw_virtio_virtio.c.o: In function `qmp_decode_features':
>     /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
>     /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
> 
> 
>     I could not figure it out from a quick look, please debug.
> 
> Got it, will debug. May be missing an #ifdef somewhere I suspect...
> 
> It will take some time for me to get the next series (v15) out since
> I'll be away next week but hopefully I'll be able to get them out sooner
> rather than later once I'm back.
> 
> Thanks,
> 
> Jonah
> 
> 
> 
> 
>          enum virtio_device_endian {
>              VIRTIO_DEVICE_ENDIAN_UNKNOWN,
>              VIRTIO_DEVICE_ENDIAN_LITTLE,
>         diff --git a/qapi/virtio.json b/qapi/virtio.json
>         index ba61d83df7..474a8bd64e 100644
>         --- a/qapi/virtio.json
>         +++ b/qapi/virtio.json
>         @@ -106,10 +106,10 @@
>                      'n-tmp-sections': 'int',
>                      'nvqs': 'uint32',
>                      'vq-index': 'int',
>         -            'features': 'uint64',
>         -            'acked-features': 'uint64',
>         -            'backend-features': 'uint64',
>         -            'protocol-features': 'uint64',
>         +            'features': 'VirtioDeviceFeatures',
>         +            'acked-features': 'VirtioDeviceFeatures',
>         +            'backend-features': 'VirtioDeviceFeatures',
>         +            'protocol-features': 'VhostDeviceProtocols',
>                      'max-queues': 'uint64',
>                      'backend-cap': 'uint64',
>                      'log-enabled': 'bool',
>         @@ -176,11 +176,11 @@
>                      'device-id': 'uint16',
>                      'vhost-started': 'bool',
>                      'device-endian': 'str',
>         -            'guest-features': 'uint64',
>         -            'host-features': 'uint64',
>         -            'backend-features': 'uint64',
>         +            'guest-features': 'VirtioDeviceFeatures',
>         +            'host-features': 'VirtioDeviceFeatures',
>         +            'backend-features': 'VirtioDeviceFeatures',
>                      'num-vqs': 'int',
>         -            'status': 'uint8',
>         +            'status': 'VirtioDeviceStatus',
>                      'isr': 'uint8',
>                      'queue-sel': 'uint16',
>                      'vm-running': 'bool',
>         @@ -222,14 +222,28 @@
>          #            "name": "virtio-crypto",
>          #            "started": true,
>          #            "device-id": 20,
>         -#            "backend-features": 0,
>         +#            "backend-features": {
>         +#               "transports": [],
>         +#               "dev-features": []
>         +#            },
>          #            "start-on-kick": false,
>          #            "isr": 1,
>          #            "broken": false,
>         -#            "status": 15,
>         +#            "status": {
>         +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
>         +#                            "DRIVER_OK"]
>         +#            },
>          #            "num-vqs": 2,
>         -#            "guest-features": 5100273664,
>         -#            "host-features": 6325010432,
>         +#            "guest-features": {
>         +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>         +#               "dev-features": []
>         +#            },
>         +#            "host-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>         +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>         +#                              "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": []
>         +#            },
>          #            "use-guest-notifier-mask": true,
>          #            "vm-running": true,
>          #            "queue-sel": 1,
>         @@ -257,22 +271,65 @@
>          #               "max-queues": 1,
>          #               "backend-cap": 2,
>          #               "log-size": 0,
>         -#               "backend-features": 0,
>         +#               "backend-features": {
>         +#                  "transports": [],
>         +#                  "dev-features": []
>         +#               },
>          #               "nvqs": 2,
>         -#               "protocol-features": 0,
>         +#               "protocol-features": {
>         +#                  "protocols": []
>         +#               },
>          #               "vq-index": 0,
>          #               "log-enabled": false,
>         -#               "acked-features": 5100306432,
>         -#               "features": 13908344832
>         +#               "acked-features": {
>         +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
>         +#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>         +#                  "dev-features": ["MRG_RXBUF"]
>         +#               },
>         +#               "features": {
>         +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
>         +#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
>         +#                                 "NOTIFY_ON_EMPTY"],
>         +#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
>         +#               }
>         +#            },
>         +#            "backend-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
>         +#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
>         +#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>         +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
>         +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
>         +#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>          #            },
>         -#            "backend-features": 6337593319,
>          #            "start-on-kick": false,
>          #            "isr": 1,
>          #            "broken": false,
>         -#            "status": 15,
>         +#            "status": {
>         +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
>         +#            },
>          #            "num-vqs": 3,
>         -#            "guest-features": 5111807911,
>         -#            "host-features": 6337593319,
>         +#            "guest-features": {
>         +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>         +#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
>         +#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>         +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
>         +#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
>         +#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
>         +#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>         +#            },
>         +#            "host-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>         +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>         +#                              "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
>         +#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
>         +#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
>         +#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
>         +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
>         +#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
>         +#                                "GUEST_CSUM", "CSUM"]
>         +#            },
>          #            "use-guest-notifier-mask": true,
>          #            "vm-running": true,
>          #            "queue-sel": 2,
>         @@ -288,3 +345,62 @@
>            'data': { 'path': 'str' },
>            'returns': 'VirtioStatus',
>            'features': [ 'unstable' ] }
>         +
>         +##
>         +# @VirtioDeviceStatus:
>         +#
>         +# A structure defined to list the configuration statuses of a virtio
>         +# device
>         +#
>         +# @statuses: List of decoded configuration statuses of the virtio
>         +#            device
>         +#
>         +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VirtioDeviceStatus',
>         +  'data': { 'statuses': [ 'str' ],
>         +            '*unknown-statuses': 'uint8' } }
>         +
>         +##
>         +# @VhostDeviceProtocols:
>         +#
>         +# A structure defined to list the vhost user protocol features of a
>         +# Vhost User device
>         +#
>         +# @protocols: List of decoded vhost user protocol features of a vhost
>         +#             user device
>         +#
>         +# @unknown-protocols: Vhost user device protocol features bitmap that
>         +#                     have not been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VhostDeviceProtocols',
>         +  'data': { 'protocols': [ 'str' ],
>         +            '*unknown-protocols': 'uint64' } }
>         +
>         +##
>         +# @VirtioDeviceFeatures:
>         +#
>         +# The common fields that apply to most Virtio devices. Some devices
>         +# may not have their own device-specific features (e.g. virtio-rng).
>         +#
>         +# @transports: List of transport features of the virtio device
>         +#
>         +# @dev-features: List of device-specific features (if the device has
>         +#                unique features)
>         +#
>         +# @unknown-dev-features: Virtio device features bitmap that have not
>         +#                        been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VirtioDeviceFeatures',
>         +  'data': { 'transports': [ 'str' ],
>         +            '*dev-features': [ 'str' ],
>         +            '*unknown-dev-features': 'uint64' } }
>         --
>         2.35.1
> 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-05-19  6:30     ` Jonah Palmer
  2022-05-26 15:11       ` Michael S. Tsirkin
@ 2022-06-10  5:41       ` Michael S. Tsirkin
  2022-06-13 14:43         ` Jonah Palmer
  1 sibling, 1 reply; 15+ messages in thread
From: Michael S. Tsirkin @ 2022-06-10  5:41 UTC (permalink / raw)
  To: Jonah Palmer
  Cc: qemu-devel, boris.ostrovsky, si-wei.liu, joao.m.martins,
	qemu-block, groug, qemu_oss, stefanha, lvivier, mathieu.poirier,
	arei.gonglei, eric.auger, kraxel, dgilbert, david,
	marcandre.lureau, armbru, michael.roth, eblake, thuth, pbonzini,
	kwolf, raphael.norwitz

On Thu, May 19, 2022 at 02:30:43AM -0400, Jonah Palmer wrote:
> 
> On 5/16/22 16:26, Michael S. Tsirkin wrote:
> 
>     On Fri, Apr 01, 2022 at 09:23:22AM -0400, Jonah Palmer wrote:
> 
>         From: Laurent Vivier <lvivier@redhat.com>
> 
>         Display feature names instead of bitmaps for host, guest, and
>         backend for VirtIODevices.
> 
>         Display status names instead of bitmaps for VirtIODevices.
> 
>         Display feature names instead of bitmaps for backend, protocol,
>         acked, and features (hdev->features) for vhost devices.
> 
>         Decode features according to device ID. Decode statuses
>         according to configuration status bitmap (config_status_map).
>         Decode vhost user protocol features according to vhost user
>         protocol bitmap (vhost_user_protocol_map).
> 
>         Transport features are on the first line. Undecoded bits (if
>         any) are stored in a separate field.
> 
>         Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
> 
> 
>     So this has several problems that I missed previously.
>     First, sign off from poster is missing.
> 
> My apologies, will add missing Laurent's SOB in correct order for
> patches 3-8.


Were you going to repost?

> 
> 
> 
> 
>         ---
>          hw/block/virtio-blk.c          |  29 ++++
>          hw/char/virtio-serial-bus.c    |  11 ++
>          hw/display/virtio-gpu.c        |  18 ++
>          hw/input/virtio-input.c        |  10 ++
>          hw/net/virtio-net.c            |  47 +++++
>          hw/scsi/virtio-scsi.c          |  17 ++
>          hw/virtio/vhost-user-fs.c      |  10 ++
>          hw/virtio/vhost-user-i2c.c     |  14 ++
>          hw/virtio/vhost-vsock-common.c |  10 ++
>          hw/virtio/virtio-balloon.c     |  14 ++
>          hw/virtio/virtio-crypto.c      |  10 ++
>          hw/virtio/virtio-iommu.c       |  14 ++
>          hw/virtio/virtio-mem.c         |  11 ++
>          hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
>          include/hw/virtio/vhost.h      |   3 +
>          include/hw/virtio/virtio.h     |  19 +++
>          qapi/virtio.json               | 156 ++++++++++++++---
>          17 files changed, 667 insertions(+), 28 deletions(-)
> 
>         diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
>         index 27c71ad316..f104603040 100644
>         --- a/hw/block/virtio-blk.c
>         +++ b/hw/block/virtio-blk.c
>         @@ -13,6 +13,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/module.h"
>          #include "qemu/error-report.h"
>         @@ -33,10 +34,38 @@
>          #include "migration/qemu-file-types.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "qemu/coroutine.h"
>         +#include "standard-headers/linux/vhost_types.h"
> 
>          /* Config size before the discard support (hide associated config fields) */
>          #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
>                                               max_discard_sectors)
>         +
>         +qmp_virtio_feature_map_t blk_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_BLK_F_##name, #name }
>         +    FEATURE_ENTRY(SIZE_MAX),
>         +    FEATURE_ENTRY(SEG_MAX),
>         +    FEATURE_ENTRY(GEOMETRY),
>         +    FEATURE_ENTRY(RO),
>         +    FEATURE_ENTRY(BLK_SIZE),
>         +    FEATURE_ENTRY(TOPOLOGY),
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(DISCARD),
>         +    FEATURE_ENTRY(WRITE_ZEROES),
>         +#ifndef VIRTIO_BLK_NO_LEGACY
>         +    FEATURE_ENTRY(BARRIER),
>         +    FEATURE_ENTRY(SCSI),
>         +    FEATURE_ENTRY(FLUSH),
>         +    FEATURE_ENTRY(CONFIG_WCE),
>         +#endif /* !VIRTIO_BLK_NO_LEGACY */
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * Starting from the discard feature, we can use this array to properly
>           * set the config size depending on the features enabled.
>         diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
>         index 7d4601cb5d..fbb31a2b16 100644
>         --- a/hw/char/virtio-serial-bus.c
>         +++ b/hw/char/virtio-serial-bus.c
>         @@ -20,6 +20,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/main-loop.h"
>          #include "qemu/module.h"
>         @@ -32,6 +33,16 @@
>          #include "hw/virtio/virtio-serial.h"
>          #include "hw/virtio/virtio-access.h"
> 
>         +qmp_virtio_feature_map_t serial_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_CONSOLE_F_##name, #name }
>         +    FEATURE_ENTRY(SIZE),
>         +    FEATURE_ENTRY(MULTIPORT),
>         +    FEATURE_ENTRY(EMERG_WRITE),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static struct VirtIOSerialDevices {
>              QLIST_HEAD(, VirtIOSerial) devices;
>          } vserdevices;
>         diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
>         index 529b5246b2..0bd5dc6232 100644
>         --- a/hw/display/virtio-gpu.c
>         +++ b/hw/display/virtio-gpu.c
>         @@ -29,10 +29,28 @@
>          #include "qemu/log.h"
>          #include "qemu/module.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
>         +#include "standard-headers/linux/vhost_types.h"
> 
>          #define VIRTIO_GPU_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t gpu_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_GPU_F_##name, #name }
>         +    FEATURE_ENTRY(VIRGL),
>         +    FEATURE_ENTRY(EDID),
>         +    FEATURE_ENTRY(RESOURCE_UUID),
>         +    FEATURE_ENTRY(RESOURCE_BLOB),
>         +    FEATURE_ENTRY(CONTEXT_INIT),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
> 
> 
>     Now I had some experience with this, the trick makes it
>     harder to find where is a given macro used, and at the same
>     time saves very little. Also should a macro name change, we
>     do not want the name to change.
>     Let's just keep it simple please.
>     Plain array of macros and strings with no tricks.
> 
> Sure thing. Should I define the macro outside of the map
> definition? E.g:
> 
> #define FEATURE_ENTRY(name) { ##name, #name }
> qmp_virtio_feature_map_t virtio_gpu_feature_map[] = {
>     FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL),
>     FEATURE_ENTRY(VIRTIO_GPU_F_EDID),
>     ...
>     { -1, "" }
> };
> 
> Also, is that what you were thinking as a "plain array of macros
> and strings"? Or was there something more simple you had in mind?
> 
> 
> 
> 
>          static struct virtio_gpu_simple_resource*
>          virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
>          static struct virtio_gpu_simple_resource *
>         diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
>         index 5b5398b3ca..fe0ed6d5b4 100644
>         --- a/hw/input/virtio-input.c
>         +++ b/hw/input/virtio-input.c
>         @@ -6,6 +6,7 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/iov.h"
>          #include "qemu/module.h"
>          #include "trace.h"
>         @@ -14,10 +15,19 @@
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-input.h"
> 
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "standard-headers/linux/input.h"
> 
>          #define VIRTIO_INPUT_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t input_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /* ----------------------------------------------------------------- */
> 
>          void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
>         diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>         index 027ce40c6f..9356958fb6 100644
>         --- a/hw/net/virtio-net.c
>         +++ b/hw/net/virtio-net.c
>         @@ -35,9 +35,11 @@
>          #include "hw/qdev-properties.h"
>          #include "qapi/qapi-types-migration.h"
>          #include "qapi/qapi-events-migration.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "migration/misc.h"
>          #include "standard-headers/linux/ethtool.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "sysemu/sysemu.h"
>          #include "trace.h"
>          #include "monitor/qdev.h"
>         @@ -90,6 +92,51 @@
>                                                   VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
>                                                   VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
> 
>         +qmp_virtio_feature_map_t net_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_NET_F_##name, #name }
>         +    FEATURE_ENTRY(CSUM),
>         +    FEATURE_ENTRY(GUEST_CSUM),
>         +    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
>         +    FEATURE_ENTRY(MTU),
>         +    FEATURE_ENTRY(MAC),
>         +    FEATURE_ENTRY(GUEST_TSO4),
>         +    FEATURE_ENTRY(GUEST_TSO6),
>         +    FEATURE_ENTRY(GUEST_ECN),
>         +    FEATURE_ENTRY(GUEST_UFO),
>         +    FEATURE_ENTRY(HOST_TSO4),
>         +    FEATURE_ENTRY(HOST_TSO6),
>         +    FEATURE_ENTRY(HOST_ECN),
>         +    FEATURE_ENTRY(HOST_UFO),
>         +    FEATURE_ENTRY(MRG_RXBUF),
>         +    FEATURE_ENTRY(STATUS),
>         +    FEATURE_ENTRY(CTRL_VQ),
>         +    FEATURE_ENTRY(CTRL_RX),
>         +    FEATURE_ENTRY(CTRL_VLAN),
>         +    FEATURE_ENTRY(CTRL_RX_EXTRA),
>         +    FEATURE_ENTRY(GUEST_ANNOUNCE),
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(CTRL_MAC_ADDR),
>         +    FEATURE_ENTRY(HASH_REPORT),
>         +    FEATURE_ENTRY(RSS),
>         +    FEATURE_ENTRY(RSC_EXT),
>         +    FEATURE_ENTRY(STANDBY),
>         +    FEATURE_ENTRY(SPEED_DUPLEX),
>         +#ifndef VIRTIO_NET_NO_LEGACY
>         +    FEATURE_ENTRY(GSO),
>         +#endif /* VIRTIO_NET_NO_LEGACY */
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_NET_F_##name, #name }
>         +    FEATURE_ENTRY(VIRTIO_NET_HDR),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static const VirtIOFeature feature_sizes[] = {
>              {.flags = 1ULL << VIRTIO_NET_F_MAC,
>               .end = endof(struct virtio_net_config, mac)},
>         diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
>         index 2a6141d081..9ca8faa40e 100644
>         --- a/hw/scsi/virtio-scsi.c
>         +++ b/hw/scsi/virtio-scsi.c
>         @@ -15,7 +15,9 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "hw/virtio/virtio-scsi.h"
>          #include "migration/qemu-file-types.h"
>          #include "qemu/error-report.h"
>         @@ -29,6 +31,21 @@
>          #include "hw/virtio/virtio-access.h"
>          #include "trace.h"
> 
>         +qmp_virtio_feature_map_t scsi_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_SCSI_F_##name, #name }
>         +    FEATURE_ENTRY(INOUT),
>         +    FEATURE_ENTRY(HOTPLUG),
>         +    FEATURE_ENTRY(CHANGE),
>         +    FEATURE_ENTRY(T10_PI),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          static inline int virtio_scsi_get_lun(uint8_t *lun)
>          {
>              return ((lun[2] << 8) | lun[3]) & 0x3FFF;
>         diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
>         index e513e4fdda..096cc07c44 100644
>         --- a/hw/virtio/vhost-user-fs.c
>         +++ b/hw/virtio/vhost-user-fs.c
>         @@ -15,6 +15,7 @@
>          #include <sys/ioctl.h>
>          #include "standard-headers/linux/virtio_fs.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/qdev-properties-system.h"
>          #include "hw/virtio/virtio-bus.h"
>         @@ -23,6 +24,15 @@
>          #include "hw/virtio/vhost-user-fs.h"
>          #include "monitor/monitor.h"
>          #include "sysemu/sysemu.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t fs_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          static const int user_feature_bits[] = {
>              VIRTIO_F_VERSION_1,
>         diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
>         index 6020eee093..931ec9836c 100644
>         --- a/hw/virtio/vhost-user-i2c.c
>         +++ b/hw/virtio/vhost-user-i2c.c
>         @@ -8,11 +8,25 @@
> 
>          #include "qemu/osdep.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-bus.h"
>          #include "hw/virtio/vhost-user-i2c.h"
>          #include "qemu/error-report.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t i2c_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_I2C_F_##name, #name }
>         +    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          static const int feature_bits[] = {
>              VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
>         diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
>         index 7394818e00..b03f94d8f8 100644
>         --- a/hw/virtio/vhost-vsock-common.c
>         +++ b/hw/virtio/vhost-vsock-common.c
>         @@ -11,12 +11,22 @@
>          #include "qemu/osdep.h"
>          #include "standard-headers/linux/virtio_vsock.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "qemu/error-report.h"
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/vhost-vsock.h"
>          #include "qemu/iov.h"
>          #include "monitor/monitor.h"
>         +#include "standard-headers/linux/vhost_types.h"
>         +
>         +qmp_virtio_feature_map_t vsock_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
> 
>          const int feature_bits[] = {
>              VIRTIO_VSOCK_F_SEQPACKET,
>         diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
>         index 193ff5261c..b2ae0a4d8c 100644
>         --- a/hw/virtio/virtio-balloon.c
>         +++ b/hw/virtio/virtio-balloon.c
>         @@ -28,6 +28,7 @@
>          #include "qapi/error.h"
>          #include "qapi/qapi-events-machine.h"
>          #include "qapi/visitor.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "trace.h"
>          #include "qemu/error-report.h"
>          #include "migration/misc.h"
>         @@ -38,6 +39,19 @@
> 
>          #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
> 
>         +qmp_virtio_feature_map_t balloon_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_BALLOON_F_##name, #name }
>         +    FEATURE_ENTRY(MUST_TELL_HOST),
>         +    FEATURE_ENTRY(STATS_VQ),
>         +    FEATURE_ENTRY(DEFLATE_ON_OOM),
>         +    FEATURE_ENTRY(FREE_PAGE_HINT),
>         +    FEATURE_ENTRY(PAGE_POISON),
>         +    FEATURE_ENTRY(REPORTING),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          typedef struct PartiallyBalloonedPage {
>              ram_addr_t base_gpa;
>              unsigned long *bitmap;
>         diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
>         index 947a11c3af..5c9a3d045d 100644
>         --- a/hw/virtio/virtio-crypto.c
>         +++ b/hw/virtio/virtio-crypto.c
>         @@ -16,6 +16,7 @@
>          #include "qemu/main-loop.h"
>          #include "qemu/module.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
> 
>          #include "hw/virtio/virtio.h"
>         @@ -23,10 +24,19 @@
>          #include "hw/qdev-properties.h"
>          #include "hw/virtio/virtio-access.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.h"
>          #include "sysemu/cryptodev-vhost.h"
> 
>          #define VIRTIO_CRYPTO_VM_VERSION 1
> 
>         +qmp_virtio_feature_map_t crypto_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_F_##name, #name }
>         +    FEATURE_ENTRY(LOG_ALL),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * Transfer virtqueue index to crypto queue index.
>           * The control virtqueue is after the data virtqueues
>         diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>         index 4ed5bb16ba..d993106d10 100644
>         --- a/hw/virtio/virtio-iommu.c
>         +++ b/hw/virtio/virtio-iommu.c
>         @@ -26,6 +26,7 @@
>          #include "sysemu/kvm.h"
>          #include "sysemu/reset.h"
>          #include "qapi/error.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "qemu/error-report.h"
>          #include "trace.h"
> 
>         @@ -41,6 +42,19 @@
>          #define VIOMMU_DEFAULT_QUEUE_SIZE 256
>          #define VIOMMU_PROBE_SIZE 512
> 
>         +qmp_virtio_feature_map_t iommu_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_IOMMU_F_##name, #name }
>         +    FEATURE_ENTRY(INPUT_RANGE),
>         +    FEATURE_ENTRY(DOMAIN_RANGE),
>         +    FEATURE_ENTRY(MAP_UNMAP),
>         +    FEATURE_ENTRY(BYPASS),
>         +    FEATURE_ENTRY(PROBE),
>         +    FEATURE_ENTRY(MMIO),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          typedef struct VirtIOIOMMUDomain {
>              uint32_t id;
>              bool bypass;
>         diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
>         index 465a996214..31e7af834e 100644
>         --- a/hw/virtio/virtio-mem.c
>         +++ b/hw/virtio/virtio-mem.c
>         @@ -25,6 +25,7 @@
>          #include "hw/virtio/virtio-mem.h"
>          #include "qapi/error.h"
>          #include "qapi/visitor.h"
>         +#include "qapi/qapi-visit-virtio.h"
>          #include "exec/ram_addr.h"
>          #include "migration/misc.h"
>          #include "hw/boards.h"
>         @@ -32,6 +33,16 @@
>          #include CONFIG_DEVICES
>          #include "trace.h"
> 
>         +qmp_virtio_feature_map_t mem_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_MEM_F_##name, #name }
>         +#ifndef CONFIG_ACPI
>         +    FEATURE_ENTRY(ACPI_PXM),
>         +#endif /* CONFIG_ACPI */
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * We only had legacy x86 guests that did not support
>           * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
>         diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>         index 7f8eb29ced..af376be933 100644
>         --- a/hw/virtio/virtio.c
>         +++ b/hw/virtio/virtio.c
>         @@ -34,10 +34,99 @@
>          #include "sysemu/dma.h"
>          #include "sysemu/runstate.h"
>          #include "standard-headers/linux/virtio_ids.h"
>         +#include "standard-headers/linux/vhost_types.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
>         +
>         +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
>         +};
>         +
>         +static qmp_virtio_feature_map_t transport_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_F_##name, #name }
>         +#ifndef VIRTIO_CONFIG_NO_LEGACY
>         +    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
>         +    FEATURE_ENTRY(ANY_LAYOUT),
>         +#endif /* VIRTIO_CONFIG_NO_LEGACY */
>         +    FEATURE_ENTRY(VERSION_1),
>         +    FEATURE_ENTRY(IOMMU_PLATFORM),
>         +    FEATURE_ENTRY(RING_PACKED),
>         +    FEATURE_ENTRY(ORDER_PLATFORM),
>         +    FEATURE_ENTRY(SR_IOV),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VIRTIO_RING_F_##name, #name }
>         +    FEATURE_ENTRY(INDIRECT_DESC),
>         +    FEATURE_ENTRY(EVENT_IDX),
>         +#undef FEATURE_ENTRY
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_USER_F_##name, #name }
>         +    FEATURE_ENTRY(PROTOCOL_FEATURES),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>         +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
>         +#define FEATURE_ENTRY(name) \
>         +    { VHOST_USER_PROTOCOL_F_##name, #name }
>         +    FEATURE_ENTRY(MQ),
>         +    FEATURE_ENTRY(LOG_SHMFD),
>         +    FEATURE_ENTRY(RARP),
>         +    FEATURE_ENTRY(REPLY_ACK),
>         +    FEATURE_ENTRY(NET_MTU),
>         +    FEATURE_ENTRY(SLAVE_REQ),
>         +    FEATURE_ENTRY(CROSS_ENDIAN),
>         +    FEATURE_ENTRY(CRYPTO_SESSION),
>         +    FEATURE_ENTRY(PAGEFAULT),
>         +    FEATURE_ENTRY(CONFIG),
>         +    FEATURE_ENTRY(SLAVE_SEND_FD),
>         +    FEATURE_ENTRY(HOST_NOTIFIER),
>         +    FEATURE_ENTRY(INFLIGHT_SHMFD),
>         +    FEATURE_ENTRY(RESET_DEVICE),
>         +    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
>         +    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
>         +#undef FEATURE_ENTRY
>         +    { -1, "" }
>         +};
>         +
>         +/* virtio device configuration statuses */
>         +static qmp_virtio_feature_map_t config_status_map[] = {
>         +#define STATUS_ENTRY(name) \
>         +    { VIRTIO_CONFIG_S_##name, #name }
>         +    STATUS_ENTRY(DRIVER_OK),
>         +    STATUS_ENTRY(FEATURES_OK),
>         +    STATUS_ENTRY(DRIVER),
>         +    STATUS_ENTRY(NEEDS_RESET),
>         +    STATUS_ENTRY(FAILED),
>         +    STATUS_ENTRY(ACKNOWLEDGE),
>         +#undef STATUS_ENTRY
>         +    { -1, "" }
>         +};
>         +
>          /*
>           * The alignment to use between consumer and producer parts of vring.
>           * x86 pagesize again. This is the default, used by transports like PCI
>         @@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
>              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_name); \
>         +            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, 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, transport_map, 0, bitmap);
>         +
>         +    /* device features */
>         +    switch (device_id) {
>         +#ifdef CONFIG_VIRTIO_SERIAL
>         +    case VIRTIO_ID_CONSOLE:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_BLK
>         +    case VIRTIO_ID_BLOCK:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_GPU
>         +    case VIRTIO_ID_GPU:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_NET
>         +    case VIRTIO_ID_NET:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, net_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_SCSI
>         +    case VIRTIO_ID_SCSI:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_BALLOON
>         +    case VIRTIO_ID_BALLOON:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_IOMMU
>         +    case VIRTIO_ID_IOMMU:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_INPUT
>         +    case VIRTIO_ID_INPUT:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, input_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VHOST_USER_FS
>         +    case VIRTIO_ID_FS:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VHOST_VSOCK
>         +    case VIRTIO_ID_VSOCK:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_CRYPTO
>         +    case VIRTIO_ID_CRYPTO:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_MEM
>         +    case VIRTIO_ID_MEM:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
>         +        break;
>         +#endif
>         +#ifdef CONFIG_VIRTIO_I2C_ADAPTER
>         +    case VIRTIO_ID_I2C_ADAPTER:
>         +        features->dev_features =
>         +            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
>         +        break;
>         +#endif
>         +    /* No features */
>         +    case VIRTIO_ID_9P:
>         +    case VIRTIO_ID_PMEM:
>         +    case VIRTIO_ID_RNG:
>         +    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;
>         @@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>              status->name = g_strdup(vdev->name);
>              status->device_id = vdev->device_id;
>              status->vhost_started = vdev->vhost_started;
>         -    status->guest_features = vdev->guest_features;
>         -    status->host_features = vdev->host_features;
>         -    status->backend_features = vdev->backend_features;
>         +    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:
>         @@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>              }
> 
>              status->num_vqs = virtio_get_num_queues(vdev);
>         -    status->status = vdev->status;
>         +    status->status = qmp_decode_status(vdev->status);
>              status->isr = vdev->isr;
>              status->queue_sel = vdev->queue_sel;
>              status->vm_running = vdev->vm_running;
>         @@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>                  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 = hdev->features;
>         -        status->vhost_dev->acked_features = hdev->acked_features;
>         -        status->vhost_dev->backend_features = hdev->backend_features;
>         -        status->vhost_dev->protocol_features = hdev->protocol_features;
>         +        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;
>         diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
>         index 58a73e7b7a..4aaa21faf6 100644
>         --- a/include/hw/virtio/vhost.h
>         +++ b/include/hw/virtio/vhost.h
>         @@ -5,6 +5,9 @@
>          #include "hw/virtio/virtio.h"
>          #include "exec/memory.h"
> 
>         +#define VHOST_F_DEVICE_IOTLB 63
>         +#define VHOST_USER_F_PROTOCOL_FEATURES 30
>         +
>          /* Generic structures common for any vhost based device. */
> 
>          struct vhost_inflight {
>         diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
>         index ef99a626a8..9df4e081c9 100644
>         --- a/include/hw/virtio/virtio.h
>         +++ b/include/hw/virtio/virtio.h
>         @@ -71,6 +71,25 @@ typedef struct VirtQueueElement
>          #define TYPE_VIRTIO_DEVICE "virtio-device"
>          OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
> 
>         +typedef struct {
>         +    int virtio_bit;
>         +    const char *feature_name;
>         +} qmp_virtio_feature_map_t;
>         +
>         +extern qmp_virtio_feature_map_t serial_map[];
>         +extern qmp_virtio_feature_map_t blk_map[];
>         +extern qmp_virtio_feature_map_t gpu_map[];
>         +extern qmp_virtio_feature_map_t net_map[];
>         +extern qmp_virtio_feature_map_t scsi_map[];
>         +extern qmp_virtio_feature_map_t balloon_map[];
>         +extern qmp_virtio_feature_map_t iommu_map[];
>         +extern qmp_virtio_feature_map_t input_map[];
>         +extern qmp_virtio_feature_map_t fs_map[];
>         +extern qmp_virtio_feature_map_t vsock_map[];
>         +extern qmp_virtio_feature_map_t crypto_map[];
>         +extern qmp_virtio_feature_map_t mem_map[];
>         +extern qmp_virtio_feature_map_t i2c_map[];
>         +
> 
> 
>     So this hack where extern is in a common header, but the
>     actual values are spread in individual C files is not really
>     acceptable.
> 
> Understood. Will move these map definitions into virtio.c
> instead.
> 
> 
>     Also, the names are too generic and are not prefixed with
>     virtio which is a problem for a generic virtio.h header.
>     this kind of name is only ok as a static variable.
> 
> No problem, I can change them to something like
> 'virtio_x_feature_map'.
> 
> 
>     And, it seems to be causing problems when some devices
>     are disabled at config time. E.g. with virtio gpu disabled
>     we get:
> 
>     https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276202__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvABmkhnR$
>     https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276291__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvK89VWxr$
> 
>     libqemu-ppc64-softmmu.fa.p/hw_virtio_virtio.c.o: In function `qmp_decode_features':
>     /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
>     /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
> 
> 
>     I could not figure it out from a quick look, please debug.
> 
> Got it, will debug. May be missing an #ifdef somewhere I suspect...
> 
> It will take some time for me to get the next series (v15) out since
> I'll be away next week but hopefully I'll be able to get them out sooner
> rather than later once I'm back.
> 
> Thanks,
> 
> Jonah
> 
> 
> 
> 
>          enum virtio_device_endian {
>              VIRTIO_DEVICE_ENDIAN_UNKNOWN,
>              VIRTIO_DEVICE_ENDIAN_LITTLE,
>         diff --git a/qapi/virtio.json b/qapi/virtio.json
>         index ba61d83df7..474a8bd64e 100644
>         --- a/qapi/virtio.json
>         +++ b/qapi/virtio.json
>         @@ -106,10 +106,10 @@
>                      'n-tmp-sections': 'int',
>                      'nvqs': 'uint32',
>                      'vq-index': 'int',
>         -            'features': 'uint64',
>         -            'acked-features': 'uint64',
>         -            'backend-features': 'uint64',
>         -            'protocol-features': 'uint64',
>         +            'features': 'VirtioDeviceFeatures',
>         +            'acked-features': 'VirtioDeviceFeatures',
>         +            'backend-features': 'VirtioDeviceFeatures',
>         +            'protocol-features': 'VhostDeviceProtocols',
>                      'max-queues': 'uint64',
>                      'backend-cap': 'uint64',
>                      'log-enabled': 'bool',
>         @@ -176,11 +176,11 @@
>                      'device-id': 'uint16',
>                      'vhost-started': 'bool',
>                      'device-endian': 'str',
>         -            'guest-features': 'uint64',
>         -            'host-features': 'uint64',
>         -            'backend-features': 'uint64',
>         +            'guest-features': 'VirtioDeviceFeatures',
>         +            'host-features': 'VirtioDeviceFeatures',
>         +            'backend-features': 'VirtioDeviceFeatures',
>                      'num-vqs': 'int',
>         -            'status': 'uint8',
>         +            'status': 'VirtioDeviceStatus',
>                      'isr': 'uint8',
>                      'queue-sel': 'uint16',
>                      'vm-running': 'bool',
>         @@ -222,14 +222,28 @@
>          #            "name": "virtio-crypto",
>          #            "started": true,
>          #            "device-id": 20,
>         -#            "backend-features": 0,
>         +#            "backend-features": {
>         +#               "transports": [],
>         +#               "dev-features": []
>         +#            },
>          #            "start-on-kick": false,
>          #            "isr": 1,
>          #            "broken": false,
>         -#            "status": 15,
>         +#            "status": {
>         +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
>         +#                            "DRIVER_OK"]
>         +#            },
>          #            "num-vqs": 2,
>         -#            "guest-features": 5100273664,
>         -#            "host-features": 6325010432,
>         +#            "guest-features": {
>         +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>         +#               "dev-features": []
>         +#            },
>         +#            "host-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>         +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>         +#                              "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": []
>         +#            },
>          #            "use-guest-notifier-mask": true,
>          #            "vm-running": true,
>          #            "queue-sel": 1,
>         @@ -257,22 +271,65 @@
>          #               "max-queues": 1,
>          #               "backend-cap": 2,
>          #               "log-size": 0,
>         -#               "backend-features": 0,
>         +#               "backend-features": {
>         +#                  "transports": [],
>         +#                  "dev-features": []
>         +#               },
>          #               "nvqs": 2,
>         -#               "protocol-features": 0,
>         +#               "protocol-features": {
>         +#                  "protocols": []
>         +#               },
>          #               "vq-index": 0,
>          #               "log-enabled": false,
>         -#               "acked-features": 5100306432,
>         -#               "features": 13908344832
>         +#               "acked-features": {
>         +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
>         +#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>         +#                  "dev-features": ["MRG_RXBUF"]
>         +#               },
>         +#               "features": {
>         +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
>         +#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
>         +#                                 "NOTIFY_ON_EMPTY"],
>         +#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
>         +#               }
>         +#            },
>         +#            "backend-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
>         +#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
>         +#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>         +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
>         +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
>         +#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>          #            },
>         -#            "backend-features": 6337593319,
>          #            "start-on-kick": false,
>          #            "isr": 1,
>          #            "broken": false,
>         -#            "status": 15,
>         +#            "status": {
>         +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
>         +#            },
>          #            "num-vqs": 3,
>         -#            "guest-features": 5111807911,
>         -#            "host-features": 6337593319,
>         +#            "guest-features": {
>         +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>         +#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
>         +#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>         +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
>         +#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
>         +#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
>         +#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>         +#            },
>         +#            "host-features": {
>         +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>         +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>         +#                              "NOTIFY_ON_EMPTY"],
>         +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
>         +#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
>         +#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
>         +#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
>         +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
>         +#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
>         +#                                "GUEST_CSUM", "CSUM"]
>         +#            },
>          #            "use-guest-notifier-mask": true,
>          #            "vm-running": true,
>          #            "queue-sel": 2,
>         @@ -288,3 +345,62 @@
>            'data': { 'path': 'str' },
>            'returns': 'VirtioStatus',
>            'features': [ 'unstable' ] }
>         +
>         +##
>         +# @VirtioDeviceStatus:
>         +#
>         +# A structure defined to list the configuration statuses of a virtio
>         +# device
>         +#
>         +# @statuses: List of decoded configuration statuses of the virtio
>         +#            device
>         +#
>         +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VirtioDeviceStatus',
>         +  'data': { 'statuses': [ 'str' ],
>         +            '*unknown-statuses': 'uint8' } }
>         +
>         +##
>         +# @VhostDeviceProtocols:
>         +#
>         +# A structure defined to list the vhost user protocol features of a
>         +# Vhost User device
>         +#
>         +# @protocols: List of decoded vhost user protocol features of a vhost
>         +#             user device
>         +#
>         +# @unknown-protocols: Vhost user device protocol features bitmap that
>         +#                     have not been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VhostDeviceProtocols',
>         +  'data': { 'protocols': [ 'str' ],
>         +            '*unknown-protocols': 'uint64' } }
>         +
>         +##
>         +# @VirtioDeviceFeatures:
>         +#
>         +# The common fields that apply to most Virtio devices. Some devices
>         +# may not have their own device-specific features (e.g. virtio-rng).
>         +#
>         +# @transports: List of transport features of the virtio device
>         +#
>         +# @dev-features: List of device-specific features (if the device has
>         +#                unique features)
>         +#
>         +# @unknown-dev-features: Virtio device features bitmap that have not
>         +#                        been decoded
>         +#
>         +# Since: 7.0
>         +##
>         +
>         +{ 'struct': 'VirtioDeviceFeatures',
>         +  'data': { 'transports': [ 'str' ],
>         +            '*dev-features': [ 'str' ],
>         +            '*unknown-dev-features': 'uint64' } }
>         --
>         2.35.1
> 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status
  2022-06-10  5:41       ` Michael S. Tsirkin
@ 2022-06-13 14:43         ` Jonah Palmer
  0 siblings, 0 replies; 15+ messages in thread
From: Jonah Palmer @ 2022-06-13 14:43 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: qemu-devel, boris.ostrovsky, si-wei.liu, joao.m.martins,
	qemu-block, groug, qemu_oss, stefanha, lvivier, mathieu.poirier,
	arei.gonglei, eric.auger, kraxel, dgilbert, david,
	marcandre.lureau, armbru, michael.roth, eblake, thuth, pbonzini,
	kwolf, raphael.norwitz

[-- Attachment #1: Type: text/plain, Size: 52238 bytes --]


On 6/10/22 01:41, Michael S. Tsirkin wrote:
> On Thu, May 19, 2022 at 02:30:43AM -0400, Jonah Palmer wrote:
>> On 5/16/22 16:26, Michael S. Tsirkin wrote:
>>
>>      On Fri, Apr 01, 2022 at 09:23:22AM -0400, Jonah Palmer wrote:
>>
>>          From: Laurent Vivier<lvivier@redhat.com>
>>
>>          Display feature names instead of bitmaps for host, guest, and
>>          backend for VirtIODevices.
>>
>>          Display status names instead of bitmaps for VirtIODevices.
>>
>>          Display feature names instead of bitmaps for backend, protocol,
>>          acked, and features (hdev->features) for vhost devices.
>>
>>          Decode features according to device ID. Decode statuses
>>          according to configuration status bitmap (config_status_map).
>>          Decode vhost user protocol features according to vhost user
>>          protocol bitmap (vhost_user_protocol_map).
>>
>>          Transport features are on the first line. Undecoded bits (if
>>          any) are stored in a separate field.
>>
>>          Signed-off-by: Jonah Palmer<jonah.palmer@oracle.com>
>>
>>
>>      So this has several problems that I missed previously.
>>      First, sign off from poster is missing.
>>
>> My apologies, will add missing Laurent's SOB in correct order for
>> patches 3-8.
>
> Were you going to repost?

Yes, and sorry for the delay. Trying to get these out ASAP.

Jonah

>
>>
>>
>>
>>          ---
>>           hw/block/virtio-blk.c          |  29 ++++
>>           hw/char/virtio-serial-bus.c    |  11 ++
>>           hw/display/virtio-gpu.c        |  18 ++
>>           hw/input/virtio-input.c        |  10 ++
>>           hw/net/virtio-net.c            |  47 +++++
>>           hw/scsi/virtio-scsi.c          |  17 ++
>>           hw/virtio/vhost-user-fs.c      |  10 ++
>>           hw/virtio/vhost-user-i2c.c     |  14 ++
>>           hw/virtio/vhost-vsock-common.c |  10 ++
>>           hw/virtio/virtio-balloon.c     |  14 ++
>>           hw/virtio/virtio-crypto.c      |  10 ++
>>           hw/virtio/virtio-iommu.c       |  14 ++
>>           hw/virtio/virtio-mem.c         |  11 ++
>>           hw/virtio/virtio.c             | 302 ++++++++++++++++++++++++++++++++-
>>           include/hw/virtio/vhost.h      |   3 +
>>           include/hw/virtio/virtio.h     |  19 +++
>>           qapi/virtio.json               | 156 ++++++++++++++---
>>           17 files changed, 667 insertions(+), 28 deletions(-)
>>
>>          diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
>>          index 27c71ad316..f104603040 100644
>>          --- a/hw/block/virtio-blk.c
>>          +++ b/hw/block/virtio-blk.c
>>          @@ -13,6 +13,7 @@
>>
>>           #include "qemu/osdep.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/iov.h"
>>           #include "qemu/module.h"
>>           #include "qemu/error-report.h"
>>          @@ -33,10 +34,38 @@
>>           #include "migration/qemu-file-types.h"
>>           #include "hw/virtio/virtio-access.h"
>>           #include "qemu/coroutine.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>
>>           /* Config size before the discard support (hide associated config fields) */
>>           #define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
>>                                                max_discard_sectors)
>>          +
>>          +qmp_virtio_feature_map_t blk_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_BLK_F_##name, #name }
>>          +    FEATURE_ENTRY(SIZE_MAX),
>>          +    FEATURE_ENTRY(SEG_MAX),
>>          +    FEATURE_ENTRY(GEOMETRY),
>>          +    FEATURE_ENTRY(RO),
>>          +    FEATURE_ENTRY(BLK_SIZE),
>>          +    FEATURE_ENTRY(TOPOLOGY),
>>          +    FEATURE_ENTRY(MQ),
>>          +    FEATURE_ENTRY(DISCARD),
>>          +    FEATURE_ENTRY(WRITE_ZEROES),
>>          +#ifndef VIRTIO_BLK_NO_LEGACY
>>          +    FEATURE_ENTRY(BARRIER),
>>          +    FEATURE_ENTRY(SCSI),
>>          +    FEATURE_ENTRY(FLUSH),
>>          +    FEATURE_ENTRY(CONFIG_WCE),
>>          +#endif /* !VIRTIO_BLK_NO_LEGACY */
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           /*
>>            * Starting from the discard feature, we can use this array to properly
>>            * set the config size depending on the features enabled.
>>          diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
>>          index 7d4601cb5d..fbb31a2b16 100644
>>          --- a/hw/char/virtio-serial-bus.c
>>          +++ b/hw/char/virtio-serial-bus.c
>>          @@ -20,6 +20,7 @@
>>
>>           #include "qemu/osdep.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/iov.h"
>>           #include "qemu/main-loop.h"
>>           #include "qemu/module.h"
>>          @@ -32,6 +33,16 @@
>>           #include "hw/virtio/virtio-serial.h"
>>           #include "hw/virtio/virtio-access.h"
>>
>>          +qmp_virtio_feature_map_t serial_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_CONSOLE_F_##name, #name }
>>          +    FEATURE_ENTRY(SIZE),
>>          +    FEATURE_ENTRY(MULTIPORT),
>>          +    FEATURE_ENTRY(EMERG_WRITE),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           static struct VirtIOSerialDevices {
>>               QLIST_HEAD(, VirtIOSerial) devices;
>>           } vserdevices;
>>          diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
>>          index 529b5246b2..0bd5dc6232 100644
>>          --- a/hw/display/virtio-gpu.c
>>          +++ b/hw/display/virtio-gpu.c
>>          @@ -29,10 +29,28 @@
>>           #include "qemu/log.h"
>>           #include "qemu/module.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/error-report.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>
>>           #define VIRTIO_GPU_VM_VERSION 1
>>
>>          +qmp_virtio_feature_map_t gpu_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_GPU_F_##name, #name }
>>          +    FEATURE_ENTRY(VIRGL),
>>          +    FEATURE_ENTRY(EDID),
>>          +    FEATURE_ENTRY(RESOURCE_UUID),
>>          +    FEATURE_ENTRY(RESOURCE_BLOB),
>>          +    FEATURE_ENTRY(CONTEXT_INIT),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>
>>
>>      Now I had some experience with this, the trick makes it
>>      harder to find where is a given macro used, and at the same
>>      time saves very little. Also should a macro name change, we
>>      do not want the name to change.
>>      Let's just keep it simple please.
>>      Plain array of macros and strings with no tricks.
>>
>> Sure thing. Should I define the macro outside of the map
>> definition? E.g:
>>
>> #define FEATURE_ENTRY(name) { ##name, #name }
>> qmp_virtio_feature_map_t virtio_gpu_feature_map[] = {
>>      FEATURE_ENTRY(VIRTIO_GPU_F_VIRGL),
>>      FEATURE_ENTRY(VIRTIO_GPU_F_EDID),
>>      ...
>>      { -1, "" }
>> };
>>
>> Also, is that what you were thinking as a "plain array of macros
>> and strings"? Or was there something more simple you had in mind?
>>
>>
>>
>>
>>           static struct virtio_gpu_simple_resource*
>>           virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
>>           static struct virtio_gpu_simple_resource *
>>          diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
>>          index 5b5398b3ca..fe0ed6d5b4 100644
>>          --- a/hw/input/virtio-input.c
>>          +++ b/hw/input/virtio-input.c
>>          @@ -6,6 +6,7 @@
>>
>>           #include "qemu/osdep.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/iov.h"
>>           #include "qemu/module.h"
>>           #include "trace.h"
>>          @@ -14,10 +15,19 @@
>>           #include "hw/qdev-properties.h"
>>           #include "hw/virtio/virtio-input.h"
>>
>>          +#include "standard-headers/linux/vhost_types.h"
>>           #include "standard-headers/linux/input.h"
>>
>>           #define VIRTIO_INPUT_VM_VERSION 1
>>
>>          +qmp_virtio_feature_map_t input_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           /* ----------------------------------------------------------------- */
>>
>>           void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
>>          diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>>          index 027ce40c6f..9356958fb6 100644
>>          --- a/hw/net/virtio-net.c
>>          +++ b/hw/net/virtio-net.c
>>          @@ -35,9 +35,11 @@
>>           #include "hw/qdev-properties.h"
>>           #include "qapi/qapi-types-migration.h"
>>           #include "qapi/qapi-events-migration.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "hw/virtio/virtio-access.h"
>>           #include "migration/misc.h"
>>           #include "standard-headers/linux/ethtool.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>           #include "sysemu/sysemu.h"
>>           #include "trace.h"
>>           #include "monitor/qdev.h"
>>          @@ -90,6 +92,51 @@
>>                                                    VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
>>                                                    VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
>>
>>          +qmp_virtio_feature_map_t net_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_NET_F_##name, #name }
>>          +    FEATURE_ENTRY(CSUM),
>>          +    FEATURE_ENTRY(GUEST_CSUM),
>>          +    FEATURE_ENTRY(CTRL_GUEST_OFFLOADS),
>>          +    FEATURE_ENTRY(MTU),
>>          +    FEATURE_ENTRY(MAC),
>>          +    FEATURE_ENTRY(GUEST_TSO4),
>>          +    FEATURE_ENTRY(GUEST_TSO6),
>>          +    FEATURE_ENTRY(GUEST_ECN),
>>          +    FEATURE_ENTRY(GUEST_UFO),
>>          +    FEATURE_ENTRY(HOST_TSO4),
>>          +    FEATURE_ENTRY(HOST_TSO6),
>>          +    FEATURE_ENTRY(HOST_ECN),
>>          +    FEATURE_ENTRY(HOST_UFO),
>>          +    FEATURE_ENTRY(MRG_RXBUF),
>>          +    FEATURE_ENTRY(STATUS),
>>          +    FEATURE_ENTRY(CTRL_VQ),
>>          +    FEATURE_ENTRY(CTRL_RX),
>>          +    FEATURE_ENTRY(CTRL_VLAN),
>>          +    FEATURE_ENTRY(CTRL_RX_EXTRA),
>>          +    FEATURE_ENTRY(GUEST_ANNOUNCE),
>>          +    FEATURE_ENTRY(MQ),
>>          +    FEATURE_ENTRY(CTRL_MAC_ADDR),
>>          +    FEATURE_ENTRY(HASH_REPORT),
>>          +    FEATURE_ENTRY(RSS),
>>          +    FEATURE_ENTRY(RSC_EXT),
>>          +    FEATURE_ENTRY(STANDBY),
>>          +    FEATURE_ENTRY(SPEED_DUPLEX),
>>          +#ifndef VIRTIO_NET_NO_LEGACY
>>          +    FEATURE_ENTRY(GSO),
>>          +#endif /* VIRTIO_NET_NO_LEGACY */
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_NET_F_##name, #name }
>>          +    FEATURE_ENTRY(VIRTIO_NET_HDR),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           static const VirtIOFeature feature_sizes[] = {
>>               {.flags = 1ULL << VIRTIO_NET_F_MAC,
>>                .end = endof(struct virtio_net_config, mac)},
>>          diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
>>          index 2a6141d081..9ca8faa40e 100644
>>          --- a/hw/scsi/virtio-scsi.c
>>          +++ b/hw/scsi/virtio-scsi.c
>>          @@ -15,7 +15,9 @@
>>
>>           #include "qemu/osdep.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "standard-headers/linux/virtio_ids.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>           #include "hw/virtio/virtio-scsi.h"
>>           #include "migration/qemu-file-types.h"
>>           #include "qemu/error-report.h"
>>          @@ -29,6 +31,21 @@
>>           #include "hw/virtio/virtio-access.h"
>>           #include "trace.h"
>>
>>          +qmp_virtio_feature_map_t scsi_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_SCSI_F_##name, #name }
>>          +    FEATURE_ENTRY(INOUT),
>>          +    FEATURE_ENTRY(HOTPLUG),
>>          +    FEATURE_ENTRY(CHANGE),
>>          +    FEATURE_ENTRY(T10_PI),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           static inline int virtio_scsi_get_lun(uint8_t *lun)
>>           {
>>               return ((lun[2] << 8) | lun[3]) & 0x3FFF;
>>          diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
>>          index e513e4fdda..096cc07c44 100644
>>          --- a/hw/virtio/vhost-user-fs.c
>>          +++ b/hw/virtio/vhost-user-fs.c
>>          @@ -15,6 +15,7 @@
>>           #include <sys/ioctl.h>
>>           #include "standard-headers/linux/virtio_fs.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "hw/qdev-properties.h"
>>           #include "hw/qdev-properties-system.h"
>>           #include "hw/virtio/virtio-bus.h"
>>          @@ -23,6 +24,15 @@
>>           #include "hw/virtio/vhost-user-fs.h"
>>           #include "monitor/monitor.h"
>>           #include "sysemu/sysemu.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>          +
>>          +qmp_virtio_feature_map_t fs_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>
>>           static const int user_feature_bits[] = {
>>               VIRTIO_F_VERSION_1,
>>          diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c
>>          index 6020eee093..931ec9836c 100644
>>          --- a/hw/virtio/vhost-user-i2c.c
>>          +++ b/hw/virtio/vhost-user-i2c.c
>>          @@ -8,11 +8,25 @@
>>
>>           #include "qemu/osdep.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "hw/qdev-properties.h"
>>           #include "hw/virtio/virtio-bus.h"
>>           #include "hw/virtio/vhost-user-i2c.h"
>>           #include "qemu/error-report.h"
>>           #include "standard-headers/linux/virtio_ids.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>          +
>>          +qmp_virtio_feature_map_t i2c_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_I2C_F_##name, #name }
>>          +    FEATURE_ENTRY(ZERO_LENGTH_REQUEST),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>
>>           static const int feature_bits[] = {
>>               VIRTIO_I2C_F_ZERO_LENGTH_REQUEST,
>>          diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c
>>          index 7394818e00..b03f94d8f8 100644
>>          --- a/hw/virtio/vhost-vsock-common.c
>>          +++ b/hw/virtio/vhost-vsock-common.c
>>          @@ -11,12 +11,22 @@
>>           #include "qemu/osdep.h"
>>           #include "standard-headers/linux/virtio_vsock.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "hw/virtio/virtio-access.h"
>>           #include "qemu/error-report.h"
>>           #include "hw/qdev-properties.h"
>>           #include "hw/virtio/vhost-vsock.h"
>>           #include "qemu/iov.h"
>>           #include "monitor/monitor.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>          +
>>          +qmp_virtio_feature_map_t vsock_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>
>>           const int feature_bits[] = {
>>               VIRTIO_VSOCK_F_SEQPACKET,
>>          diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
>>          index 193ff5261c..b2ae0a4d8c 100644
>>          --- a/hw/virtio/virtio-balloon.c
>>          +++ b/hw/virtio/virtio-balloon.c
>>          @@ -28,6 +28,7 @@
>>           #include "qapi/error.h"
>>           #include "qapi/qapi-events-machine.h"
>>           #include "qapi/visitor.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "trace.h"
>>           #include "qemu/error-report.h"
>>           #include "migration/misc.h"
>>          @@ -38,6 +39,19 @@
>>
>>           #define BALLOON_PAGE_SIZE  (1 << VIRTIO_BALLOON_PFN_SHIFT)
>>
>>          +qmp_virtio_feature_map_t balloon_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_BALLOON_F_##name, #name }
>>          +    FEATURE_ENTRY(MUST_TELL_HOST),
>>          +    FEATURE_ENTRY(STATS_VQ),
>>          +    FEATURE_ENTRY(DEFLATE_ON_OOM),
>>          +    FEATURE_ENTRY(FREE_PAGE_HINT),
>>          +    FEATURE_ENTRY(PAGE_POISON),
>>          +    FEATURE_ENTRY(REPORTING),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           typedef struct PartiallyBalloonedPage {
>>               ram_addr_t base_gpa;
>>               unsigned long *bitmap;
>>          diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
>>          index 947a11c3af..5c9a3d045d 100644
>>          --- a/hw/virtio/virtio-crypto.c
>>          +++ b/hw/virtio/virtio-crypto.c
>>          @@ -16,6 +16,7 @@
>>           #include "qemu/main-loop.h"
>>           #include "qemu/module.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/error-report.h"
>>
>>           #include "hw/virtio/virtio.h"
>>          @@ -23,10 +24,19 @@
>>           #include "hw/qdev-properties.h"
>>           #include "hw/virtio/virtio-access.h"
>>           #include "standard-headers/linux/virtio_ids.h"
>>          +#include "standard-headers/linux/vhost_types.h"
>>           #include "sysemu/cryptodev-vhost.h"
>>
>>           #define VIRTIO_CRYPTO_VM_VERSION 1
>>
>>          +qmp_virtio_feature_map_t crypto_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_F_##name, #name }
>>          +    FEATURE_ENTRY(LOG_ALL),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           /*
>>            * Transfer virtqueue index to crypto queue index.
>>            * The control virtqueue is after the data virtqueues
>>          diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
>>          index 4ed5bb16ba..d993106d10 100644
>>          --- a/hw/virtio/virtio-iommu.c
>>          +++ b/hw/virtio/virtio-iommu.c
>>          @@ -26,6 +26,7 @@
>>           #include "sysemu/kvm.h"
>>           #include "sysemu/reset.h"
>>           #include "qapi/error.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "qemu/error-report.h"
>>           #include "trace.h"
>>
>>          @@ -41,6 +42,19 @@
>>           #define VIOMMU_DEFAULT_QUEUE_SIZE 256
>>           #define VIOMMU_PROBE_SIZE 512
>>
>>          +qmp_virtio_feature_map_t iommu_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_IOMMU_F_##name, #name }
>>          +    FEATURE_ENTRY(INPUT_RANGE),
>>          +    FEATURE_ENTRY(DOMAIN_RANGE),
>>          +    FEATURE_ENTRY(MAP_UNMAP),
>>          +    FEATURE_ENTRY(BYPASS),
>>          +    FEATURE_ENTRY(PROBE),
>>          +    FEATURE_ENTRY(MMIO),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           typedef struct VirtIOIOMMUDomain {
>>               uint32_t id;
>>               bool bypass;
>>          diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
>>          index 465a996214..31e7af834e 100644
>>          --- a/hw/virtio/virtio-mem.c
>>          +++ b/hw/virtio/virtio-mem.c
>>          @@ -25,6 +25,7 @@
>>           #include "hw/virtio/virtio-mem.h"
>>           #include "qapi/error.h"
>>           #include "qapi/visitor.h"
>>          +#include "qapi/qapi-visit-virtio.h"
>>           #include "exec/ram_addr.h"
>>           #include "migration/misc.h"
>>           #include "hw/boards.h"
>>          @@ -32,6 +33,16 @@
>>           #include CONFIG_DEVICES
>>           #include "trace.h"
>>
>>          +qmp_virtio_feature_map_t mem_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_MEM_F_##name, #name }
>>          +#ifndef CONFIG_ACPI
>>          +    FEATURE_ENTRY(ACPI_PXM),
>>          +#endif /* CONFIG_ACPI */
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           /*
>>            * We only had legacy x86 guests that did not support
>>            * VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE. Other targets don't have legacy guests.
>>          diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>>          index 7f8eb29ced..af376be933 100644
>>          --- a/hw/virtio/virtio.c
>>          +++ b/hw/virtio/virtio.c
>>          @@ -34,10 +34,99 @@
>>           #include "sysemu/dma.h"
>>           #include "sysemu/runstate.h"
>>           #include "standard-headers/linux/virtio_ids.h"
>>          +#include "standard-headers/linux/vhost_types.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
>>          +
>>          +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
>>          +};
>>          +
>>          +static qmp_virtio_feature_map_t transport_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_F_##name, #name }
>>          +#ifndef VIRTIO_CONFIG_NO_LEGACY
>>          +    FEATURE_ENTRY(NOTIFY_ON_EMPTY),
>>          +    FEATURE_ENTRY(ANY_LAYOUT),
>>          +#endif /* VIRTIO_CONFIG_NO_LEGACY */
>>          +    FEATURE_ENTRY(VERSION_1),
>>          +    FEATURE_ENTRY(IOMMU_PLATFORM),
>>          +    FEATURE_ENTRY(RING_PACKED),
>>          +    FEATURE_ENTRY(ORDER_PLATFORM),
>>          +    FEATURE_ENTRY(SR_IOV),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VIRTIO_RING_F_##name, #name }
>>          +    FEATURE_ENTRY(INDIRECT_DESC),
>>          +    FEATURE_ENTRY(EVENT_IDX),
>>          +#undef FEATURE_ENTRY
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_USER_F_##name, #name }
>>          +    FEATURE_ENTRY(PROTOCOL_FEATURES),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>          +static qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
>>          +#define FEATURE_ENTRY(name) \
>>          +    { VHOST_USER_PROTOCOL_F_##name, #name }
>>          +    FEATURE_ENTRY(MQ),
>>          +    FEATURE_ENTRY(LOG_SHMFD),
>>          +    FEATURE_ENTRY(RARP),
>>          +    FEATURE_ENTRY(REPLY_ACK),
>>          +    FEATURE_ENTRY(NET_MTU),
>>          +    FEATURE_ENTRY(SLAVE_REQ),
>>          +    FEATURE_ENTRY(CROSS_ENDIAN),
>>          +    FEATURE_ENTRY(CRYPTO_SESSION),
>>          +    FEATURE_ENTRY(PAGEFAULT),
>>          +    FEATURE_ENTRY(CONFIG),
>>          +    FEATURE_ENTRY(SLAVE_SEND_FD),
>>          +    FEATURE_ENTRY(HOST_NOTIFIER),
>>          +    FEATURE_ENTRY(INFLIGHT_SHMFD),
>>          +    FEATURE_ENTRY(RESET_DEVICE),
>>          +    FEATURE_ENTRY(INBAND_NOTIFICATIONS),
>>          +    FEATURE_ENTRY(CONFIGURE_MEM_SLOTS),
>>          +#undef FEATURE_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>          +/* virtio device configuration statuses */
>>          +static qmp_virtio_feature_map_t config_status_map[] = {
>>          +#define STATUS_ENTRY(name) \
>>          +    { VIRTIO_CONFIG_S_##name, #name }
>>          +    STATUS_ENTRY(DRIVER_OK),
>>          +    STATUS_ENTRY(FEATURES_OK),
>>          +    STATUS_ENTRY(DRIVER),
>>          +    STATUS_ENTRY(NEEDS_RESET),
>>          +    STATUS_ENTRY(FAILED),
>>          +    STATUS_ENTRY(ACKNOWLEDGE),
>>          +#undef STATUS_ENTRY
>>          +    { -1, "" }
>>          +};
>>          +
>>           /*
>>            * The alignment to use between consumer and producer parts of vring.
>>            * x86 pagesize again. This is the default, used by transports like PCI
>>          @@ -3962,6 +4051,196 @@ static VirtIODevice *virtio_device_find(const char *path)
>>               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_name); \
>>          +            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, 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, transport_map, 0, bitmap);
>>          +
>>          +    /* device features */
>>          +    switch (device_id) {
>>          +#ifdef CONFIG_VIRTIO_SERIAL
>>          +    case VIRTIO_ID_CONSOLE:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, serial_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_BLK
>>          +    case VIRTIO_ID_BLOCK:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, blk_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_GPU
>>          +    case VIRTIO_ID_GPU:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, gpu_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_NET
>>          +    case VIRTIO_ID_NET:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, net_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_SCSI
>>          +    case VIRTIO_ID_SCSI:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, scsi_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_BALLOON
>>          +    case VIRTIO_ID_BALLOON:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, balloon_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_IOMMU
>>          +    case VIRTIO_ID_IOMMU:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, iommu_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_INPUT
>>          +    case VIRTIO_ID_INPUT:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, input_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VHOST_USER_FS
>>          +    case VIRTIO_ID_FS:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, fs_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VHOST_VSOCK
>>          +    case VIRTIO_ID_VSOCK:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, vsock_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_CRYPTO
>>          +    case VIRTIO_ID_CRYPTO:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, crypto_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_MEM
>>          +    case VIRTIO_ID_MEM:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, mem_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +#ifdef CONFIG_VIRTIO_I2C_ADAPTER
>>          +    case VIRTIO_ID_I2C_ADAPTER:
>>          +        features->dev_features =
>>          +            CONVERT_FEATURES(strList, i2c_map, 0, bitmap);
>>          +        break;
>>          +#endif
>>          +    /* No features */
>>          +    case VIRTIO_ID_9P:
>>          +    case VIRTIO_ID_PMEM:
>>          +    case VIRTIO_ID_RNG:
>>          +    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;
>>          @@ -3977,9 +4256,12 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>               status->name = g_strdup(vdev->name);
>>               status->device_id = vdev->device_id;
>>               status->vhost_started = vdev->vhost_started;
>>          -    status->guest_features = vdev->guest_features;
>>          -    status->host_features = vdev->host_features;
>>          -    status->backend_features = vdev->backend_features;
>>          +    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:
>>          @@ -3994,7 +4276,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>               }
>>
>>               status->num_vqs = virtio_get_num_queues(vdev);
>>          -    status->status = vdev->status;
>>          +    status->status = qmp_decode_status(vdev->status);
>>               status->isr = vdev->isr;
>>               status->queue_sel = vdev->queue_sel;
>>               status->vm_running = vdev->vm_running;
>>          @@ -4017,10 +4299,14 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
>>                   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 = hdev->features;
>>          -        status->vhost_dev->acked_features = hdev->acked_features;
>>          -        status->vhost_dev->backend_features = hdev->backend_features;
>>          -        status->vhost_dev->protocol_features = hdev->protocol_features;
>>          +        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;
>>          diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
>>          index 58a73e7b7a..4aaa21faf6 100644
>>          --- a/include/hw/virtio/vhost.h
>>          +++ b/include/hw/virtio/vhost.h
>>          @@ -5,6 +5,9 @@
>>           #include "hw/virtio/virtio.h"
>>           #include "exec/memory.h"
>>
>>          +#define VHOST_F_DEVICE_IOTLB 63
>>          +#define VHOST_USER_F_PROTOCOL_FEATURES 30
>>          +
>>           /* Generic structures common for any vhost based device. */
>>
>>           struct vhost_inflight {
>>          diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
>>          index ef99a626a8..9df4e081c9 100644
>>          --- a/include/hw/virtio/virtio.h
>>          +++ b/include/hw/virtio/virtio.h
>>          @@ -71,6 +71,25 @@ typedef struct VirtQueueElement
>>           #define TYPE_VIRTIO_DEVICE "virtio-device"
>>           OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
>>
>>          +typedef struct {
>>          +    int virtio_bit;
>>          +    const char *feature_name;
>>          +} qmp_virtio_feature_map_t;
>>          +
>>          +extern qmp_virtio_feature_map_t serial_map[];
>>          +extern qmp_virtio_feature_map_t blk_map[];
>>          +extern qmp_virtio_feature_map_t gpu_map[];
>>          +extern qmp_virtio_feature_map_t net_map[];
>>          +extern qmp_virtio_feature_map_t scsi_map[];
>>          +extern qmp_virtio_feature_map_t balloon_map[];
>>          +extern qmp_virtio_feature_map_t iommu_map[];
>>          +extern qmp_virtio_feature_map_t input_map[];
>>          +extern qmp_virtio_feature_map_t fs_map[];
>>          +extern qmp_virtio_feature_map_t vsock_map[];
>>          +extern qmp_virtio_feature_map_t crypto_map[];
>>          +extern qmp_virtio_feature_map_t mem_map[];
>>          +extern qmp_virtio_feature_map_t i2c_map[];
>>          +
>>
>>
>>      So this hack where extern is in a common header, but the
>>      actual values are spread in individual C files is not really
>>      acceptable.
>>
>> Understood. Will move these map definitions into virtio.c
>> instead.
>>
>>
>>      Also, the names are too generic and are not prefixed with
>>      virtio which is a problem for a generic virtio.h header.
>>      this kind of name is only ok as a static variable.
>>
>> No problem, I can change them to something like
>> 'virtio_x_feature_map'.
>>
>>
>>      And, it seems to be causing problems when some devices
>>      are disabled at config time. E.g. with virtio gpu disabled
>>      we get:
>>
>>      https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276202__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvABmkhnR$
>>      https://urldefense.com/v3/__https://gitlab.com/qemu-project/qemu/-/jobs/2463276291__;!!ACWV5N9M2RV99hQ!LxUl7ygdoZjKT_zWfAfkcior1j2Bn4E5okOrtbudwWyRsmGyRMxMdQlIVhn5AhR7n6LHvK89VWxr$
>>
>>      libqemu-ppc64-softmmu.fa.p/hw_virtio_virtio.c.o: In function `qmp_decode_features':
>>      /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
>>      /builds/qemu-project/qemu/build/../hw/virtio/virtio.c:4167: undefined reference to `gpu_map'
>>
>>
>>      I could not figure it out from a quick look, please debug.
>>
>> Got it, will debug. May be missing an #ifdef somewhere I suspect...
>>
>> It will take some time for me to get the next series (v15) out since
>> I'll be away next week but hopefully I'll be able to get them out sooner
>> rather than later once I'm back.
>>
>> Thanks,
>>
>> Jonah
>>
>>
>>
>>
>>           enum virtio_device_endian {
>>               VIRTIO_DEVICE_ENDIAN_UNKNOWN,
>>               VIRTIO_DEVICE_ENDIAN_LITTLE,
>>          diff --git a/qapi/virtio.json b/qapi/virtio.json
>>          index ba61d83df7..474a8bd64e 100644
>>          --- a/qapi/virtio.json
>>          +++ b/qapi/virtio.json
>>          @@ -106,10 +106,10 @@
>>                       'n-tmp-sections': 'int',
>>                       'nvqs': 'uint32',
>>                       'vq-index': 'int',
>>          -            'features': 'uint64',
>>          -            'acked-features': 'uint64',
>>          -            'backend-features': 'uint64',
>>          -            'protocol-features': 'uint64',
>>          +            'features': 'VirtioDeviceFeatures',
>>          +            'acked-features': 'VirtioDeviceFeatures',
>>          +            'backend-features': 'VirtioDeviceFeatures',
>>          +            'protocol-features': 'VhostDeviceProtocols',
>>                       'max-queues': 'uint64',
>>                       'backend-cap': 'uint64',
>>                       'log-enabled': 'bool',
>>          @@ -176,11 +176,11 @@
>>                       'device-id': 'uint16',
>>                       'vhost-started': 'bool',
>>                       'device-endian': 'str',
>>          -            'guest-features': 'uint64',
>>          -            'host-features': 'uint64',
>>          -            'backend-features': 'uint64',
>>          +            'guest-features': 'VirtioDeviceFeatures',
>>          +            'host-features': 'VirtioDeviceFeatures',
>>          +            'backend-features': 'VirtioDeviceFeatures',
>>                       'num-vqs': 'int',
>>          -            'status': 'uint8',
>>          +            'status': 'VirtioDeviceStatus',
>>                       'isr': 'uint8',
>>                       'queue-sel': 'uint16',
>>                       'vm-running': 'bool',
>>          @@ -222,14 +222,28 @@
>>           #            "name": "virtio-crypto",
>>           #            "started": true,
>>           #            "device-id": 20,
>>          -#            "backend-features": 0,
>>          +#            "backend-features": {
>>          +#               "transports": [],
>>          +#               "dev-features": []
>>          +#            },
>>           #            "start-on-kick": false,
>>           #            "isr": 1,
>>           #            "broken": false,
>>          -#            "status": 15,
>>          +#            "status": {
>>          +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK",
>>          +#                            "DRIVER_OK"]
>>          +#            },
>>           #            "num-vqs": 2,
>>          -#            "guest-features": 5100273664,
>>          -#            "host-features": 6325010432,
>>          +#            "guest-features": {
>>          +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>>          +#               "dev-features": []
>>          +#            },
>>          +#            "host-features": {
>>          +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>>          +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>>          +#                              "NOTIFY_ON_EMPTY"],
>>          +#               "dev-features": []
>>          +#            },
>>           #            "use-guest-notifier-mask": true,
>>           #            "vm-running": true,
>>           #            "queue-sel": 1,
>>          @@ -257,22 +271,65 @@
>>           #               "max-queues": 1,
>>           #               "backend-cap": 2,
>>           #               "log-size": 0,
>>          -#               "backend-features": 0,
>>          +#               "backend-features": {
>>          +#                  "transports": [],
>>          +#                  "dev-features": []
>>          +#               },
>>           #               "nvqs": 2,
>>          -#               "protocol-features": 0,
>>          +#               "protocol-features": {
>>          +#                  "protocols": []
>>          +#               },
>>           #               "vq-index": 0,
>>           #               "log-enabled": false,
>>          -#               "acked-features": 5100306432,
>>          -#               "features": 13908344832
>>          +#               "acked-features": {
>>          +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1",
>>          +#                                 "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>>          +#                  "dev-features": ["MRG_RXBUF"]
>>          +#               },
>>          +#               "features": {
>>          +#                  "transports": ["EVENT_IDX", "INDIRECT_DESC",
>>          +#                                 "IOMMU_PLATFORM", "VERSION_1", "ANY_LAYOUT",
>>          +#                                 "NOTIFY_ON_EMPTY"],
>>          +#                  "dev-features": ["LOG_ALL", "MRG_RXBUF"]
>>          +#               }
>>          +#            },
>>          +#            "backend-features": {
>>          +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX", "INDIRECT_DESC",
>>          +#                              "VERSION_1", "ANY_LAYOUT", "NOTIFY_ON_EMPTY"],
>>          +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_RX_EXTRA",
>>          +#                                "CTRL_VLAN", "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>>          +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6", "HOST_TSO4",
>>          +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6", "GUEST_TSO4",
>>          +#                                "MAC", "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>>           #            },
>>          -#            "backend-features": 6337593319,
>>           #            "start-on-kick": false,
>>           #            "isr": 1,
>>           #            "broken": false,
>>          -#            "status": 15,
>>          +#            "status": {
>>          +#               "statuses": ["ACKNOWLEDGE", "DRIVER", "FEATURES_OK", "DRIVER_OK"]
>>          +#            },
>>           #            "num-vqs": 3,
>>          -#            "guest-features": 5111807911,
>>          -#            "host-features": 6337593319,
>>          +#            "guest-features": {
>>          +#               "transports": ["EVENT_IDX", "INDIRECT_DESC", "VERSION_1"],
>>          +#               "dev-features": ["CTRL_MAC_ADDR", "GUEST_ANNOUNCE", "CTRL_VLAN",
>>          +#                                "CTRL_RX", "CTRL_VQ", "STATUS", "MRG_RXBUF",
>>          +#                                "HOST_UFO", "HOST_ECN", "HOST_TSO6",
>>          +#                                "HOST_TSO4", "GUEST_UFO", "GUEST_ECN",
>>          +#                                "GUEST_TSO6", "GUEST_TSO4", "MAC",
>>          +#                                "CTRL_GUEST_OFFLOADS", "GUEST_CSUM", "CSUM"]
>>          +#            },
>>          +#            "host-features": {
>>          +#               "transports": ["PROTOCOL_FEATURES", "EVENT_IDX",
>>          +#                              "INDIRECT_DESC", "VERSION_1", "ANY_LAYOUT",
>>          +#                              "NOTIFY_ON_EMPTY"],
>>          +#               "dev-features": ["GSO", "CTRL_MAC_ADDR", "GUEST_ANNOUNCE",
>>          +#                                "CTRL_RX_EXTRA", "CTRL_VLAN", "CTRL_RX",
>>          +#                                "CTRL_VQ", "STATUS", "MRG_RXBUF", "HOST_UFO",
>>          +#                                "HOST_ECN", "HOST_TSO4", "HOST_TSO4",
>>          +#                                "GUEST_UFO", "GUEST_ECN", "GUEST_TSO6",
>>          +#                                "GUEST_TSO4", "MAC", "CTRL_GUEST_OFFLOADS",
>>          +#                                "GUEST_CSUM", "CSUM"]
>>          +#            },
>>           #            "use-guest-notifier-mask": true,
>>           #            "vm-running": true,
>>           #            "queue-sel": 2,
>>          @@ -288,3 +345,62 @@
>>             'data': { 'path': 'str' },
>>             'returns': 'VirtioStatus',
>>             'features': [ 'unstable' ] }
>>          +
>>          +##
>>          +# @VirtioDeviceStatus:
>>          +#
>>          +# A structure defined to list the configuration statuses of a virtio
>>          +# device
>>          +#
>>          +# @statuses: List of decoded configuration statuses of the virtio
>>          +#            device
>>          +#
>>          +# @unknown-statuses: Virtio device statuses bitmap that have not been decoded
>>          +#
>>          +# Since: 7.0
>>          +##
>>          +
>>          +{ 'struct': 'VirtioDeviceStatus',
>>          +  'data': { 'statuses': [ 'str' ],
>>          +            '*unknown-statuses': 'uint8' } }
>>          +
>>          +##
>>          +# @VhostDeviceProtocols:
>>          +#
>>          +# A structure defined to list the vhost user protocol features of a
>>          +# Vhost User device
>>          +#
>>          +# @protocols: List of decoded vhost user protocol features of a vhost
>>          +#             user device
>>          +#
>>          +# @unknown-protocols: Vhost user device protocol features bitmap that
>>          +#                     have not been decoded
>>          +#
>>          +# Since: 7.0
>>          +##
>>          +
>>          +{ 'struct': 'VhostDeviceProtocols',
>>          +  'data': { 'protocols': [ 'str' ],
>>          +            '*unknown-protocols': 'uint64' } }
>>          +
>>          +##
>>          +# @VirtioDeviceFeatures:
>>          +#
>>          +# The common fields that apply to most Virtio devices. Some devices
>>          +# may not have their own device-specific features (e.g. virtio-rng).
>>          +#
>>          +# @transports: List of transport features of the virtio device
>>          +#
>>          +# @dev-features: List of device-specific features (if the device has
>>          +#                unique features)
>>          +#
>>          +# @unknown-dev-features: Virtio device features bitmap that have not
>>          +#                        been decoded
>>          +#
>>          +# Since: 7.0
>>          +##
>>          +
>>          +{ 'struct': 'VirtioDeviceFeatures',
>>          +  'data': { 'transports': [ 'str' ],
>>          +            '*dev-features': [ 'str' ],
>>          +            '*unknown-dev-features': 'uint64' } }
>>          --
>>          2.35.1
>>

[-- Attachment #2: Type: text/html, Size: 52651 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-06-13 14:46 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-01 13:23 [PATCH v14 0/8] hmp,qmp: Add commands to introspect virtio devices Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 1/8] virtio: drop name parameter for virtio_init() Jonah Palmer
2022-04-21 17:47   ` Dr. David Alan Gilbert
2022-04-01 13:23 ` [PATCH v14 2/8] virtio: add vhost support for virtio devices Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 3/8] qmp: add QMP command x-query-virtio Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 4/8] qmp: add QMP command x-query-virtio-status Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 5/8] qmp: decode feature & status bits in virtio-status Jonah Palmer
2022-05-16 20:26   ` Michael S. Tsirkin
2022-05-19  6:30     ` Jonah Palmer
2022-05-26 15:11       ` Michael S. Tsirkin
2022-06-10  5:41       ` Michael S. Tsirkin
2022-06-13 14:43         ` Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 6/8] qmp: add QMP commands for virtio/vhost queue-status Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 7/8] qmp: add QMP command x-query-virtio-queue-element Jonah Palmer
2022-04-01 13:23 ` [PATCH v14 8/8] hmp: add virtio commands Jonah Palmer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.