Message ID | 20200507134800.10837-7-lvivier@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | hmp,qmp: Add some commands to introspect virtio devices | expand |
* Laurent Vivier (lvivier@redhat.com) wrote: > This patch implements HMP version of the virtio QMP commands > > Signed-off-by: Laurent Vivier <lvivier@redhat.com> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> With a thought below.... > --- > Makefile | 2 +- > Makefile.target | 7 +- > docs/system/monitor.rst | 2 + > hmp-commands-virtio.hx | 160 +++++++++++++++++++++++++++++++++ > hmp-commands.hx | 10 +++ > hw/virtio/virtio.c | 193 +++++++++++++++++++++++++++++++++++++++- > include/monitor/hmp.h | 4 + > monitor/misc.c | 17 ++++ > 8 files changed, 391 insertions(+), 4 deletions(-) > create mode 100644 hmp-commands-virtio.hx > > diff --git a/Makefile b/Makefile > index 34275f57c9cb..feb300ebb2d4 100644 > --- a/Makefile > +++ b/Makefile > @@ -1099,7 +1099,7 @@ $(MANUAL_BUILDDIR)/interop/index.html: $(call manual-deps,interop) > $(MANUAL_BUILDDIR)/specs/index.html: $(call manual-deps,specs) > $(call build-manual,specs,html) > > -$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx > +$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/hmp-commands-virtio.hx > $(call build-manual,system,html) > > $(MANUAL_BUILDDIR)/tools/index.html: $(call manual-deps,tools) $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc > diff --git a/Makefile.target b/Makefile.target > index 8ed1eba95b9c..66d3ff9bc350 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -171,7 +171,7 @@ else > obj-y += hw/$(TARGET_BASE_ARCH)/ > endif > > -generated-files-y += hmp-commands.h hmp-commands-info.h > +generated-files-y += hmp-commands.h hmp-commands-info.h hmp-commands-virtio.h > generated-files-y += config-devices.h > > endif # CONFIG_SOFTMMU > @@ -220,10 +220,13 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool > hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool > $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") > > +hmp-commands-virtio.h: $(SRC_PATH)/hmp-commands-virtio.hx $(SRC_PATH)/scripts/hxtool > + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") > + > clean: clean-target > rm -f *.a *~ $(PROGS) > rm -f $(shell find . -name '*.[od]') > - rm -f hmp-commands.h gdbstub-xml.c > + rm -f hmp-commands.h hmp-commands-virtio.h gdbstub-xml.c > rm -f trace/generated-helpers.c trace/generated-helpers.c-timestamp > ifdef CONFIG_TRACE_SYSTEMTAP > rm -f *.stp > diff --git a/docs/system/monitor.rst b/docs/system/monitor.rst > index 0bcd5da21644..985c3f51ffe7 100644 > --- a/docs/system/monitor.rst > +++ b/docs/system/monitor.rst > @@ -21,6 +21,8 @@ The following commands are available: > > .. hxtool-doc:: hmp-commands.hx > > +.. hxtool-doc:: hmp-commands-virtio.hx > + > .. hxtool-doc:: hmp-commands-info.hx > > Integer expressions > diff --git a/hmp-commands-virtio.hx b/hmp-commands-virtio.hx > new file mode 100644 > index 000000000000..14cb14bfcc70 > --- /dev/null > +++ b/hmp-commands-virtio.hx > @@ -0,0 +1,160 @@ > +HXCOMM Use DEFHEADING() to define headings in both help text and rST. > +HXCOMM Text between SRST and ERST is copied to the rST version and > +HXCOMM discarded from C version. > +HXCOMM DEF(command, args, callback, arg_string, help) is used to construct > +HXCOMM monitor info commands > +HXCOMM HXCOMM can be used for comments, discarded from both rST and C. > +HXCOMM > +HXCOMM In this file, generally SRST fragments should have two extra > +HXCOMM spaces of indent, so that the documentation list item for "x-debug-virtio cmd" > +HXCOMM appears inside the documentation list item for the top level > +HXCOMM "x-debug-virtio" documentation entry. The exception is the first SRST > +HXCOMM fragment that defines that top level entry. > + > +SRST > +``x-debug-virtio`` *subcommand* > + Show various information about virtio. > + > + Example: > + > + List all sub-commands:: > + > + (qemu) x-debug-virtio > + x-debug-virtio query -- List all available virtio devices > + x-debug-virtio status path -- Display status of a given virtio device > + x-debug-virtio queue-status path queue -- Display status of a given virtio queue > + x-debug-virtio queue-element path queue [index] -- Display element of a given virtio queue > + > +ERST > + > + { > + .name = "query", > + .args_type = "", > + .params = "", > + .help = "List all available virtio devices", > + .cmd = hmp_x_debug_virtio_query, > + .flags = "p", > + }, > + > +SRST > + ``x-debug-virtio query`` > + List all available virtio devices > + > + Example: > + > + List all available virtio devices in the machine:: > + > + (qemu) x-debug-virtio query > + /machine/peripheral-anon/device[3]/virtio-backend [virtio-net] > + /machine/peripheral-anon/device[1]/virtio-backend [virtio-serial] > + /machine/peripheral-anon/device[0]/virtio-backend [virtio-blk] > + > +ERST > + > + { > + .name = "status", > + .args_type = "path:s", > + .params = "path", > + .help = "Display status of a given virtio device", > + .cmd = hmp_x_debug_virtio_status, > + .flags = "p", > + }, > + > +SRST > + ``x-debug-virtio status`` *path* > + Display status of a given virtio device > + > + Example: > + > + Dump the status of the first virtio device:: > + > + (qemu) x-debug-virtio status /machine/peripheral-anon/device[3]/virtio-backend > + /machine/peripheral-anon/device[3]/virtio-backend: > + Device Id: 1 > + Guest features: event-idx, indirect-desc, version-1 > + 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: event-idx, indirect-desc, bad-feature, version-1, any-layout, notify-on-empty > + 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: > + Endianness: little > + VirtQueues: 3 > + > +ERST > + > + { > + .name = "queue-status", > + .args_type = "path:s,queue:i", > + .params = "path queue", > + .help = "Display status of a given virtio queue", > + .cmd = hmp_x_debug_virtio_queue_status, > + .flags = "p", > + }, > + > +SRST > + ``x-debug-virtio queue-status`` *path* *queue* > + Display status of a given virtio queue > + > + Example: > + > + Dump the status of the first queue of the first virtio device:: > + > + (qemu) x-debug-virtio queue-status /machine/peripheral-anon/device[3]/virtio-backend 0 > + /machine/peripheral-anon/device[3]/virtio-backend: > + index: 0 > + inuse: 0 > + last_avail_idx: 61 > + shadow_avail_idx: 292 > + signalled_used: 61 > + signalled_used_valid: 1 > + VRing: > + num: 256 > + num_default: 256 > + align: 4096 > + desc: 0x000000006c352000 > + avail: 0x000000006c353000 > + used: 0x000000006c353240 > + > +ERST > + > + { > + .name = "queue-element", > + .args_type = "path:s,queue:i,index:i?", > + .params = "path queue [index]", > + .help = "Display element of a given virtio queue", > + .cmd = hmp_x_debug_virtio_queue_element, > + .flags = "p", > + }, > + > +SRST > + ``x-debug-virtio queue-element`` *path* *queue* [*index*] > + Display element of a given virtio queue > + > + Example: > + > + Dump the information of the head element of the first queue of > + the first virtio device:: > + > + (qemu) x-debug-virtio queue-element/machine/peripheral-anon/device[3]/virtio-backend 0 > + index: 67 > + ndescs: 1 > + descs: addr 0x6fe69800 len 1536 (write) > + > + (qemu) xp/128bx 0x6fe69800 > + 000000006fe69800: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 > + 000000006fe69808: 0x00 0x00 0x01 0x00 0x52 0x54 0x00 0x12 > + 000000006fe69810: 0x34 0x56 0x52 0x54 0x00 0x09 0x51 0xde > + 000000006fe69818: 0x08 0x00 0x45 0x00 0x00 0x4c 0x8f 0x32 > + > + device[3] is a virtio-net device and we can see in the element buffer the > + MAC address of the card:: > + > + [root@localhost ~]# ip link show ens4 > + 2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP m0 > + link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff > + > + and the MAC address of the gateway:: > + > + [root@localhost ~]# arp -a > + _gateway (192.168.122.1) at 52:54:00:09:51:de [ether] on ens4 > + > +ERST > diff --git a/hmp-commands.hx b/hmp-commands.hx > index 7f0f3974ad90..777761dc48d7 100644 > --- a/hmp-commands.hx > +++ b/hmp-commands.hx > @@ -1804,6 +1804,16 @@ SRST > Set QOM property *property* of object at location *path* to value *value* > ERST > > + { > + .name = "x-debug-virtio", > + .args_type = "name:S?", > + .params = "[cmd]", > + .help = "show various information about virtio", > + .cmd = hmp_x_debug_virtio_help, > + .sub_table = hmp_x_debug_virtio_cmds, > + .flags = "p", > + }, > + > { > .name = "info", > .args_type = "item:s?", > diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > index 66dc2cef1b39..c3d6b783417e 100644 > --- a/hw/virtio/virtio.c > +++ b/hw/virtio/virtio.c > @@ -30,6 +30,9 @@ > #include "sysemu/dma.h" > #include "sysemu/runstate.h" > #include "config-devices.h" > +#include "monitor/hmp.h" > +#include "monitor/monitor.h" > +#include "qapi/qmp/qdict.h" > > static QTAILQ_HEAD(, VirtIODevice) virtio_list; > > @@ -3861,6 +3864,32 @@ VirtioInfoList *qmp_x_debug_query_virtio(Error **errp) > return list; > } > > +void hmp_x_debug_virtio_query(Monitor *mon, const QDict *qdict) > +{ > + Error *err = NULL; > + VirtioInfoList *list = qmp_x_debug_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, > + VirtioType_str(node->value->type)); > + node = node->next; > + } > + > + qapi_free_VirtioInfoList(list); > +} > + > static VirtIODevice *virtio_device_find(const char *path) > { > VirtIODevice *vdev; > @@ -3912,8 +3941,38 @@ VirtQueueStatus *qmp_x_debug_virtio_queue_status(const char *path, > return status; > } > > +void hmp_x_debug_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_debug_virtio_queue_status(path, queue, &err); > + > + if (err != NULL) { > + hmp_handle_error(mon, err); > + return; > + } > + monitor_printf(mon, "%s:\n", path); > + monitor_printf(mon, " index: %d\n", s->queue_index); > + monitor_printf(mon, " inuse: %d\n", s->inuse); > + monitor_printf(mon, " last_avail_idx: %d\n", s->last_avail_idx); > + monitor_printf(mon, " shadow_avail_idx: %d\n", s->shadow_avail_idx); > + monitor_printf(mon, " signalled_used: %d\n", s->signalled_used); > + monitor_printf(mon, " signalled_used_valid: %d\n", > + s->signalled_used_valid); > + monitor_printf(mon, " VRing:\n"); > + monitor_printf(mon, " num: %"PRId64"\n", s->vring_num); > + monitor_printf(mon, " num_default: %"PRId64"\n", s->vring_num_default); > + monitor_printf(mon, " align: %"PRId64"\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); > +} > + > #define CONVERT_FEATURES(type, map) \ > - ({ \ > + ({ \ > type *list = NULL; \ > type *node; \ > for (i = 0; map[i].virtio_bit != -1; i++) {\ > @@ -4033,6 +4092,92 @@ VirtioStatus *qmp_x_debug_virtio_status(const char* path, Error **errp) > return status; > } > > +#define DUMP_FEATURES(type, field) \ > + do { \ > + type##FeatureList *list = features->device->u.field.data; \ > + if (list) { \ > + monitor_printf(mon, " "); \ > + while (list) { \ > + monitor_printf(mon, "%s", type##Feature_str(list->value)); \ > + list = list->next; \ > + if (list != NULL) { \ > + monitor_printf(mon, ", "); \ > + } \ > + } \ > + monitor_printf(mon, "\n"); \ > + } \ > + } while (0) It feels like you should be able to have an array of Feature_str's indexed by VIRTIO_DEVICE_FEATURE_KIND_ enum, so that when a new VIRTIO_DEVICE_FEATURE_KIND is added you don't need to fix this up. Dave > + > +static void hmp_virtio_dump_features(Monitor *mon, > + VirtioStatusFeatures *features) > +{ > + VirtioTransportFeatureList *transport_list = features->transport; > + while (transport_list) { > + monitor_printf(mon, "%s", > + VirtioTransportFeature_str(transport_list->value)); > + transport_list = transport_list->next; > + if (transport_list != NULL) { > + monitor_printf(mon, ", "); > + } > + } > + monitor_printf(mon, "\n"); > + switch (features->device->type) { > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SERIAL: > + DUMP_FEATURES(VirtioSerial, virtio_serial); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BLK: > + DUMP_FEATURES(VirtioBlk, virtio_blk); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_GPU: > + DUMP_FEATURES(VirtioGpu, virtio_gpu); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_NET: > + DUMP_FEATURES(VirtioNet, virtio_net); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SCSI: > + DUMP_FEATURES(VirtioScsi, virtio_scsi); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BALLOON: > + DUMP_FEATURES(VirtioBalloon, virtio_balloon); > + break; > + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_IOMMU: > + DUMP_FEATURES(VirtioIommu, virtio_iommu); > + break; > + default: > + g_assert_not_reached(); > + } > + if (features->unknown) { > + monitor_printf(mon, " unknown(0x%016"PRIx64")\n", \ > + features->unknown); > + } > +} > + > +void hmp_x_debug_virtio_status(Monitor *mon, const QDict *qdict) > +{ > + Error *err = NULL; > + const char *path = qdict_get_try_str(qdict, "path"); > + VirtioStatus *s = qmp_x_debug_virtio_status(path, &err); > + > + if (err != NULL) { > + hmp_handle_error(mon, err); > + return; > + } > + > + monitor_printf(mon, "%s:\n", path); > + monitor_printf(mon, " Device Id: %"PRId64"\n", s->device_id); > + 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); > + monitor_printf(mon, " Endianness: %s\n", > + VirtioStatusEndianness_str(s->device_endian)); > + monitor_printf(mon, " VirtQueues: %d\n", s->num_vqs); > + > + qapi_free_VirtioStatus(s); > +} > + > static VirtioRingDescFlagsList *qmp_decode_vring_desc_flags(uint16_t flags) > { > VirtioRingDescFlagsList *list = NULL; > @@ -4163,6 +4308,52 @@ done: > return element; > } > > +void hmp_x_debug_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 *element; > + VirtioRingDescList *list; > + > + element = qmp_x_debug_virtio_queue_element(path, queue, index != -1, > + index, &err); > + if (err != NULL) { > + hmp_handle_error(mon, err); > + return; > + } > + > + monitor_printf(mon, "index: %d\n", element->index); > + monitor_printf(mon, "ndescs: %d\n", element->ndescs); > + monitor_printf(mon, "descs: "); > + > + list = element->descs; > + while (list) { > + monitor_printf(mon, "addr 0x%"PRIx64" len %d", list->value->addr, > + list->value->len); > + if (list->value->flags) { > + VirtioRingDescFlagsList *flag = list->value->flags; > + monitor_printf(mon, " ("); > + while (flag) { > + monitor_printf(mon, "%s", VirtioRingDescFlags_str(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"); > + > + qapi_free_VirtioQueueElement(element); > +} > + > static const TypeInfo virtio_device_info = { > .name = TYPE_VIRTIO_DEVICE, > .parent = TYPE_DEVICE, > diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h > index e33ca5a911a5..f07509985254 100644 > --- a/include/monitor/hmp.h > +++ b/include/monitor/hmp.h > @@ -98,6 +98,10 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict); > void hmp_qom_list(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_x_debug_virtio_query(Monitor *mon, const QDict *qdict); > +void hmp_x_debug_virtio_status(Monitor *mon, const QDict *qdict); > +void hmp_x_debug_virtio_queue_status(Monitor *mon, const QDict *qdict); > +void hmp_x_debug_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/misc.c b/monitor/misc.c > index 9723b466cda1..1a179829250d 100644 > --- a/monitor/misc.c > +++ b/monitor/misc.c > @@ -23,6 +23,7 @@ > */ > > #include "qemu/osdep.h" > +#include "config-devices.h" > #include "monitor-internal.h" > #include "cpu.h" > #include "monitor/qdev.h" > @@ -232,6 +233,15 @@ static void hmp_info_help(Monitor *mon, const QDict *qdict) > help_cmd(mon, "info"); > } > > +static void hmp_x_debug_virtio_help(Monitor *mon, const QDict *qdict) > +{ > +#if defined(CONFIG_VIRTIO) > + help_cmd(mon, "x-debug-virtio"); > +#else > + monitor_printf(mon, "Virtio is disabled\n"); > +#endif > +} > + > static void monitor_init_qmp_commands(void) > { > /* > @@ -1681,6 +1691,13 @@ static HMPCommand hmp_info_cmds[] = { > { NULL, NULL, }, > }; > > +static HMPCommand hmp_x_debug_virtio_cmds[] = { > +#if defined(CONFIG_VIRTIO) > +#include "hmp-commands-virtio.h" > +#endif > + { NULL, NULL, }, > +}; > + > /* hmp_cmds and hmp_info_cmds would be sorted at runtime */ > HMPCommand hmp_cmds[] = { > #include "hmp-commands.h" > -- > 2.26.2 > -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On 13/05/2020 12:51, Dr. David Alan Gilbert wrote: > * Laurent Vivier (lvivier@redhat.com) wrote: >> This patch implements HMP version of the virtio QMP commands >> >> Signed-off-by: Laurent Vivier <lvivier@redhat.com> > > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > > With a thought below.... > >> --- >> Makefile | 2 +- >> Makefile.target | 7 +- >> docs/system/monitor.rst | 2 + >> hmp-commands-virtio.hx | 160 +++++++++++++++++++++++++++++++++ >> hmp-commands.hx | 10 +++ >> hw/virtio/virtio.c | 193 +++++++++++++++++++++++++++++++++++++++- >> include/monitor/hmp.h | 4 + >> monitor/misc.c | 17 ++++ >> 8 files changed, 391 insertions(+), 4 deletions(-) >> create mode 100644 hmp-commands-virtio.hx >> ... >> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c >> index 66dc2cef1b39..c3d6b783417e 100644 >> --- a/hw/virtio/virtio.c >> +++ b/hw/virtio/virtio.c ... >> @@ -4033,6 +4092,92 @@ VirtioStatus *qmp_x_debug_virtio_status(const char* path, Error **errp) >> return status; >> } >> >> +#define DUMP_FEATURES(type, field) \ >> + do { \ >> + type##FeatureList *list = features->device->u.field.data; \ >> + if (list) { \ >> + monitor_printf(mon, " "); \ >> + while (list) { \ >> + monitor_printf(mon, "%s", type##Feature_str(list->value)); \ >> + list = list->next; \ >> + if (list != NULL) { \ >> + monitor_printf(mon, ", "); \ >> + } \ >> + } \ >> + monitor_printf(mon, "\n"); \ >> + } \ >> + } while (0) > > It feels like you should be able to have an array of Feature_str's > indexed by VIRTIO_DEVICE_FEATURE_KIND_ enum, so that when a new > VIRTIO_DEVICE_FEATURE_KIND is added you don't need to fix this up. I don't understand what you mean here. >> + >> +static void hmp_virtio_dump_features(Monitor *mon, >> + VirtioStatusFeatures *features) >> +{ >> + VirtioTransportFeatureList *transport_list = features->transport; >> + while (transport_list) { >> + monitor_printf(mon, "%s", >> + VirtioTransportFeature_str(transport_list->value)); >> + transport_list = transport_list->next; >> + if (transport_list != NULL) { >> + monitor_printf(mon, ", "); >> + } >> + } >> + monitor_printf(mon, "\n"); >> + switch (features->device->type) { >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SERIAL: >> + DUMP_FEATURES(VirtioSerial, virtio_serial); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BLK: >> + DUMP_FEATURES(VirtioBlk, virtio_blk); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_GPU: >> + DUMP_FEATURES(VirtioGpu, virtio_gpu); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_NET: >> + DUMP_FEATURES(VirtioNet, virtio_net); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SCSI: >> + DUMP_FEATURES(VirtioScsi, virtio_scsi); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BALLOON: >> + DUMP_FEATURES(VirtioBalloon, virtio_balloon); >> + break; >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_IOMMU: >> + DUMP_FEATURES(VirtioIommu, virtio_iommu); >> + break; >> + default: >> + g_assert_not_reached(); >> + } >> + if (features->unknown) { >> + monitor_printf(mon, " unknown(0x%016"PRIx64")\n", \ >> + features->unknown); >> + } >> +} ... Thanks, Laurent
* Laurent Vivier (lvivier@redhat.com) wrote: > On 13/05/2020 12:51, Dr. David Alan Gilbert wrote: > > * Laurent Vivier (lvivier@redhat.com) wrote: > >> This patch implements HMP version of the virtio QMP commands > >> > >> Signed-off-by: Laurent Vivier <lvivier@redhat.com> > > > > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > > > > With a thought below.... > > > >> --- > >> Makefile | 2 +- > >> Makefile.target | 7 +- > >> docs/system/monitor.rst | 2 + > >> hmp-commands-virtio.hx | 160 +++++++++++++++++++++++++++++++++ > >> hmp-commands.hx | 10 +++ > >> hw/virtio/virtio.c | 193 +++++++++++++++++++++++++++++++++++++++- > >> include/monitor/hmp.h | 4 + > >> monitor/misc.c | 17 ++++ > >> 8 files changed, 391 insertions(+), 4 deletions(-) > >> create mode 100644 hmp-commands-virtio.hx > >> > ... > >> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c > >> index 66dc2cef1b39..c3d6b783417e 100644 > >> --- a/hw/virtio/virtio.c > >> +++ b/hw/virtio/virtio.c > ... > >> @@ -4033,6 +4092,92 @@ VirtioStatus *qmp_x_debug_virtio_status(const char* path, Error **errp) > >> return status; > >> } > >> > >> +#define DUMP_FEATURES(type, field) \ > >> + do { \ > >> + type##FeatureList *list = features->device->u.field.data; \ > >> + if (list) { \ > >> + monitor_printf(mon, " "); \ > >> + while (list) { \ > >> + monitor_printf(mon, "%s", type##Feature_str(list->value)); \ > >> + list = list->next; \ > >> + if (list != NULL) { \ > >> + monitor_printf(mon, ", "); \ > >> + } \ > >> + } \ > >> + monitor_printf(mon, "\n"); \ > >> + } \ > >> + } while (0) > > > > It feels like you should be able to have an array of Feature_str's > > indexed by VIRTIO_DEVICE_FEATURE_KIND_ enum, so that when a new > > VIRTIO_DEVICE_FEATURE_KIND is added you don't need to fix this up. > > I don't understand what you mean here. Instead of the switch below, I'm thinking you could have something like: if (features->device->type < something_MAX) { features_str = anarray[features->device->type]; .... monitor_printf(mon, "%s", features_str(list->value)); .... } with 'anarray' somewhere more central, so we don't have to keep these switch structures and macros spread around. Dave > >> + > >> +static void hmp_virtio_dump_features(Monitor *mon, > >> + VirtioStatusFeatures *features) > >> +{ > >> + VirtioTransportFeatureList *transport_list = features->transport; > >> + while (transport_list) { > >> + monitor_printf(mon, "%s", > >> + VirtioTransportFeature_str(transport_list->value)); > >> + transport_list = transport_list->next; > >> + if (transport_list != NULL) { > >> + monitor_printf(mon, ", "); > >> + } > >> + } > >> + monitor_printf(mon, "\n"); > >> + switch (features->device->type) { > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SERIAL: > >> + DUMP_FEATURES(VirtioSerial, virtio_serial); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BLK: > >> + DUMP_FEATURES(VirtioBlk, virtio_blk); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_GPU: > >> + DUMP_FEATURES(VirtioGpu, virtio_gpu); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_NET: > >> + DUMP_FEATURES(VirtioNet, virtio_net); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SCSI: > >> + DUMP_FEATURES(VirtioScsi, virtio_scsi); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BALLOON: > >> + DUMP_FEATURES(VirtioBalloon, virtio_balloon); > >> + break; > >> + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_IOMMU: > >> + DUMP_FEATURES(VirtioIommu, virtio_iommu); > >> + break; > >> + default: > >> + g_assert_not_reached(); > >> + } > >> + if (features->unknown) { > >> + monitor_printf(mon, " unknown(0x%016"PRIx64")\n", \ > >> + features->unknown); > >> + } > >> +} > ... > > Thanks, > Laurent -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
On 15/05/2020 17:45, Dr. David Alan Gilbert wrote: > * Laurent Vivier (lvivier@redhat.com) wrote: >> On 13/05/2020 12:51, Dr. David Alan Gilbert wrote: >>> * Laurent Vivier (lvivier@redhat.com) wrote: >>>> This patch implements HMP version of the virtio QMP commands >>>> >>>> Signed-off-by: Laurent Vivier <lvivier@redhat.com> >>> >>> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> >>> >>> With a thought below.... >>> >>>> --- >>>> Makefile | 2 +- >>>> Makefile.target | 7 +- >>>> docs/system/monitor.rst | 2 + >>>> hmp-commands-virtio.hx | 160 +++++++++++++++++++++++++++++++++ >>>> hmp-commands.hx | 10 +++ >>>> hw/virtio/virtio.c | 193 +++++++++++++++++++++++++++++++++++++++- >>>> include/monitor/hmp.h | 4 + >>>> monitor/misc.c | 17 ++++ >>>> 8 files changed, 391 insertions(+), 4 deletions(-) >>>> create mode 100644 hmp-commands-virtio.hx >>>> >> ... >>>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c >>>> index 66dc2cef1b39..c3d6b783417e 100644 >>>> --- a/hw/virtio/virtio.c >>>> +++ b/hw/virtio/virtio.c >> ... >>>> @@ -4033,6 +4092,92 @@ VirtioStatus *qmp_x_debug_virtio_status(const char* path, Error **errp) >>>> return status; >>>> } >>>> >>>> +#define DUMP_FEATURES(type, field) \ >>>> + do { \ >>>> + type##FeatureList *list = features->device->u.field.data; \ >>>> + if (list) { \ >>>> + monitor_printf(mon, " "); \ >>>> + while (list) { \ >>>> + monitor_printf(mon, "%s", type##Feature_str(list->value)); \ >>>> + list = list->next; \ >>>> + if (list != NULL) { \ >>>> + monitor_printf(mon, ", "); \ >>>> + } \ >>>> + } \ >>>> + monitor_printf(mon, "\n"); \ >>>> + } \ >>>> + } while (0) >>> >>> It feels like you should be able to have an array of Feature_str's >>> indexed by VIRTIO_DEVICE_FEATURE_KIND_ enum, so that when a new >>> VIRTIO_DEVICE_FEATURE_KIND is added you don't need to fix this up. >> >> I don't understand what you mean here. > > Instead of the switch below, I'm thinking you could have something like: > > if (features->device->type < something_MAX) { > features_str = anarray[features->device->type]; > > .... > monitor_printf(mon, "%s", features_str(list->value)); > .... > } > > with 'anarray' somewhere more central, so we don't have to keep > these switch structures and macros spread around. OK, I tried that, but in fact we need to know the type of the list to be able to scan it (the "type##FeatureList": VirtoSerialFeatureList, VirtioBlkFeatureList, ...), except if we introduce a generic feature list node (for "next " and "value"). But it becomes more complicated, because we also need to generate the "anarray" somewhere. [Note: I've changed the legacy enum to a flat enum as proposed by Eric in v3] Thanks, Laurent
diff --git a/Makefile b/Makefile index 34275f57c9cb..feb300ebb2d4 100644 --- a/Makefile +++ b/Makefile @@ -1099,7 +1099,7 @@ $(MANUAL_BUILDDIR)/interop/index.html: $(call manual-deps,interop) $(MANUAL_BUILDDIR)/specs/index.html: $(call manual-deps,specs) $(call build-manual,specs,html) -$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx +$(MANUAL_BUILDDIR)/system/index.html: $(call manual-deps,system) $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/hmp-commands-virtio.hx $(call build-manual,system,html) $(MANUAL_BUILDDIR)/tools/index.html: $(call manual-deps,tools) $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/docs/qemu-option-trace.rst.inc diff --git a/Makefile.target b/Makefile.target index 8ed1eba95b9c..66d3ff9bc350 100644 --- a/Makefile.target +++ b/Makefile.target @@ -171,7 +171,7 @@ else obj-y += hw/$(TARGET_BASE_ARCH)/ endif -generated-files-y += hmp-commands.h hmp-commands-info.h +generated-files-y += hmp-commands.h hmp-commands-info.h hmp-commands-virtio.h generated-files-y += config-devices.h endif # CONFIG_SOFTMMU @@ -220,10 +220,13 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx $(SRC_PATH)/scripts/hxtool hmp-commands-info.h: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxtool $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") +hmp-commands-virtio.h: $(SRC_PATH)/hmp-commands-virtio.hx $(SRC_PATH)/scripts/hxtool + $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$(TARGET_DIR)$@") + clean: clean-target rm -f *.a *~ $(PROGS) rm -f $(shell find . -name '*.[od]') - rm -f hmp-commands.h gdbstub-xml.c + rm -f hmp-commands.h hmp-commands-virtio.h gdbstub-xml.c rm -f trace/generated-helpers.c trace/generated-helpers.c-timestamp ifdef CONFIG_TRACE_SYSTEMTAP rm -f *.stp diff --git a/docs/system/monitor.rst b/docs/system/monitor.rst index 0bcd5da21644..985c3f51ffe7 100644 --- a/docs/system/monitor.rst +++ b/docs/system/monitor.rst @@ -21,6 +21,8 @@ The following commands are available: .. hxtool-doc:: hmp-commands.hx +.. hxtool-doc:: hmp-commands-virtio.hx + .. hxtool-doc:: hmp-commands-info.hx Integer expressions diff --git a/hmp-commands-virtio.hx b/hmp-commands-virtio.hx new file mode 100644 index 000000000000..14cb14bfcc70 --- /dev/null +++ b/hmp-commands-virtio.hx @@ -0,0 +1,160 @@ +HXCOMM Use DEFHEADING() to define headings in both help text and rST. +HXCOMM Text between SRST and ERST is copied to the rST version and +HXCOMM discarded from C version. +HXCOMM DEF(command, args, callback, arg_string, help) is used to construct +HXCOMM monitor info commands +HXCOMM HXCOMM can be used for comments, discarded from both rST and C. +HXCOMM +HXCOMM In this file, generally SRST fragments should have two extra +HXCOMM spaces of indent, so that the documentation list item for "x-debug-virtio cmd" +HXCOMM appears inside the documentation list item for the top level +HXCOMM "x-debug-virtio" documentation entry. The exception is the first SRST +HXCOMM fragment that defines that top level entry. + +SRST +``x-debug-virtio`` *subcommand* + Show various information about virtio. + + Example: + + List all sub-commands:: + + (qemu) x-debug-virtio + x-debug-virtio query -- List all available virtio devices + x-debug-virtio status path -- Display status of a given virtio device + x-debug-virtio queue-status path queue -- Display status of a given virtio queue + x-debug-virtio queue-element path queue [index] -- Display element of a given virtio queue + +ERST + + { + .name = "query", + .args_type = "", + .params = "", + .help = "List all available virtio devices", + .cmd = hmp_x_debug_virtio_query, + .flags = "p", + }, + +SRST + ``x-debug-virtio query`` + List all available virtio devices + + Example: + + List all available virtio devices in the machine:: + + (qemu) x-debug-virtio query + /machine/peripheral-anon/device[3]/virtio-backend [virtio-net] + /machine/peripheral-anon/device[1]/virtio-backend [virtio-serial] + /machine/peripheral-anon/device[0]/virtio-backend [virtio-blk] + +ERST + + { + .name = "status", + .args_type = "path:s", + .params = "path", + .help = "Display status of a given virtio device", + .cmd = hmp_x_debug_virtio_status, + .flags = "p", + }, + +SRST + ``x-debug-virtio status`` *path* + Display status of a given virtio device + + Example: + + Dump the status of the first virtio device:: + + (qemu) x-debug-virtio status /machine/peripheral-anon/device[3]/virtio-backend + /machine/peripheral-anon/device[3]/virtio-backend: + Device Id: 1 + Guest features: event-idx, indirect-desc, version-1 + 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: event-idx, indirect-desc, bad-feature, version-1, any-layout, notify-on-empty + 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: + Endianness: little + VirtQueues: 3 + +ERST + + { + .name = "queue-status", + .args_type = "path:s,queue:i", + .params = "path queue", + .help = "Display status of a given virtio queue", + .cmd = hmp_x_debug_virtio_queue_status, + .flags = "p", + }, + +SRST + ``x-debug-virtio queue-status`` *path* *queue* + Display status of a given virtio queue + + Example: + + Dump the status of the first queue of the first virtio device:: + + (qemu) x-debug-virtio queue-status /machine/peripheral-anon/device[3]/virtio-backend 0 + /machine/peripheral-anon/device[3]/virtio-backend: + index: 0 + inuse: 0 + last_avail_idx: 61 + shadow_avail_idx: 292 + signalled_used: 61 + signalled_used_valid: 1 + VRing: + num: 256 + num_default: 256 + align: 4096 + desc: 0x000000006c352000 + avail: 0x000000006c353000 + used: 0x000000006c353240 + +ERST + + { + .name = "queue-element", + .args_type = "path:s,queue:i,index:i?", + .params = "path queue [index]", + .help = "Display element of a given virtio queue", + .cmd = hmp_x_debug_virtio_queue_element, + .flags = "p", + }, + +SRST + ``x-debug-virtio queue-element`` *path* *queue* [*index*] + Display element of a given virtio queue + + Example: + + Dump the information of the head element of the first queue of + the first virtio device:: + + (qemu) x-debug-virtio queue-element/machine/peripheral-anon/device[3]/virtio-backend 0 + index: 67 + ndescs: 1 + descs: addr 0x6fe69800 len 1536 (write) + + (qemu) xp/128bx 0x6fe69800 + 000000006fe69800: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 000000006fe69808: 0x00 0x00 0x01 0x00 0x52 0x54 0x00 0x12 + 000000006fe69810: 0x34 0x56 0x52 0x54 0x00 0x09 0x51 0xde + 000000006fe69818: 0x08 0x00 0x45 0x00 0x00 0x4c 0x8f 0x32 + + device[3] is a virtio-net device and we can see in the element buffer the + MAC address of the card:: + + [root@localhost ~]# ip link show ens4 + 2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP m0 + link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff + + and the MAC address of the gateway:: + + [root@localhost ~]# arp -a + _gateway (192.168.122.1) at 52:54:00:09:51:de [ether] on ens4 + +ERST diff --git a/hmp-commands.hx b/hmp-commands.hx index 7f0f3974ad90..777761dc48d7 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1804,6 +1804,16 @@ SRST Set QOM property *property* of object at location *path* to value *value* ERST + { + .name = "x-debug-virtio", + .args_type = "name:S?", + .params = "[cmd]", + .help = "show various information about virtio", + .cmd = hmp_x_debug_virtio_help, + .sub_table = hmp_x_debug_virtio_cmds, + .flags = "p", + }, + { .name = "info", .args_type = "item:s?", diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 66dc2cef1b39..c3d6b783417e 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -30,6 +30,9 @@ #include "sysemu/dma.h" #include "sysemu/runstate.h" #include "config-devices.h" +#include "monitor/hmp.h" +#include "monitor/monitor.h" +#include "qapi/qmp/qdict.h" static QTAILQ_HEAD(, VirtIODevice) virtio_list; @@ -3861,6 +3864,32 @@ VirtioInfoList *qmp_x_debug_query_virtio(Error **errp) return list; } +void hmp_x_debug_virtio_query(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + VirtioInfoList *list = qmp_x_debug_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, + VirtioType_str(node->value->type)); + node = node->next; + } + + qapi_free_VirtioInfoList(list); +} + static VirtIODevice *virtio_device_find(const char *path) { VirtIODevice *vdev; @@ -3912,8 +3941,38 @@ VirtQueueStatus *qmp_x_debug_virtio_queue_status(const char *path, return status; } +void hmp_x_debug_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_debug_virtio_queue_status(path, queue, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " index: %d\n", s->queue_index); + monitor_printf(mon, " inuse: %d\n", s->inuse); + monitor_printf(mon, " last_avail_idx: %d\n", s->last_avail_idx); + monitor_printf(mon, " shadow_avail_idx: %d\n", s->shadow_avail_idx); + monitor_printf(mon, " signalled_used: %d\n", s->signalled_used); + monitor_printf(mon, " signalled_used_valid: %d\n", + s->signalled_used_valid); + monitor_printf(mon, " VRing:\n"); + monitor_printf(mon, " num: %"PRId64"\n", s->vring_num); + monitor_printf(mon, " num_default: %"PRId64"\n", s->vring_num_default); + monitor_printf(mon, " align: %"PRId64"\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); +} + #define CONVERT_FEATURES(type, map) \ - ({ \ + ({ \ type *list = NULL; \ type *node; \ for (i = 0; map[i].virtio_bit != -1; i++) {\ @@ -4033,6 +4092,92 @@ VirtioStatus *qmp_x_debug_virtio_status(const char* path, Error **errp) return status; } +#define DUMP_FEATURES(type, field) \ + do { \ + type##FeatureList *list = features->device->u.field.data; \ + if (list) { \ + monitor_printf(mon, " "); \ + while (list) { \ + monitor_printf(mon, "%s", type##Feature_str(list->value)); \ + list = list->next; \ + if (list != NULL) { \ + monitor_printf(mon, ", "); \ + } \ + } \ + monitor_printf(mon, "\n"); \ + } \ + } while (0) + +static void hmp_virtio_dump_features(Monitor *mon, + VirtioStatusFeatures *features) +{ + VirtioTransportFeatureList *transport_list = features->transport; + while (transport_list) { + monitor_printf(mon, "%s", + VirtioTransportFeature_str(transport_list->value)); + transport_list = transport_list->next; + if (transport_list != NULL) { + monitor_printf(mon, ", "); + } + } + monitor_printf(mon, "\n"); + switch (features->device->type) { + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SERIAL: + DUMP_FEATURES(VirtioSerial, virtio_serial); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BLK: + DUMP_FEATURES(VirtioBlk, virtio_blk); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_GPU: + DUMP_FEATURES(VirtioGpu, virtio_gpu); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_NET: + DUMP_FEATURES(VirtioNet, virtio_net); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_SCSI: + DUMP_FEATURES(VirtioScsi, virtio_scsi); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_BALLOON: + DUMP_FEATURES(VirtioBalloon, virtio_balloon); + break; + case VIRTIO_DEVICE_FEATURES_KIND_VIRTIO_IOMMU: + DUMP_FEATURES(VirtioIommu, virtio_iommu); + break; + default: + g_assert_not_reached(); + } + if (features->unknown) { + monitor_printf(mon, " unknown(0x%016"PRIx64")\n", \ + features->unknown); + } +} + +void hmp_x_debug_virtio_status(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + const char *path = qdict_get_try_str(qdict, "path"); + VirtioStatus *s = qmp_x_debug_virtio_status(path, &err); + + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "%s:\n", path); + monitor_printf(mon, " Device Id: %"PRId64"\n", s->device_id); + 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); + monitor_printf(mon, " Endianness: %s\n", + VirtioStatusEndianness_str(s->device_endian)); + monitor_printf(mon, " VirtQueues: %d\n", s->num_vqs); + + qapi_free_VirtioStatus(s); +} + static VirtioRingDescFlagsList *qmp_decode_vring_desc_flags(uint16_t flags) { VirtioRingDescFlagsList *list = NULL; @@ -4163,6 +4308,52 @@ done: return element; } +void hmp_x_debug_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 *element; + VirtioRingDescList *list; + + element = qmp_x_debug_virtio_queue_element(path, queue, index != -1, + index, &err); + if (err != NULL) { + hmp_handle_error(mon, err); + return; + } + + monitor_printf(mon, "index: %d\n", element->index); + monitor_printf(mon, "ndescs: %d\n", element->ndescs); + monitor_printf(mon, "descs: "); + + list = element->descs; + while (list) { + monitor_printf(mon, "addr 0x%"PRIx64" len %d", list->value->addr, + list->value->len); + if (list->value->flags) { + VirtioRingDescFlagsList *flag = list->value->flags; + monitor_printf(mon, " ("); + while (flag) { + monitor_printf(mon, "%s", VirtioRingDescFlags_str(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"); + + qapi_free_VirtioQueueElement(element); +} + static const TypeInfo virtio_device_info = { .name = TYPE_VIRTIO_DEVICE, .parent = TYPE_DEVICE, diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index e33ca5a911a5..f07509985254 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -98,6 +98,10 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict); void hmp_qom_list(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_x_debug_virtio_query(Monitor *mon, const QDict *qdict); +void hmp_x_debug_virtio_status(Monitor *mon, const QDict *qdict); +void hmp_x_debug_virtio_queue_status(Monitor *mon, const QDict *qdict); +void hmp_x_debug_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/misc.c b/monitor/misc.c index 9723b466cda1..1a179829250d 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "config-devices.h" #include "monitor-internal.h" #include "cpu.h" #include "monitor/qdev.h" @@ -232,6 +233,15 @@ static void hmp_info_help(Monitor *mon, const QDict *qdict) help_cmd(mon, "info"); } +static void hmp_x_debug_virtio_help(Monitor *mon, const QDict *qdict) +{ +#if defined(CONFIG_VIRTIO) + help_cmd(mon, "x-debug-virtio"); +#else + monitor_printf(mon, "Virtio is disabled\n"); +#endif +} + static void monitor_init_qmp_commands(void) { /* @@ -1681,6 +1691,13 @@ static HMPCommand hmp_info_cmds[] = { { NULL, NULL, }, }; +static HMPCommand hmp_x_debug_virtio_cmds[] = { +#if defined(CONFIG_VIRTIO) +#include "hmp-commands-virtio.h" +#endif + { NULL, NULL, }, +}; + /* hmp_cmds and hmp_info_cmds would be sorted at runtime */ HMPCommand hmp_cmds[] = { #include "hmp-commands.h"
This patch implements HMP version of the virtio QMP commands Signed-off-by: Laurent Vivier <lvivier@redhat.com> --- Makefile | 2 +- Makefile.target | 7 +- docs/system/monitor.rst | 2 + hmp-commands-virtio.hx | 160 +++++++++++++++++++++++++++++++++ hmp-commands.hx | 10 +++ hw/virtio/virtio.c | 193 +++++++++++++++++++++++++++++++++++++++- include/monitor/hmp.h | 4 + monitor/misc.c | 17 ++++ 8 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 hmp-commands-virtio.hx