From nobody Mon Feb 9 23:00:58 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1644027708848179.48692600156608; Fri, 4 Feb 2022 18:21:48 -0800 (PST) Received: from localhost ([::1]:55166 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nGAhw-0001mG-43 for importer@patchew.org; Fri, 04 Feb 2022 21:21:48 -0500 Received: from eggs.gnu.org ([209.51.188.92]:50670) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nGA8i-0005AS-MP for qemu-devel@nongnu.org; Fri, 04 Feb 2022 20:45:26 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:39624) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nGA8V-0003h5-C6 for qemu-devel@nongnu.org; Fri, 04 Feb 2022 20:45:13 -0500 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-248-gyKF-hQGPKmpQt2PiVQFzw-1; Fri, 04 Feb 2022 20:45:09 -0500 Received: by mail-wr1-f70.google.com with SMTP id d14-20020adfa34e000000b001e306be1ec8so69299wrb.17 for ; Fri, 04 Feb 2022 17:45:09 -0800 (PST) Received: from redhat.com ([2a10:8005:331d:0:5c51:c095:613e:277c]) by smtp.gmail.com with ESMTPSA id h6sm11323689wmq.26.2022.02.04.17.45.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Feb 2022 17:45:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1644025510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=7oHwf0NYiJCKp5HOBO9BRKY/iEUjv1oAWKV79Qa6iUA=; b=ML7oQpW1MwksFCd21gm/MVkpLDDxj2DVe1QKvk8lto9bwL8rDXvVbc71h68FxKF6qb6p0X DIW7V4W7RinpZF4i48cqffd8D8NHRLDzIX86daEBMSAjJWib+0XRxPg+jAyzl3P4JZbReR Hq067iqAJP7IeSdp+VbwoHG0temG9kQ= X-MC-Unique: gyKF-hQGPKmpQt2PiVQFzw-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=7oHwf0NYiJCKp5HOBO9BRKY/iEUjv1oAWKV79Qa6iUA=; b=3jhbOw2Q7aIOrqMQoZOnJP2BHcQ92wTliBWov32jk5C7R2jz9ic1aXJk+C13OQGOOA W/Q9ES68k+gpSdhwK4Gctuyf53hCi7MJxnu1I/E8WjsclQfiF8ybqG17exSgrcuNewbn irYEFe52oEJlPWHNqWGewacjCByx80NIEv5fGD5aAJ5A2AylUhUhttOTAZUSY/v1mA5W MEYsPCW4NKw9clNxLh4aSlVA+VXffciKQKLens9tVxBJfQ8p3vicju6pqFM2TBB9/6my ydhI6nay+lbhSbXH4Fgmn5/7qMbpH5WIDMitz3YNPSyHqJViUxHTkwkssJxW18V7QBMB j6JA== X-Gm-Message-State: AOAM532YlBqZwMsaciJ3ujCrsfviHZ47GmYCWlxzDAVhywGdOr4P6OQx cyYHmeJ2QYezsaqYwlUckhQc7103N/5e3CvZwkYWrp3Gchy7sD8q6a8YMXIXgovGLZGuKRqDxIB PYLi/KXfZ/lhoaAGMmy8O/G7o9VywRT9ZrJVqEKko5xwAssdbjDwrXIZK4GgR X-Received: by 2002:adf:fa48:: with SMTP id y8mr1219142wrr.646.1644025507801; Fri, 04 Feb 2022 17:45:07 -0800 (PST) X-Google-Smtp-Source: ABdhPJyfcqDZBjjYH8qGRChWk//avs2UC2b1cR8usacGjWA/V0pkD34UbGyxPVudjohJ8N/PuK7tLQ== X-Received: by 2002:adf:fa48:: with SMTP id y8mr1219119wrr.646.1644025507490; Fri, 04 Feb 2022 17:45:07 -0800 (PST) Date: Fri, 4 Feb 2022 20:45:05 -0500 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Subject: [PULL 21/32] qmp: add QMP command x-query-virtio-queue-element Message-ID: <20220205014149.1189026-22-mst@redhat.com> References: <20220205014149.1189026-1-mst@redhat.com> MIME-Version: 1.0 In-Reply-To: <20220205014149.1189026-1-mst@redhat.com> X-Mailer: git-send-email 2.27.0.106.g8ac3dc51b1 X-Mutt-Fcc: =sent Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=mst@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=mst@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.092, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Peter Maydell , Eric Blake , Markus Armbruster , Jonah Palmer Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1644027710606100001 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Laurent Vivier 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 Message-Id: <1642678168-20447-8-git-send-email-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- qapi/virtio.json | 183 ++++++++++++++++++++++++++++++++++++++++ hw/virtio/virtio-stub.c | 9 ++ hw/virtio/virtio.c | 154 +++++++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+) diff --git a/qapi/virtio.json b/qapi/virtio.json index 44cc05ceeb..bb93d6df93 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 +# (default: head of the queue) +# +# @path: VirtIODevice canonical QOM path +# +# @queue: VirtQueue index to examine +# +# @index: Index of the element in 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-b= ackend", +# "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-b= ackend", +# "queue": 2 } +# } +# <- { "return": { +# "index": 19, +# "name": "virtio-scsi", +# "descs": [ +# { "flags": ["used", "indirect", "write"], "len": 409932794= 4, +# "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' ] } 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 c= har *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 8723a53b68..d45b8dd040 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -489,6 +489,19 @@ static inline void vring_used_write(VirtQueue *vq, VRi= ngUsedElem *uelem, address_space_cache_invalidate(&caches->used, pa, sizeof(VRingUsedElem= )); } =20 +/* Called within rcu_read_lock(). */ +static inline uint16_t vring_used_flags(VirtQueue *vq) +{ + VRingMemoryRegionCaches *caches =3D vring_get_region_caches(vq); + hwaddr pa =3D 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) { @@ -4415,6 +4428,147 @@ VirtQueueStatus *qmp_x_query_virtio_queue_status(co= nst char *path, return status; } =20 +static strList *qmp_decode_vring_desc_flags(uint16_t flags) +{ + strList *list =3D NULL; + strList *node; + int i; + + struct { + uint16_t flag; + const char *value; + } map[] =3D { + { 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 =3D 0; map[i].flag; i++) { + if ((map[i].flag & flags) =3D=3D 0) { + continue; + } + node =3D g_malloc0(sizeof(strList)); + node->value =3D g_strdup(map[i].value); + node->next =3D list; + list =3D 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 =3D NULL; + + vdev =3D virtio_device_find(path); + if (vdev =3D=3D NULL) { + error_setg(errp, "Path %s is not a VirtIO device", path); + return NULL; + } + + if (queue >=3D VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, queue))= { + error_setg(errp, "Invalid virtqueue number %d", queue); + return NULL; + } + vq =3D &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 =3D MEMORY_REGION_CACHE_INVA= LID; + MemoryRegionCache *desc_cache; + VRingDesc desc; + VirtioRingDescList *list =3D NULL; + VirtioRingDescList *node; + int rc; int ndescs; + + RCU_READ_LOCK_GUARD(); + + max =3D vq->vring.num; + + if (!has_index) { + head =3D vring_avail_ring(vq, vq->last_avail_idx % vq->vring.n= um); + } else { + head =3D vring_avail_ring(vq, index % vq->vring.num); + } + i =3D head; + + caches =3D 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 =3D &caches->desc; + vring_split_desc_read(vdev, &desc, desc_cache, i); + if (desc.flags & VRING_DESC_F_INDIRECT) { + int64_t len; + len =3D address_space_cache_init(&indirect_desc_cache, vdev->d= ma_as, + desc.addr, desc.len, false); + desc_cache =3D &indirect_desc_cache; + if (len < desc.len) { + error_setg(errp, "Cannot map indirect buffer"); + goto done; + } + + max =3D desc.len / sizeof(VRingDesc); + i =3D 0; + vring_split_desc_read(vdev, &desc, desc_cache, i); + } + + element =3D g_new0(VirtioQueueElement, 1); + element->avail =3D g_new0(VirtioRingAvail, 1); + element->used =3D g_new0(VirtioRingUsed, 1); + element->name =3D g_strdup(vdev->name); + element->index =3D head; + element->avail->flags =3D vring_avail_flags(vq); + element->avail->idx =3D vring_avail_idx(vq); + element->avail->ring =3D head; + element->used->flags =3D vring_used_flags(vq); + element->used->idx =3D vring_used_idx(vq); + ndescs =3D 0; + + do { + /* A buggy driver may produce an infinite loop */ + if (ndescs >=3D max) { + break; + } + node =3D g_new0(VirtioRingDescList, 1); + node->value =3D g_new0(VirtioRingDesc, 1); + node->value->addr =3D desc.addr; + node->value->len =3D desc.len; + node->value->flags =3D qmp_decode_vring_desc_flags(desc.flags); + node->next =3D list; + list =3D node; + + ndescs++; + rc =3D virtqueue_split_read_next_desc(vdev, &desc, desc_cache, + max, &i); + } while (rc =3D=3D VIRTQUEUE_READ_DESC_MORE); + element->descs =3D list; +done: + address_space_cache_destroy(&indirect_desc_cache); + } + + return element; +} + static const TypeInfo virtio_device_info =3D { .name =3D TYPE_VIRTIO_DEVICE, .parent =3D TYPE_DEVICE, --=20 MST