diff mbox series

[v8,3/8] qmp: add QMP command x-debug-query-virtio

Message ID 1635334909-31614-4-git-send-email-jonah.palmer@oracle.com (mailing list archive)
State New, archived
Headers show
Series hmp,qmp: Add commands to introspect virtio devices | expand

Commit Message

Jonah Palmer Oct. 27, 2021, 11:41 a.m. UTC
From: Laurent Vivier <lvivier@redhat.com>

This new command lists all the instances of VirtIODevice with
their QOM paths and virtio type/name.

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

Comments

Markus Armbruster Nov. 4, 2021, 3:15 p.m. UTC | #1
Jonah Palmer <jonah.palmer@oracle.com> writes:

> From: Laurent Vivier <lvivier@redhat.com>
>
> This new command lists all the instances of VirtIODevice with
> their QOM paths and virtio type/name.
>
> Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
> ---
>  hw/virtio/meson.build      |  2 ++
>  hw/virtio/virtio-stub.c    | 14 ++++++++++
>  hw/virtio/virtio.c         | 27 +++++++++++++++++++
>  include/hw/virtio/virtio.h |  1 +
>  qapi/meson.build           |  1 +
>  qapi/qapi-schema.json      |  1 +
>  qapi/virtio.json           | 67 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/qtest/qmp-cmd-test.c |  1 +
>  8 files changed, 114 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 521f7d6..d893f5f 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 0000000..d4a88f5
> --- /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_debug_query_virtio(Error **errp)
> +{
> +    return qmp_virtio_unsupported(errp);
> +}
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 7050bd5..ad17be7 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -13,6 +13,8 @@
>  
>  #include "qemu/osdep.h"
>  #include "qapi/error.h"
> +#include "qapi/qapi-commands-virtio.h"
> +#include "qapi/qapi-visit-virtio.h"
>  #include "cpu.h"
>  #include "trace.h"
>  #include "qemu/error-report.h"
> @@ -29,6 +31,9 @@
>  #include "sysemu/runstate.h"
>  #include "standard-headers/linux/virtio_ids.h"
>  
> +/* QAPI list of 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
> @@ -3709,6 +3714,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)
> @@ -3723,6 +3729,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;
>  }
> @@ -3896,6 +3903,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)
> @@ -3906,6 +3915,24 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
>      return virtio_bus_ioeventfd_enabled(vbus);
>  }
>  
> +VirtioInfoList *qmp_x_debug_query_virtio(Error **errp)
> +{
> +    VirtioInfoList *list = NULL;
> +    VirtioInfoList *node;
> +    VirtIODevice *vdev;
> +
> +    QTAILQ_FOREACH(vdev, &virtio_list, next) {
> +        DeviceState *dev = DEVICE(vdev);
> +        node = g_new0(VirtioInfoList, 1);
> +        node->value = g_new(VirtioInfo, 1);
> +        node->value->path = g_strdup(dev->canonical_path);
> +        node->value->type = g_strdup(vdev->name);
> +        QAPI_LIST_PREPEND(list, node->value);
> +    }
> +
> +    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 105b98c..eceaafc 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 c356a38..df5662e 100644
> --- a/qapi/meson.build
> +++ b/qapi/meson.build
> @@ -45,6 +45,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 4912b97..1512ada 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 0000000..4490c2c
> --- /dev/null
> +++ b/qapi/virtio.json
> @@ -0,0 +1,67 @@
> +# -*- Mode: Python -*-
> +# vim: filetype=python
> +#
> +
> +##
> +# = Virtio devices
> +##
> +
> +##
> +# @VirtioInfo:
> +#
> +# Basic information about a given VirtIODevice including the device
> +# canonical QOM path as well as the name of the device.

Is the part starting with "including" worth its keep?

> +#
> +# @path: VirtIO device canonical QOM path

I'd prefer "the device's canonical QOM path".

> +#
> +# @type: VirtIO device name
> +#
> +# Since: 6.2

If this series misses 6.2, which seems likely, you'll have to adjust the
since tags.

> +#
> +##
> +{ 'struct': 'VirtioInfo',
> +    'data': {
> +        'path': 'str',
> +        'type': 'str'
> +    }
> +}
> +
> +##
> +# @x-debug-query-virtio:
> +#
> +# Returns a list of all initalized VirtIO devices

What's an uninitialized VirtIO device?

> +#
> +# Returns: list of gathered @VirtioInfo devices
> +#
> +# Since: 6.2
> +#
> +# Example:
> +#
> +# -> { "execute": "x-debug-query-virtio" }
> +# <- { "return": [
> +#        {
> +#            "path": "/machine/peripheral-anon/device[4]/virtio-backend",
> +#            "type": "virtio-input"
> +#        },
> +#        {
> +#            "path": "/machine/peripheral/crypto0/virtio-backend",
> +#            "type": "virtio-crypto"
> +#        },
> +#        {
> +#            "path": "/machine/peripheral-anon/device[2]/virtio-backend",
> +#            "type": "virtio-scsi"
> +#        },
> +#        {
> +#            "path": "/machine/peripheral-anon/device[1]/virtio-backend",
> +#            "type": "virtio-net"
> +#        },
> +#        {
> +#            "path": "/machine/peripheral-anon/device[0]/virtio-backend",
> +#            "type": "virtio-serial"
> +#        }
> +#      ]
> +#    }
> +#
> +##
> +
> +{ 'command': 'x-debug-query-virtio', 'returns': ['VirtioInfo'] }
> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
> index 1af2f74..62c6cc4 100644
> --- a/tests/qtest/qmp-cmd-test.c
> +++ b/tests/qtest/qmp-cmd-test.c
> @@ -95,6 +95,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-debug-query-virtio",   /* CONFIG_VIRTIO */
>          /* Success depends on launching SEV guest */
>          "query-sev-launch-measure",
>          /* Success depends on Host or Hypervisor SEV support */
Jonah Palmer Nov. 5, 2021, 8:24 a.m. UTC | #2
On 11/4/21 11:15, Markus Armbruster wrote:
> Jonah Palmer<jonah.palmer@oracle.com>  writes:
>
>> From: Laurent Vivier<lvivier@redhat.com>
>>
>> This new command lists all the instances of VirtIODevice with
>> their QOM paths and virtio type/name.
>>
>> Signed-off-by: Jonah Palmer<jonah.palmer@oracle.com>
>> ---
>>   hw/virtio/meson.build      |  2 ++
>>   hw/virtio/virtio-stub.c    | 14 ++++++++++
>>   hw/virtio/virtio.c         | 27 +++++++++++++++++++
>>   include/hw/virtio/virtio.h |  1 +
>>   qapi/meson.build           |  1 +
>>   qapi/qapi-schema.json      |  1 +
>>   qapi/virtio.json           | 67 ++++++++++++++++++++++++++++++++++++++++++++++
>>   tests/qtest/qmp-cmd-test.c |  1 +
>>   8 files changed, 114 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 521f7d6..d893f5f 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 0000000..d4a88f5
>> --- /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_debug_query_virtio(Error **errp)
>> +{
>> +    return qmp_virtio_unsupported(errp);
>> +}
>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>> index 7050bd5..ad17be7 100644
>> --- a/hw/virtio/virtio.c
>> +++ b/hw/virtio/virtio.c
>> @@ -13,6 +13,8 @@
>>   
>>   #include "qemu/osdep.h"
>>   #include "qapi/error.h"
>> +#include "qapi/qapi-commands-virtio.h"
>> +#include "qapi/qapi-visit-virtio.h"
>>   #include "cpu.h"
>>   #include "trace.h"
>>   #include "qemu/error-report.h"
>> @@ -29,6 +31,9 @@
>>   #include "sysemu/runstate.h"
>>   #include "standard-headers/linux/virtio_ids.h"
>>   
>> +/* QAPI list of 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
>> @@ -3709,6 +3714,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)
>> @@ -3723,6 +3729,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;
>>   }
>> @@ -3896,6 +3903,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)
>> @@ -3906,6 +3915,24 @@ bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
>>       return virtio_bus_ioeventfd_enabled(vbus);
>>   }
>>   
>> +VirtioInfoList *qmp_x_debug_query_virtio(Error **errp)
>> +{
>> +    VirtioInfoList *list = NULL;
>> +    VirtioInfoList *node;
>> +    VirtIODevice *vdev;
>> +
>> +    QTAILQ_FOREACH(vdev, &virtio_list, next) {
>> +        DeviceState *dev = DEVICE(vdev);
>> +        node = g_new0(VirtioInfoList, 1);
>> +        node->value = g_new(VirtioInfo, 1);
>> +        node->value->path = g_strdup(dev->canonical_path);
>> +        node->value->type = g_strdup(vdev->name);
>> +        QAPI_LIST_PREPEND(list, node->value);
>> +    }
>> +
>> +    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 105b98c..eceaafc 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 c356a38..df5662e 100644
>> --- a/qapi/meson.build
>> +++ b/qapi/meson.build
>> @@ -45,6 +45,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 4912b97..1512ada 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 0000000..4490c2c
>> --- /dev/null
>> +++ b/qapi/virtio.json
>> @@ -0,0 +1,67 @@
>> +# -*- Mode: Python -*-
>> +# vim: filetype=python
>> +#
>> +
>> +##
>> +# = Virtio devices
>> +##
>> +
>> +##
>> +# @VirtioInfo:
>> +#
>> +# Basic information about a given VirtIODevice including the device
>> +# canonical QOM path as well as the name of the device.
> Is the part starting with "including" worth its keep?

Probably not. Sometimes I'm just unnecessarily verbose. Plus it's pretty
obvious once you look at the fields below. Will trim this.

>
>> +#
>> +# @path: VirtIO device canonical QOM path
> I'd prefer "the device's canonical QOM path".

Ok, will do!

>
>> +#
>> +# @type: VirtIO device name
>> +#
>> +# Since: 6.2
> If this series misses 6.2, which seems likely, you'll have to adjust the
> since tags.

Yup, will keep that in mind!

>
>> +#
>> +##
>> +{ 'struct': 'VirtioInfo',
>> +    'data': {
>> +        'path': 'str',
>> +        'type': 'str'
>> +    }
>> +}
>> +
>> +##
>> +# @x-debug-query-virtio:
>> +#
>> +# Returns a list of all initalized VirtIO devices
> What's an uninitialized VirtIO device?

Oops. I think this should really be "Returns a list of all realized
VirtIO devices". All devices that are realized are added to virtio_list
and all devices that unrealized are removed from virtio_list.

I'll change this to "Returns a list of all realized VirtIO devices".

>
>> +#
>> +# Returns: list of gathered @VirtioInfo devices
>> +#
>> +# Since: 6.2
>> +#
>> +# Example:
>> +#
>> +# -> { "execute": "x-debug-query-virtio" }
>> +# <- { "return": [
>> +#        {
>> +#            "path": "/machine/peripheral-anon/device[4]/virtio-backend",
>> +#            "type": "virtio-input"
>> +#        },
>> +#        {
>> +#            "path": "/machine/peripheral/crypto0/virtio-backend",
>> +#            "type": "virtio-crypto"
>> +#        },
>> +#        {
>> +#            "path": "/machine/peripheral-anon/device[2]/virtio-backend",
>> +#            "type": "virtio-scsi"
>> +#        },
>> +#        {
>> +#            "path": "/machine/peripheral-anon/device[1]/virtio-backend",
>> +#            "type": "virtio-net"
>> +#        },
>> +#        {
>> +#            "path": "/machine/peripheral-anon/device[0]/virtio-backend",
>> +#            "type": "virtio-serial"
>> +#        }
>> +#      ]
>> +#    }
>> +#
>> +##
>> +
>> +{ 'command': 'x-debug-query-virtio', 'returns': ['VirtioInfo'] }
>> diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
>> index 1af2f74..62c6cc4 100644
>> --- a/tests/qtest/qmp-cmd-test.c
>> +++ b/tests/qtest/qmp-cmd-test.c
>> @@ -95,6 +95,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-debug-query-virtio",   /* CONFIG_VIRTIO */
>>           /* Success depends on launching SEV guest */
>>           "query-sev-launch-measure",
>>           /* Success depends on Host or Hypervisor SEV support */
Jonah
diff mbox series

