[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC v5 5/6] qmp: add QMP command x-debug-virtio-queue-element
From: |
Jonah Palmer |
Subject: |
[RFC v5 5/6] qmp: add QMP command x-debug-virtio-queue-element |
Date: |
Thu, 18 Mar 2021 12:29:43 -0400 |
From: Laurent Vivier <lvivier@redhat.com>
This new command shows the information of a VirtQueue element.
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Signed-off-by: Jonah Palmer <jonah.palmer@oracle.com>
---
hw/virtio/virtio-stub.c | 9 ++++
hw/virtio/virtio.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++
qapi/virtio.json | 94 +++++++++++++++++++++++++++++++++
3 files changed, 238 insertions(+)
diff --git a/hw/virtio/virtio-stub.c b/hw/virtio/virtio-stub.c
index 3c1bf17..8275e31 100644
--- a/hw/virtio/virtio-stub.c
+++ b/hw/virtio/virtio-stub.c
@@ -23,3 +23,12 @@ VirtQueueStatus *qmp_x_debug_virtio_queue_status(const char
*path,
{
return qmp_virtio_unsupported(errp);
}
+
+VirtioQueueElement *qmp_x_debug_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 d9b5734..735a6ae 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -4090,6 +4090,141 @@ VirtioStatus *qmp_x_debug_virtio_status(const char*
path, Error **errp)
return status;
}
+static VirtioRingDescFlagsList *qmp_decode_vring_desc_flags(uint16_t flags)
+{
+ VirtioRingDescFlagsList *list = NULL;
+ VirtioRingDescFlagsList *node;
+ int i;
+ struct {
+ uint16_t flag;
+ VirtioRingDescFlags value;
+ } map[] = {
+ { VRING_DESC_F_NEXT, VIRTIO_RING_DESC_FLAGS_NEXT },
+ { VRING_DESC_F_WRITE, VIRTIO_RING_DESC_FLAGS_WRITE },
+ { VRING_DESC_F_INDIRECT, VIRTIO_RING_DESC_FLAGS_INDIRECT },
+ { 1 << VRING_PACKED_DESC_F_AVAIL, VIRTIO_RING_DESC_FLAGS_AVAIL },
+ { 1 << VRING_PACKED_DESC_F_USED, VIRTIO_RING_DESC_FLAGS_USED },
+ { 0, -1 }
+ };
+
+ for (i = 0; map[i].flag; i++) {
+ if ((map[i].flag & flags) == 0) {
+ continue;
+ }
+ node = g_malloc0(sizeof(VirtioRingDescFlagsList));
+ node->value = map[i].value;
+ node->next = list;
+ list = node;
+ }
+
+ return list;
+}
+
+VirtioQueueElement *qmp_x_debug_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;
+
+ 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->index = head;
+ element->ndescs = 0;
+
+ do {
+ /* A buggy driver may produce an infinite loop */
+ if (element->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;
+
+ element->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 ab94263..3d4ba1f 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -504,3 +504,97 @@
'data': { 'path': 'str', 'queue': 'uint16' },
'returns': 'VirtQueueStatus'
}
+
+##
+# @VirtioRingDescFlags:
+#
+# An enumeration of the virtio ring descriptor flags
+#
+# Since: 6.0
+#
+##
+
+{ 'enum': 'VirtioRingDescFlags',
+ 'data': [ 'next', 'write', 'indirect', 'avail', 'used' ]
+}
+
+##
+# @VirtioRingDesc:
+#
+# @addr: guest physical address of the descriptor data
+#
+# @len: length of the descriptor data
+#
+# @flags: descriptor flags
+#
+# Since: 6.0
+#
+##
+
+{ 'struct': 'VirtioRingDesc',
+ 'data': {
+ 'addr': 'uint64',
+ 'len': 'uint32',
+ 'flags': [ 'VirtioRingDescFlags' ]
+ }
+}
+
+##
+# @VirtioQueueElement:
+#
+# @index: index of the element in the queue
+#
+# @ndescs: number of descriptors
+#
+# @descs: list of the descriptors
+#
+# Since: 6.0
+#
+##
+
+{ 'struct': 'VirtioQueueElement',
+ 'data': {
+ 'index': 'uint32',
+ 'ndescs': 'uint32',
+ 'descs': ['VirtioRingDesc']
+ }
+}
+
+##
+# @x-debug-virtio-queue-element:
+#
+# Return the information about an element queue (by default head)
+#
+# @path: QOBject path of the VirtIODevice
+#
+# @queue: queue number to examine
+#
+# @index: the index in the queue, by default head
+#
+# Returns: the element information
+#
+# Since: 6.0
+#
+# Example:
+#
+# -> { "execute": "x-debug-virtio-queue-element",
+# "arguments": {
+# "path": "/machine/peripheral-anon/device[3]/virtio-backend",
+# "queue": 0
+# }
+# }
+# -> { "return": {
+# "index": 24,
+# "ndescs": 1,
+# "descs": [
+# { "flags": ["write"], "len": 1536, "addr": 2027557376 }
+# ]
+# }
+# }
+#
+##
+
+{ 'command': 'x-debug-virtio-queue-element',
+ 'data': { 'path': 'str', 'queue': 'uint16', '*index': 'uint16' },
+ 'returns': 'VirtioQueueElement'
+}
--
1.8.3.1
- [RFC v5 0/6] hmp,qmp: Add some commands to introspect virtio deices, Jonah Palmer, 2021/03/18
- Re: [RFC v5 0/6] hmp, qmp: Add some commands to introspect virtio deices, no-reply, 2021/03/18
- [RFC v5 2/6] qmp: add QMP command x-debug-virtio-status, Jonah Palmer, 2021/03/18
- [RFC v5 5/6] qmp: add QMP command x-debug-virtio-queue-element,
Jonah Palmer <=
- [RFC v5 3/6] qmp: decode feature bits in virtio-status, Jonah Palmer, 2021/03/18
- [RFC v5 1/6] qmp: add QMP command x-debug-query-virtio, Jonah Palmer, 2021/03/18
- [RFC v5 6/6] hmp: add virtio commands, Jonah Palmer, 2021/03/18
- [RFC v5 4/6] qmp: add QMP command x-debug-virtio-queue-status, Jonah Palmer, 2021/03/18