Patch

diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 521f7d6..d893f5f 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 0000000..d4a88f5
--- /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_debug_query_virtio(Error **errp)
+{
+    return qmp_virtio_unsupported(errp);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7050bd5..ad17be7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -13,6 +13,8 @@ 
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qapi/qapi-commands-virtio.h"
+#include "qapi/qapi-visit-virtio.h"
 #include "cpu.h"
 #include "trace.h"
 #include "qemu/error-report.h"
@@ -29,6 +31,9 @@ 
 #include "sysemu/runstate.h"
 #include "standard-headers/linux/virtio_ids.h"
 
+/* QAPI list of 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
@@ -3709,6 +3714,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)
@@ -3723,6 +3729,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;
 }
@@ -3896,6 +3903,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)
@@ -3906,6 +3915,24 @@  bool virtio_device_ioeventfd_enabled(VirtIODevice *vdev)
     return virtio_bus_ioeventfd_enabled(vbus);
 }
 
+VirtioInfoList *qmp_x_debug_query_virtio(Error **errp)
+{
+    VirtioInfoList *list = NULL;
+    VirtioInfoList *node;
+    VirtIODevice *vdev;
+
+    QTAILQ_FOREACH(vdev, &virtio_list, next) {
+        DeviceState *dev = DEVICE(vdev);
+        node = g_new0(VirtioInfoList, 1);
+        node->value = g_new(VirtioInfo, 1);
+        node->value->path = g_strdup(dev->canonical_path);
+        node->value->type = g_strdup(vdev->name);
+        QAPI_LIST_PREPEND(list, node->value);
+    }
+
+    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 105b98c..eceaafc 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 c356a38..df5662e 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -45,6 +45,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 4912b97..1512ada 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 0000000..4490c2c
--- /dev/null
+++ b/qapi/virtio.json
@@ -0,0 +1,67 @@ 
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+
+##
+# = Virtio devices
+##
+
+##
+# @VirtioInfo:
+#
+# Basic information about a given VirtIODevice including the device
+# canonical QOM path as well as the name of the device.
+#
+# @path: VirtIO device canonical QOM path
+#
+# @type: VirtIO device name
+#
+# Since: 6.2
+#
+##
+{ 'struct': 'VirtioInfo',
+    'data': {
+        'path': 'str',
+        'type': 'str'
+    }
+}
+
+##
+# @x-debug-query-virtio:
+#
+# Returns a list of all initalized VirtIO devices
+#
+# Returns: list of gathered @VirtioInfo devices
+#
+# Since: 6.2
+#
+# Example:
+#
+# -> { "execute": "x-debug-query-virtio" }
+# <- { "return": [
+#        {
+#            "path": "/machine/peripheral-anon/device[4]/virtio-backend",
+#            "type": "virtio-input"
+#        },
+#        {
+#            "path": "/machine/peripheral/crypto0/virtio-backend",
+#            "type": "virtio-crypto"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[2]/virtio-backend",
+#            "type": "virtio-scsi"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[1]/virtio-backend",
+#            "type": "virtio-net"
+#        },
+#        {
+#            "path": "/machine/peripheral-anon/device[0]/virtio-backend",
+#            "type": "virtio-serial"
+#        }
+#      ]
+#    }
+#
+##
+
+{ 'command': 'x-debug-query-virtio', 'returns': ['VirtioInfo'] }
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index 1af2f74..62c6cc4 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -95,6 +95,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-debug-query-virtio",   /* CONFIG_VIRTIO */
         /* Success depends on launching SEV guest */
         "query-sev-launch-measure",
         /* Success depends on Host or Hypervisor SEV support */