Browse Source

pc,virtio: features, tests, fixes, cleanups

virtio introspection
 new serial number opton for cxl
 vhost user blk dynamic config size
 virtio-gpio vhost user backend
 
 Tests fixes cleanups all over the place
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmNEVeoPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRph8YH+gMWpb5IglE0Q+H2JiQPBwB/Ghy1ohRKnOvZ
 lChB7+oy18o2xXRFTOXwG9Ijqsbdn0QMbU/r3NWxBuMzxDow012xiMDniJlJmcXw
 /4POOCSTKrIfzVBhsEErVSA9NwSE5cQKr1oiRBGIa9UdZfZ//v7s6SoP4vtyj8RZ
 UJVYVnMDtq/0PaN92IMs06lhqo/LkegE7gTGHMBf8Nvw4SgQoZgfPyp1eR+dKOhz
 lXNqqvTds9yt8yS65UWbuSrZ9d7GpCQf8nuyLaLaENHd6FQUVfmTTT37l2EKziwp
 PK0EwWMHeGkj7LHrylztradhE9xBlIW23ROP8wPdGZHmgLNHbC0=
 =20Zb
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

pc,virtio: features, tests, fixes, cleanups

virtio introspection
new serial number opton for cxl
vhost user blk dynamic config size
virtio-gpio vhost user backend

Tests fixes cleanups all over the place

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmNEVeoPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRph8YH+gMWpb5IglE0Q+H2JiQPBwB/Ghy1ohRKnOvZ
# lChB7+oy18o2xXRFTOXwG9Ijqsbdn0QMbU/r3NWxBuMzxDow012xiMDniJlJmcXw
# /4POOCSTKrIfzVBhsEErVSA9NwSE5cQKr1oiRBGIa9UdZfZ//v7s6SoP4vtyj8RZ
# UJVYVnMDtq/0PaN92IMs06lhqo/LkegE7gTGHMBf8Nvw4SgQoZgfPyp1eR+dKOhz
# lXNqqvTds9yt8yS65UWbuSrZ9d7GpCQf8nuyLaLaENHd6FQUVfmTTT37l2EKziwp
# PK0EwWMHeGkj7LHrylztradhE9xBlIW23ROP8wPdGZHmgLNHbC0=
# =20Zb
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 10 Oct 2022 13:27:06 EDT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (55 commits)
  x86: pci: acpi: consolidate PCI slots creation
  tests: acpi: update expected blobs
  x86: pci: acpi: reorder Device's _DSM method
  tests: acpi: whitelist pc/q35 DSDT before moving _ADR field
  tests: acpi: update expected blobs
  x86: pci: acpi: reorder Device's _ADR and _SUN fields
  tests: acpi: whitelist pc/q35 DSDT before moving _ADR field
  tests: acpi: update expected blobs
  x86: acpi: cleanup PCI device _DSM duplication
  tests: acpi: whitelist pc/q35 DSDT before switching _DSM to use ASUN
  tests: acpi: update expected blobs
  x86: acpi: _DSM: use Package to pass parameters
  acpi: x86: refactor PDSM method to reduce nesting
  tests: acpi: whitelist pc/q35 DSDT due to HPET AML move
  tests: acpi: update expected blobs after HPET move
  acpi: x86: deduplicate HPET AML building
  tests: acpi: whitelist pc/q35 DSDT due to HPET AML move
  hw/smbios: support for type 8 (port connector)
  pci: Sanity check mask argument to pci_set_*_by_mask()
  pci: Remove unused pci_get_*_by_mask() functions
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
pull/223/head
Stefan Hajnoczi 4 years ago
parent
commit
cdcb7dcb40
  1. 12
      MAINTAINERS
  2. 70
      hmp-commands-info.hx
  3. 5
      hw/arm/virt-acpi-build.c
  4. 4
      hw/block/meson.build
  5. 39
      hw/block/vhost-user-blk.c
  6. 39
      hw/block/virtio-blk-common.c
  7. 28
      hw/block/virtio-blk.c
  8. 302
      hw/i386/acpi-build.c
  9. 5
      hw/i386/intel_iommu.c
  10. 14
      hw/mem/cxl_type3.c
  11. 9
      hw/net/virtio-net.c
  12. 4
      hw/scsi/vhost-scsi.c
  13. 2
      hw/scsi/vhost-user-scsi.c
  14. 63
      hw/smbios/smbios.c
  15. 5
      hw/virtio/Kconfig
  16. 4
      hw/virtio/meson.build
  17. 9
      hw/virtio/trace-events
  18. 9
      hw/virtio/vhost-user-fs.c
  19. 69
      hw/virtio/vhost-user-gpio-pci.c
  20. 411
      hw/virtio/vhost-user-gpio.c
  21. 10
      hw/virtio/vhost-user-i2c.c
  22. 10
      hw/virtio/vhost-user-rng.c
  23. 8
      hw/virtio/vhost-user-vsock.c
  24. 16
      hw/virtio/vhost-user.c
  25. 3
      hw/virtio/vhost-vsock-common.c
  26. 8
      hw/virtio/vhost-vsock.c
  27. 6
      hw/virtio/vhost.c
  28. 42
      hw/virtio/virtio-stub.c
  29. 1049
      hw/virtio/virtio.c
  30. 1
      include/hw/cxl/cxl_device.h
  31. 10
      include/hw/firmware/smbios.h
  32. 48
      include/hw/pci/pci.h
  33. 1
      include/hw/virtio/vhost-user-blk.h
  34. 35
      include/hw/virtio/vhost-user-gpio.h
  35. 18
      include/hw/virtio/vhost.h
  36. 20
      include/hw/virtio/virtio-blk-common.h
  37. 28
      include/hw/virtio/virtio.h
  38. 5
      include/monitor/hmp.h
  39. 310
      monitor/hmp-cmds.c
  40. 1
      qapi/meson.build
  41. 1
      qapi/qapi-schema.json
  42. 954
      qapi/virtio.json
  43. 2
      qemu-options.hx
  44. BIN
      tests/data/acpi/pc/DSDT
  45. BIN
      tests/data/acpi/pc/DSDT.acpierst
  46. BIN
      tests/data/acpi/pc/DSDT.acpihmat
  47. BIN
      tests/data/acpi/pc/DSDT.bridge
  48. BIN
      tests/data/acpi/pc/DSDT.cphp
  49. BIN
      tests/data/acpi/pc/DSDT.dimmpxm
  50. BIN
      tests/data/acpi/pc/DSDT.hpbridge
  51. BIN
      tests/data/acpi/pc/DSDT.hpbrroot
  52. BIN
      tests/data/acpi/pc/DSDT.ipmikcs
  53. BIN
      tests/data/acpi/pc/DSDT.memhp
  54. BIN
      tests/data/acpi/pc/DSDT.nohpet
  55. BIN
      tests/data/acpi/pc/DSDT.numamem
  56. BIN
      tests/data/acpi/pc/DSDT.roothp
  57. BIN
      tests/data/acpi/q35/DSDT
  58. BIN
      tests/data/acpi/q35/DSDT.acpierst
  59. BIN
      tests/data/acpi/q35/DSDT.acpihmat
  60. BIN
      tests/data/acpi/q35/DSDT.applesmc
  61. BIN
      tests/data/acpi/q35/DSDT.bridge
  62. BIN
      tests/data/acpi/q35/DSDT.cphp
  63. BIN
      tests/data/acpi/q35/DSDT.cxl
  64. BIN
      tests/data/acpi/q35/DSDT.dimmpxm
  65. BIN
      tests/data/acpi/q35/DSDT.ipmibt
  66. BIN
      tests/data/acpi/q35/DSDT.ipmismbus
  67. BIN
      tests/data/acpi/q35/DSDT.ivrs
  68. BIN
      tests/data/acpi/q35/DSDT.memhp
  69. BIN
      tests/data/acpi/q35/DSDT.mmio64
  70. BIN
      tests/data/acpi/q35/DSDT.multi-bridge
  71. BIN
      tests/data/acpi/q35/DSDT.nohpet
  72. BIN
      tests/data/acpi/q35/DSDT.numamem
  73. BIN
      tests/data/acpi/q35/DSDT.pvpanic-isa
  74. BIN
      tests/data/acpi/q35/DSDT.tis.tpm12
  75. BIN
      tests/data/acpi/q35/DSDT.tis.tpm2
  76. BIN
      tests/data/acpi/q35/DSDT.viot
  77. BIN
      tests/data/acpi/q35/DSDT.xapic
  78. BIN
      tests/data/acpi/virt/GTDT
  79. BIN
      tests/data/acpi/virt/GTDT.memhp
  80. BIN
      tests/data/acpi/virt/GTDT.numamem
  81. 1
      tests/qtest/libqos/meson.build
  82. 171
      tests/qtest/libqos/virtio-gpio.c
  83. 35
      tests/qtest/libqos/virtio-gpio.h
  84. 4
      tests/qtest/libqos/virtio.c
  85. 1
      tests/qtest/qmp-cmd-test.c
  86. 9
      tests/qtest/qos-test.c
  87. 175
      tests/qtest/vhost-user-test.c

12
MAINTAINERS

@ -2030,8 +2030,10 @@ virtio-blk
M: Stefan Hajnoczi <stefanha@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: hw/block/virtio-blk-common.c
F: hw/block/virtio-blk.c
F: hw/block/dataplane/*
F: include/hw/virtio/virtio-blk-common.h
F: tests/qtest/virtio-blk-test.c
T: git https://github.com/stefanha/qemu.git block
@ -2098,6 +2100,14 @@ F: hw/virtio/vhost-user-rng-pci.c
F: include/hw/virtio/vhost-user-rng.h
F: tools/vhost-user-rng/*
vhost-user-gpio
M: Alex Bennée <alex.bennee@linaro.org>
R: Viresh Kumar <viresh.kumar@linaro.org>
S: Maintained
F: hw/virtio/vhost-user-gpio*
F: include/hw/virtio/vhost-user-gpio.h
F: tests/qtest/libqos/virtio-gpio.*
virtio-crypto
M: Gonglei <arei.gonglei@huawei.com>
S: Supported
@ -2271,11 +2281,13 @@ S: Maintained
F: contrib/vhost-user-blk/
F: contrib/vhost-user-scsi/
F: hw/block/vhost-user-blk.c
F: hw/block/virtio-blk-common.c
F: hw/scsi/vhost-user-scsi.c
F: hw/virtio/vhost-user-blk-pci.c
F: hw/virtio/vhost-user-scsi-pci.c
F: include/hw/virtio/vhost-user-blk.h
F: include/hw/virtio/vhost-user-scsi.h
F: include/hw/virtio/virtio-blk-common.h
vhost-user-gpu
M: Marc-André Lureau <marcandre.lureau@redhat.com>

70
hmp-commands-info.hx

@ -923,3 +923,73 @@ SRST
``stats``
Show runtime-collected statistics
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

5
hw/arm/virt-acpi-build.c

@ -592,8 +592,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
acpi_table_begin(&table, table_data);
/* CntControlBase Physical Address */
/* FIXME: invalid value, should be 0xFFFFFFFFFFFFFFFF if not impl. ? */
build_append_int_noprefix(table_data, 0, 8);
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
/*
* FIXME: clarify comment:
@ -618,7 +617,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Non-Secure EL2 timer Flags */
build_append_int_noprefix(table_data, irqflags, 4);
/* CntReadBase Physical address */
build_append_int_noprefix(table_data, 0, 8);
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
/* Platform Timer Count */
build_append_int_noprefix(table_data, 0, 4);
/* Platform Timer Offset */

4
hw/block/meson.build

@ -16,7 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c'))
softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c'))
subdir('dataplane')

39
hw/block/vhost-user-blk.c

@ -23,6 +23,7 @@
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/virtio/virtio-blk-common.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user-blk.h"
#include "hw/virtio/virtio.h"
@ -63,7 +64,7 @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
/* Our num_queues overrides the device backend */
virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues);
memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config));
memcpy(config, &s->blkcfg, vdev->config_len);
}
static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
@ -92,12 +93,12 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
{
int ret;
struct virtio_blk_config blkcfg;
VirtIODevice *vdev = dev->vdev;
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
Error *local_err = NULL;
ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg,
sizeof(struct virtio_blk_config),
&local_err);
vdev->config_len, &local_err);
if (ret < 0) {
error_report_err(local_err);
return ret;
@ -106,7 +107,7 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
/* valid for resize only */
if (blkcfg.capacity != s->blkcfg.capacity) {
s->blkcfg.capacity = blkcfg.capacity;
memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config));
memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len);
virtio_notify_config(dev->vdev);
}
@ -229,7 +230,7 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
return;
}
if (s->dev.started == should_start) {
if (vhost_dev_is_started(&s->dev) == should_start) {
return;
}
@ -259,12 +260,7 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH);
virtio_add_feature(&features, VIRTIO_BLK_F_RO);
virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD);
virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES);
if (s->config_wce) {
virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
}
if (s->num_queues > 1) {
virtio_add_feature(&features, VIRTIO_BLK_F_MQ);
}
@ -286,7 +282,7 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
return;
}
if (s->dev.started) {
if (vhost_dev_is_started(&s->dev)) {
return;
}
@ -415,6 +411,12 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
* the vhost migration code. If disconnect was caught there is an
* option for the general vhost code to get the dev state without
* knowing its type (in this case vhost-user).
*
* FIXME: this is sketchy to be reaching into vhost_dev
* now because we are forcing something that implies we
* have executed vhost_dev_stop() but that won't happen
* until vhost_user_blk_stop() gets called from the bh.
* Really this state check should be tracked locally.
*/
s->dev.started = false;
}
@ -447,7 +449,7 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp)
assert(s->connected);
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
sizeof(struct virtio_blk_config), errp);
s->parent_obj.config_len, errp);
if (ret < 0) {
qemu_chr_fe_disconnect(&s->chardev);
vhost_dev_cleanup(&s->dev);
@ -462,6 +464,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
ERRP_GUARD();
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
size_t config_size;
int retries;
int i, ret;
@ -492,8 +495,9 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
virtio_init(vdev, VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
vdev->host_features);
virtio_init(vdev, VIRTIO_ID_BLOCK, config_size);
s->virtqs = g_new(VirtQueue *, s->num_queues);
for (i = 0; i < s->num_queues; i++) {
@ -591,7 +595,12 @@ static Property vhost_user_blk_properties[] = {
DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues,
VHOST_USER_BLK_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128),
DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true),
DEFINE_PROP_BIT64("config-wce", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_CONFIG_WCE, true),
DEFINE_PROP_BIT64("discard", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_DISCARD, true),
DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_WRITE_ZEROES, true),
DEFINE_PROP_END_OF_LIST(),
};

39
hw/block/virtio-blk-common.c

@ -0,0 +1,39 @@
/*
* Virtio Block Device common helpers
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "standard-headers/linux/virtio_blk.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-blk-common.h"
/* Config size before the discard support (hide associated config fields) */
#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
max_discard_sectors)
/*
* Starting from the discard feature, we can use this array to properly
* set the config size depending on the features enabled.
*/
static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
.end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
{}
};
const VirtIOConfigSizeParams virtio_blk_cfg_size_params = {
.min_size = VIRTIO_BLK_CFG_SIZE,
.max_size = sizeof(struct virtio_blk_config),
.feature_sizes = feature_sizes
};

28
hw/block/virtio-blk.c

@ -32,31 +32,9 @@
#include "hw/virtio/virtio-bus.h"
#include "migration/qemu-file-types.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/virtio-blk-common.h"
#include "qemu/coroutine.h"
/* Config size before the discard support (hide associated config fields) */
#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
max_discard_sectors)
/*
* Starting from the discard feature, we can use this array to properly
* set the config size depending on the features enabled.
*/
static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
.end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
{}
};
static void virtio_blk_set_config_size(VirtIOBlock *s, uint64_t host_features)
{
s->config_size = MAX(VIRTIO_BLK_CFG_SIZE,
virtio_feature_get_config_size(feature_sizes, host_features));
assert(s->config_size <= sizeof(struct virtio_blk_config));
}
static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
VirtIOBlockReq *req)
{
@ -1204,8 +1182,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
virtio_blk_set_config_size(s, s->host_features);
s->config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
s->host_features);
virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
s->blk = conf->conf.blk;

302
hw/i386/acpi-build.c

@ -374,6 +374,25 @@ build_facs(GArray *table_data)
g_array_append_vals(table_data, reserved, 40); /* Reserved */
}
Aml *aml_pci_device_dsm(void)
{
Aml *method;
method = aml_method("_DSM", 4, AML_SERIALIZED);
{
Aml *params = aml_local(0);
Aml *pkg = aml_package(2);
aml_append(pkg, aml_name("BSEL"));
aml_append(pkg, aml_name("ASUN"));
aml_append(method, aml_store(pkg, params));
aml_append(method,
aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1),
aml_arg(2), aml_arg(3), params))
);
}
return method;
}
static void build_append_pcihp_notify_entry(Aml *method, int slot)
{
Aml *if_ctx;
@ -408,13 +427,41 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
int func = PCI_FUNC(devfn);
/* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
int adr = slot << 16 | func;
bool hotplug_enabled_dev;
bool bridge_in_acpi;
bool cold_plugged_bridge;
bool hotpluggbale_slot = false;
bool bridge_in_acpi = false;
bool cold_plugged_bridge = false;
bool is_vga = false;
if (!pdev) {
if (pdev) {
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
continue;
}
is_vga = pc->class_id == PCI_CLASS_DISPLAY_VGA;
/*
* Cold plugged bridges aren't themselves hot-pluggable.
* Hotplugged bridges *are* hot-pluggable.
*/
cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged;
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
hotpluggbale_slot = bsel && dc->hotpluggable &&
!cold_plugged_bridge;
/*
* allow describing coldplugged bridges in ACPI even if they are not
* on function 0, as they are not unpluggable, for all other devices
* generate description only for function 0 per slot
*/
if (func && !bridge_in_acpi) {
continue;
}
} else {
/*
* add hotplug slots for non present devices.
* hotplug is supported only for non-multifunction device
* so generate device description only for function 0
*/
@ -422,51 +469,11 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
if (pci_bus_is_express(bus) && slot > 0) {
break;
}
dev = aml_device("S%.02X", devfn);
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
method = aml_method("_DSM", 4, AML_SERIALIZED);
aml_append(method,
aml_return(aml_call6("PDSM", aml_arg(0), aml_arg(1),
aml_arg(2), aml_arg(3),
aml_name("BSEL"), aml_name("_SUN")))
);
aml_append(dev, method);
aml_append(parent_scope, dev);
build_append_pcihp_notify_entry(notify_method, slot);
/* mark it as empty hotpluggable slot */
hotpluggbale_slot = true;
} else {
continue;
}
continue;
}
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
/*
* Cold plugged bridges aren't themselves hot-pluggable.
* Hotplugged bridges *are* hot-pluggable.
*/
cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged;
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
hotplug_enabled_dev = bsel && dc->hotpluggable && !cold_plugged_bridge;
if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
continue;
}
/*
* allow describing coldplugged bridges in ACPI even if they are not
* on function 0, as they are not unpluggable, for all other devices
* generate description only for function 0 per slot
*/
if (func && !bridge_in_acpi) {
continue;
}
/* start to compose PCI device descriptor */
@ -479,15 +486,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
* enumeration order in linux kernel, so use another variable for it
*/
aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
method = aml_method("_DSM", 4, AML_SERIALIZED);
aml_append(method, aml_return(
aml_call6("PDSM", aml_arg(0), aml_arg(1), aml_arg(2),
aml_arg(3), aml_name("BSEL"), aml_name("ASUN"))
));
aml_append(dev, method);
aml_append(dev, aml_pci_device_dsm());
}
if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
if (is_vga) {
/* add VGA specific AML methods */
int s3d;
@ -508,19 +510,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
method = aml_method("_S3D", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(s3d)));
aml_append(dev, method);
} else if (hotplug_enabled_dev) {
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
}
if (bsel) {
build_append_pcihp_notify_entry(notify_method, slot);
}
} else if (bridge_in_acpi) {
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
if (bridge_in_acpi) {
/*
* device is coldplugged bridge,
* add child device descriptions into its scope
@ -529,6 +522,19 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
}
if (hotpluggbale_slot) {
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
build_append_pcihp_notify_entry(notify_method, slot);
}
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
@ -572,84 +578,100 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
qobject_unref(bsel);
}
Aml *aml_pci_device_dsm(void)
static Aml *aml_pci_pdsm(void)
{
Aml *method, *UUID, *ifctx, *ifctx1, *ifctx2, *ifctx3, *elsectx;
Aml *acpi_index = aml_local(0);
Aml *method, *UUID, *ifctx, *ifctx1;
Aml *ret = aml_local(0);
Aml *caps = aml_local(1);
Aml *acpi_index = aml_local(2);
Aml *zero = aml_int(0);
Aml *bnum = aml_arg(4);
Aml *one = aml_int(1);
Aml *func = aml_arg(2);
Aml *rev = aml_arg(1);
Aml *sunum = aml_arg(5);
Aml *params = aml_arg(4);
Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
Aml *sunum = aml_derefof(aml_index(params, aml_int(1)));
method = aml_method("PDSM", 5, AML_SERIALIZED);
method = aml_method("PDSM", 6, AML_SERIALIZED);
/* get supported functions */
ifctx = aml_if(aml_equal(func, zero));
{
uint8_t byte_list[1] = { 0 }; /* nothing supported yet */
aml_append(ifctx, aml_store(aml_buffer(1, byte_list), ret));
aml_append(ifctx, aml_store(zero, caps));
/*
* PCI Firmware Specification 3.1
* 4.6. _DSM Definitions for PCI
*/
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID)));
{
/* call is for unsupported UUID, bail out */
aml_append(ifctx1, aml_return(ret));
}
aml_append(ifctx, ifctx1);
ifctx1 = aml_if(aml_lless(rev, aml_int(2)));
{
/* call is for unsupported REV, bail out */
aml_append(ifctx1, aml_return(ret));
}
aml_append(ifctx, ifctx1);
aml_append(ifctx,
aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
/*
* advertise function 7 if device has acpi-index
* acpi_index values:
* 0: not present (default value)
* FFFFFFFF: not supported (old QEMU without PIDX reg)
* other: device's acpi-index
*/
ifctx1 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
));
{
/* have supported functions */
aml_append(ifctx1, aml_or(caps, one, caps));
/* support for function 7 */
aml_append(ifctx1,
aml_or(caps, aml_shiftleft(one, aml_int(7)), caps));
}
aml_append(ifctx, ifctx1);
aml_append(ifctx, aml_store(caps, aml_index(ret, zero)));
aml_append(ifctx, aml_return(ret));
}
aml_append(method, ifctx);
/* handle specific functions requests */
/*
* PCI Firmware Specification 3.1
* 4.6. _DSM Definitions for PCI
* 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
* Operating Systems
*/
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
ifctx = aml_if(aml_equal(aml_arg(0), UUID));
ifctx = aml_if(aml_equal(func, aml_int(7)));
{
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
ifctx1 = aml_if(aml_equal(func, zero));
{
uint8_t byte_list[1];
Aml *pkg = aml_package(2);
ifctx2 = aml_if(aml_equal(rev, aml_int(2)));
{
/*
* advertise function 7 if device has acpi-index
* acpi_index values:
* 0: not present (default value)
* FFFFFFFF: not supported (old QEMU without PIDX reg)
* other: device's acpi-index
*/
ifctx3 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
));
{
byte_list[0] =
1 /* have supported functions */ |
1 << 7 /* support for function 7 */
;
aml_append(ifctx3, aml_return(aml_buffer(1, byte_list)));
}
aml_append(ifctx2, ifctx3);
}
aml_append(ifctx1, ifctx2);
byte_list[0] = 0; /* nothing supported */
aml_append(ifctx1, aml_return(aml_buffer(1, byte_list)));
}
aml_append(ifctx, ifctx1);
elsectx = aml_else();
/*
* PCI Firmware Specification 3.1
* 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
* Operating Systems
*/
ifctx1 = aml_if(aml_equal(func, aml_int(7)));
{
Aml *pkg = aml_package(2);
Aml *ret = aml_local(1);
aml_append(pkg, zero);
/*
* optional, if not impl. should return null string
*/
aml_append(pkg, aml_string("%s", ""));
aml_append(ifctx1, aml_store(pkg, ret));
/*
* update acpi-index to actual value
*/
aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
aml_append(ifctx1, aml_return(ret));
}
aml_append(elsectx, ifctx1);
aml_append(ifctx, elsectx);
aml_append(pkg, zero);
/*
* optional, if not impl. should return null string
*/
aml_append(pkg, aml_string("%s", ""));
aml_append(ifctx, aml_store(pkg, ret));
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
/*
* update acpi-index to actual value
*/
aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero)));
aml_append(ifctx, aml_return(ret));
}
aml_append(method, ifctx);
return method;
}
@ -1339,7 +1361,7 @@ static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr)
aml_append(method, aml_return(aml_local(0)));
aml_append(scope, method);
aml_append(scope, aml_pci_device_dsm());
aml_append(scope, aml_pci_pdsm());
aml_append(table, scope);
}
@ -1467,9 +1489,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(sb_scope, dev);
aml_append(dsdt, sb_scope);
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
build_piix4_isa_bridge(dsdt);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
@ -1515,9 +1534,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope);
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
build_q35_isa_bridge(dsdt);
if (pm->pcihp_bridge_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
@ -1528,6 +1544,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
if (vmbus_bridge) {
sb_scope = aml_scope("_SB");
aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));

5
hw/i386/intel_iommu.c

@ -3818,6 +3818,11 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split");
return false;
}
if (!kvm_enable_x2apic()) {
error_setg(errp, "eim=on requires support on the KVM side"
"(X2APIC_API, first shipped in v4.7)");
return false;
}
}
/* Currently only address widths supported are 39 and 48 bits */

14
hw/mem/cxl_type3.c

@ -14,6 +14,12 @@
#include "sysemu/hostmem.h"
#include "hw/cxl/cxl.h"
/*
* Null value of all Fs suggested by IEEE RA guidelines for use of
* EU, OUI and CID
*/
#define UI64_NULL ~(0ULL)
static void build_dvsecs(CXLType3Dev *ct3d)
{
CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
@ -149,7 +155,12 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL);
pcie_endpoint_cap_init(pci_dev, 0x80);
cxl_cstate->dvsec_offset = 0x100;
if (ct3d->sn != UI64_NULL) {
pcie_dev_ser_num_init(pci_dev, 0x100, ct3d->sn);
cxl_cstate->dvsec_offset = 0x100 + 0x0c;
} else {
cxl_cstate->dvsec_offset = 0x100;
}
ct3d->cxl_cstate.pdev = pci_dev;
build_dvsecs(ct3d);
@ -275,6 +286,7 @@ static Property ct3_props[] = {
HostMemoryBackend *),
DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL),
DEFINE_PROP_END_OF_LIST(),
};

9
hw/net/virtio-net.c

@ -106,6 +106,12 @@ static const VirtIOFeature feature_sizes[] = {
{}
};
static const VirtIOConfigSizeParams cfg_size_params = {
.min_size = endof(struct virtio_net_config, mac),
.max_size = sizeof(struct virtio_net_config),
.feature_sizes = feature_sizes
};
static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
@ -3241,8 +3247,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
{
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
n->config_size = virtio_feature_get_config_size(feature_sizes,
host_features);
n->config_size = virtio_get_config_size(&cfg_size_params, host_features);
}
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,

4
hw/scsi/vhost-scsi.c

@ -120,7 +120,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
start = false;
}
if (vsc->dev.started == start) {
if (vhost_dev_is_started(&vsc->dev) == start) {
return;
}
@ -147,7 +147,7 @@ static int vhost_scsi_pre_save(void *opaque)
/* At this point, backend must be stopped, otherwise
* it might keep writing to memory. */
assert(!vsc->dev.started);
assert(!vhost_dev_is_started(&vsc->dev));
return 0;
}

2
hw/scsi/vhost-user-scsi.c

@ -49,7 +49,7 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running;
if (vsc->dev.started == start) {
if (vhost_dev_is_started(&vsc->dev) == start) {
return;
}

63
hw/smbios/smbios.c

@ -111,6 +111,13 @@ static struct {
.processor_id = 0,
};
struct type8_instance {
const char *internal_reference, *external_reference;
uint8_t connector_type, port_type;
QTAILQ_ENTRY(type8_instance) next;
};
static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
static struct {
size_t nvalues;
char **values;
@ -337,6 +344,29 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = {
{ /* end of list */ }
};
static const QemuOptDesc qemu_smbios_type8_opts[] = {
{
.name = "internal_reference",
.type = QEMU_OPT_STRING,
.help = "internal reference designator",
},
{
.name = "external_reference",
.type = QEMU_OPT_STRING,
.help = "external reference designator",
},
{
.name = "connector_type",
.type = QEMU_OPT_NUMBER,
.help = "connector type",
},
{
.name = "port_type",
.type = QEMU_OPT_NUMBER,
.help = "port type",
},
};
static const QemuOptDesc qemu_smbios_type11_opts[] = {
{
.name = "value",
@ -718,6 +748,26 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
smbios_type4_count++;
}
static void smbios_build_type_8_table(void)
{
unsigned instance = 0;
struct type8_instance *t8;
QTAILQ_FOREACH(t8, &type8, next) {
SMBIOS_BUILD_TABLE_PRE(8, T0_BASE + instance, true);
SMBIOS_TABLE_SET_STR(8, internal_reference_str, t8->internal_reference);
SMBIOS_TABLE_SET_STR(8, external_reference_str, t8->external_reference);
/* most vendors seem to set this to None */
t->internal_connector_type = 0x0;
t->external_connector_type = t8->connector_type;
t->port_type = t8->port_type;
SMBIOS_BUILD_TABLE_POST;
instance++;
}
}
static void smbios_build_type_11_table(void)
{
char count_str[128];
@ -1030,6 +1080,7 @@ void smbios_get_tables(MachineState *ms,
smbios_build_type_4_table(ms, i);
}
smbios_build_type_8_table();
smbios_build_type_11_table();
#define MAX_DIMM_SZ (16 * GiB)
@ -1348,6 +1399,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
UINT16_MAX);
}
return;
case 8:
if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) {
return;
}
struct type8_instance *t;
t = g_new0(struct type8_instance, 1);
save_opt(&t->internal_reference, opts, "internal_reference");
save_opt(&t->external_reference, opts, "external_reference");
t->connector_type = qemu_opt_get_number(opts, "connector_type", 0);
t->port_type = qemu_opt_get_number(opts, "port_type", 0);
QTAILQ_INSERT_TAIL(&type8, t, next);
return;
case 11:
if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) {
return;

5
hw/virtio/Kconfig

@ -80,3 +80,8 @@ config VHOST_USER_FS
bool
default y
depends on VIRTIO && VHOST_USER
config VHOST_USER_GPIO
bool
default y
depends on VIRTIO && VHOST_USER

4
hw/virtio/meson.build

@ -29,6 +29,8 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c'))
virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c'))
virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c'))
virtio_pci_ss = ss.source_set()
virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c'))
@ -60,4 +62,6 @@ virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: virtio_ss)
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'))

9
hw/virtio/trace-events

@ -8,6 +8,10 @@ vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size,
vhost_section(const char *name) "%s"
vhost_reject_section(const char *name, int d) "%s:%d"
vhost_iotlb_miss(void *dev, int step) "%p step %d"
vhost_dev_cleanup(void *dev) "%p"
vhost_dev_start(void *dev, const char *name) "%p:%s"
vhost_dev_stop(void *dev, const char *name) "%p:%s"
# vhost-user.c
vhost_user_postcopy_end_entry(void) ""
@ -140,3 +144,8 @@ virtio_mem_state_response(uint16_t state) "state=%" PRIu16
virtio_pmem_flush_request(void) "flush request"
virtio_pmem_response(void) "flush response"
virtio_pmem_flush_done(int type) "fsync return=%d"
# virtio-gpio.c
virtio_gpio_start(void) "start"
virtio_gpio_stop(void) "stop"
virtio_gpio_set_status(uint8_t status) "0x%x"

9
hw/virtio/vhost-user-fs.c

@ -20,6 +20,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "qemu/error-report.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user-fs.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
@ -122,13 +123,9 @@ static void vuf_stop(VirtIODevice *vdev)
static void vuf_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
if (!vdev->vm_running) {
should_start = false;
}
if (fs->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&fs->vhost_dev) == should_start) {
return;
}

69
hw/virtio/vhost-user-gpio-pci.c

@ -0,0 +1,69 @@
/*
* Vhost-user gpio virtio device PCI glue
*
* Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/vhost-user-gpio.h"
#include "hw/virtio/virtio-pci.h"
struct VHostUserGPIOPCI {
VirtIOPCIProxy parent_obj;
VHostUserGPIO vdev;
};
typedef struct VHostUserGPIOPCI VHostUserGPIOPCI;
#define TYPE_VHOST_USER_GPIO_PCI "vhost-user-gpio-pci-base"
DECLARE_INSTANCE_CHECKER(VHostUserGPIOPCI, VHOST_USER_GPIO_PCI,
TYPE_VHOST_USER_GPIO_PCI)
static void vhost_user_gpio_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
vpci_dev->nvectors = 1;
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
static void vhost_user_gpio_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
k->realize = vhost_user_gpio_pci_realize;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
pcidev_k->revision = 0x00;
pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
}
static void vhost_user_gpio_pci_instance_init(Object *obj)
{
VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VHOST_USER_GPIO);
}
static const VirtioPCIDeviceTypeInfo vhost_user_gpio_pci_info = {
.base_name = TYPE_VHOST_USER_GPIO_PCI,
.non_transitional_name = "vhost-user-gpio-pci",
.instance_size = sizeof(VHostUserGPIOPCI),
.instance_init = vhost_user_gpio_pci_instance_init,
.class_init = vhost_user_gpio_pci_class_init,
};
static void vhost_user_gpio_pci_register(void)
{
virtio_pci_types_register(&vhost_user_gpio_pci_info);
}
type_init(vhost_user_gpio_pci_register);

411
hw/virtio/vhost-user-gpio.c

@ -0,0 +1,411 @@
/*
* Vhost-user GPIO virtio device
*
* Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/vhost-user-gpio.h"
#include "qemu/error-report.h"
#include "standard-headers/linux/virtio_ids.h"
#include "trace.h"
#define REALIZE_CONNECTION_RETRIES 3
/* Features required from VirtIO */
static const int feature_bits[] = {
VIRTIO_F_VERSION_1,
VIRTIO_F_NOTIFY_ON_EMPTY,
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_GPIO_F_IRQ,
VHOST_INVALID_FEATURE_BIT
};
static void vu_gpio_get_config(VirtIODevice *vdev, uint8_t *config)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
memcpy(config, &gpio->config, sizeof(gpio->config));
}
static int vu_gpio_config_notifier(struct vhost_dev *dev)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev->vdev);
memcpy(dev->vdev->config, &gpio->config, sizeof(gpio->config));
virtio_notify_config(dev->vdev);
return 0;
}
const VhostDevConfigOps gpio_ops = {
.vhost_dev_config_notifier = vu_gpio_config_notifier,
};
static int vu_gpio_start(VirtIODevice *vdev)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret, i;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return -ENOSYS;
}
ret = vhost_dev_enable_notifiers(vhost_dev, vdev);
if (ret < 0) {
error_report("Error enabling host notifiers: %d", ret);
return ret;
}
ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, true);
if (ret < 0) {
error_report("Error binding guest notifier: %d", ret);
goto err_host_notifiers;
}
/*
* Before we start up we need to ensure we have the final feature
* set needed for the vhost configuration. The backend may also
* apply backend_features when the feature set is sent.
*/
vhost_ack_features(&gpio->vhost_dev, feature_bits, vdev->guest_features);
ret = vhost_dev_start(&gpio->vhost_dev, vdev);
if (ret < 0) {
error_report("Error starting vhost-user-gpio: %d", ret);
goto err_guest_notifiers;
}
/*
* guest_notifier_mask/pending not used yet, so just unmask
* everything here. virtio-pci will do the right thing by
* enabling/disabling irqfd.
*/
for (i = 0; i < gpio->vhost_dev.nvqs; i++) {
vhost_virtqueue_mask(&gpio->vhost_dev, vdev, i, false);
}
/*
* As we must have VHOST_USER_F_PROTOCOL_FEATURES (because
* VHOST_USER_GET_CONFIG requires it) we need to explicitly enable
* the vrings.
*/
g_assert(vhost_dev->vhost_ops &&
vhost_dev->vhost_ops->vhost_set_vring_enable);
ret = vhost_dev->vhost_ops->vhost_set_vring_enable(vhost_dev, true);
if (ret == 0) {
return 0;
}
error_report("Failed to start vrings for vhost-user-gpio: %d", ret);
err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, gpio->vhost_dev.nvqs, false);
err_host_notifiers:
vhost_dev_disable_notifiers(&gpio->vhost_dev, vdev);
return ret;
}
static void vu_gpio_stop(VirtIODevice *vdev)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
if (!k->set_guest_notifiers) {
return;
}
/*
* We can call vu_gpio_stop multiple times, for example from
* vm_state_notify and the final object finalisation. Check we
* aren't already stopped before doing so.
*/
if (!vhost_dev_is_started(vhost_dev)) {
return;
}
vhost_dev_stop(vhost_dev, vdev);
ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false);
if (ret < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
return;
}
vhost_dev_disable_notifiers(vhost_dev, vdev);
}
static void vu_gpio_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
bool should_start = virtio_device_started(vdev, status);
trace_virtio_gpio_set_status(status);
if (!gpio->connected) {
return;
}
if (vhost_dev_is_started(&gpio->vhost_dev) == should_start) {
return;
}
if (should_start) {
if (vu_gpio_start(vdev)) {
qemu_chr_fe_disconnect(&gpio->chardev);
}
} else {
vu_gpio_stop(vdev);
}
}
static uint64_t vu_gpio_get_features(VirtIODevice *vdev, uint64_t features,
Error **errp)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
return vhost_get_features(&gpio->vhost_dev, feature_bits, features);
}
static void vu_gpio_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
/*
* Not normally called; it's the daemon that handles the queue;
* however virtio's cleanup path can call this.
*/
}
static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
vhost_virtqueue_mask(&gpio->vhost_dev, vdev, idx, mask);
}
static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio)
{
virtio_delete_queue(gpio->command_vq);
virtio_delete_queue(gpio->interrupt_vq);
g_free(gpio->vhost_dev.vqs);
gpio->vhost_dev.vqs = NULL;
virtio_cleanup(vdev);
vhost_user_cleanup(&gpio->vhost_user);
}
static int vu_gpio_connect(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
if (gpio->connected) {
return 0;
}
gpio->connected = true;
vhost_dev_set_config_notifier(vhost_dev, &gpio_ops);
gpio->vhost_user.supports_config = true;
ret = vhost_dev_init(vhost_dev, &gpio->vhost_user,
VHOST_BACKEND_TYPE_USER, 0, errp);
if (ret < 0) {
return ret;
}
/* restore vhost state */
if (virtio_device_started(vdev, vdev->status)) {
vu_gpio_start(vdev);
}
return 0;
}
static void vu_gpio_disconnect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
if (!gpio->connected) {
return;
}
gpio->connected = false;
vu_gpio_stop(vdev);
vhost_dev_cleanup(&gpio->vhost_dev);
}
static void vu_gpio_event(void *opaque, QEMUChrEvent event)
{
DeviceState *dev = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
Error *local_err = NULL;
switch (event) {
case CHR_EVENT_OPENED:
if (vu_gpio_connect(dev, &local_err) < 0) {
qemu_chr_fe_disconnect(&gpio->chardev);
return;
}
break;
case CHR_EVENT_CLOSED:
vu_gpio_disconnect(dev);
break;
case CHR_EVENT_BREAK:
case CHR_EVENT_MUX_IN:
case CHR_EVENT_MUX_OUT:
/* Ignore */
break;
}
}
static int vu_gpio_realize_connect(VHostUserGPIO *gpio, Error **errp)
{
VirtIODevice *vdev = &gpio->parent_obj;
DeviceState *dev = &vdev->parent_obj;
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
ret = qemu_chr_fe_wait_connected(&gpio->chardev, errp);
if (ret < 0) {
return ret;
}
/*
* vu_gpio_connect() may have already connected (via the event
* callback) in which case it will just report success.
*/
ret = vu_gpio_connect(dev, errp);
if (ret < 0) {
qemu_chr_fe_disconnect(&gpio->chardev);
return ret;
}
g_assert(gpio->connected);
ret = vhost_dev_get_config(vhost_dev, (uint8_t *)&gpio->config,
sizeof(gpio->config), errp);
if (ret < 0) {
error_report("vhost-user-gpio: get config failed");
qemu_chr_fe_disconnect(&gpio->chardev);
vhost_dev_cleanup(vhost_dev);
return ret;
}
return 0;
}
static void vu_gpio_device_realize(DeviceState *dev, Error **errp)
{
ERRP_GUARD();
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev);
int retries, ret;
if (!gpio->chardev.chr) {
error_setg(errp, "vhost-user-gpio: chardev is mandatory");
return;
}
if (!vhost_user_init(&gpio->vhost_user, &gpio->chardev, errp)) {
return;
}
virtio_init(vdev, VIRTIO_ID_GPIO, sizeof(gpio->config));
gpio->vhost_dev.nvqs = 2;
gpio->command_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output);
gpio->interrupt_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output);
gpio->vhost_dev.vqs = g_new0(struct vhost_virtqueue, gpio->vhost_dev.nvqs);
gpio->connected = false;
qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, vu_gpio_event, NULL,
dev, NULL, true);
retries = REALIZE_CONNECTION_RETRIES;
g_assert(!*errp);
do {
if (*errp) {
error_prepend(errp, "Reconnecting after error: ");
error_report_err(*errp);
*errp = NULL;
}
ret = vu_gpio_realize_connect(gpio, errp);
} while (ret < 0 && retries--);
if (ret < 0) {
do_vhost_user_cleanup(vdev, gpio);
}
return;
}
static void vu_gpio_device_unrealize(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev);
vu_gpio_set_status(vdev, 0);
qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, NULL, NULL, NULL, NULL,
false);
vhost_dev_cleanup(&gpio->vhost_dev);
do_vhost_user_cleanup(vdev, gpio);
}
static const VMStateDescription vu_gpio_vmstate = {
.name = "vhost-user-gpio",
.unmigratable = 1,
};
static Property vu_gpio_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserGPIO, chardev),
DEFINE_PROP_END_OF_LIST(),
};
static void vu_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, vu_gpio_properties);
dc->vmsd = &vu_gpio_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = vu_gpio_device_realize;
vdc->unrealize = vu_gpio_device_unrealize;
vdc->get_features = vu_gpio_get_features;
vdc->get_config = vu_gpio_get_config;
vdc->set_status = vu_gpio_set_status;
vdc->guest_notifier_mask = vu_gpio_guest_notifier_mask;
}
static const TypeInfo vu_gpio_info = {
.name = TYPE_VHOST_USER_GPIO,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VHostUserGPIO),
.class_init = vu_gpio_class_init,
};
static void vu_gpio_register_types(void)
{
type_register_static(&vu_gpio_info);
}
type_init(vu_gpio_register_types)

10
hw/virtio/vhost-user-i2c.c

@ -93,13 +93,9 @@ static void vu_i2c_stop(VirtIODevice *vdev)
static void vu_i2c_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserI2C *i2c = VHOST_USER_I2C(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
if (!vdev->vm_running) {
should_start = false;
}
if (i2c->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&i2c->vhost_dev) == should_start) {
return;
}
@ -178,7 +174,7 @@ static void vu_i2c_disconnect(DeviceState *dev)
}
i2c->connected = false;
if (i2c->vhost_dev.started) {
if (vhost_dev_is_started(&i2c->vhost_dev)) {
vu_i2c_stop(vdev);
}
}

10
hw/virtio/vhost-user-rng.c

@ -90,13 +90,9 @@ static void vu_rng_stop(VirtIODevice *vdev)
static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
if (!vdev->vm_running) {
should_start = false;
}
if (rng->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&rng->vhost_dev) == should_start) {
return;
}
@ -164,7 +160,7 @@ static void vu_rng_disconnect(DeviceState *dev)
rng->connected = false;
if (rng->vhost_dev.started) {
if (vhost_dev_is_started(&rng->vhost_dev)) {
vu_rng_stop(vdev);
}
}

8
hw/virtio/vhost-user-vsock.c

@ -55,13 +55,9 @@ const VhostDevConfigOps vsock_ops = {
static void vuv_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
if (!vdev->vm_running) {
should_start = false;
}
if (vvc->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
return;
}

16
hw/virtio/vhost-user.c

@ -200,7 +200,7 @@ typedef struct {
VhostUserRequest request;
#define VHOST_USER_VERSION_MASK (0x3)
#define VHOST_USER_REPLY_MASK (0x1<<2)
#define VHOST_USER_REPLY_MASK (0x1 << 2)
#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3)
uint32_t flags;
uint32_t size; /* the following payload size */
@ -208,7 +208,7 @@ typedef struct {
typedef union {
#define VHOST_USER_VRING_IDX_MASK (0xff)
#define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8)
uint64_t u64;
struct vhost_vring_state state;
struct vhost_vring_addr addr;
@ -248,7 +248,8 @@ struct vhost_user {
size_t region_rb_len;
/* RAMBlock associated with a given region */
RAMBlock **region_rb;
/* The offset from the start of the RAMBlock to the start of the
/*
* The offset from the start of the RAMBlock to the start of the
* vhost region.
*/
ram_addr_t *region_rb_offset;
@ -1460,7 +1461,14 @@ static int vhost_user_set_features(struct vhost_dev *dev,
*/
bool log_enabled = features & (0x1ULL << VHOST_F_LOG_ALL);
return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features,
/*
* We need to include any extra backend only feature bits that
* might be needed by our device. Currently this includes the
* VHOST_USER_F_PROTOCOL_FEATURES bit for enabling protocol
* features.
*/
return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES,
features | dev->backend_features,
log_enabled);
}

3
hw/virtio/vhost-vsock-common.c

@ -14,6 +14,7 @@
#include "hw/virtio/virtio-access.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-vsock.h"
#include "qemu/iov.h"
#include "monitor/monitor.h"
@ -199,7 +200,7 @@ int vhost_vsock_common_pre_save(void *opaque)
* At this point, backend must be stopped, otherwise
* it might keep writing to memory.
*/
assert(!vvc->vhost_dev.started);
assert(!vhost_dev_is_started(&vvc->vhost_dev));
return 0;
}

8
hw/virtio/vhost-vsock.c

@ -70,14 +70,10 @@ static int vhost_vsock_set_running(VirtIODevice *vdev, int start)
static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
int ret;
if (!vdev->vm_running) {
should_start = false;
}
if (vvc->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) {
return;
}

6
hw/virtio/vhost.c

@ -1477,6 +1477,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
{
int i;
trace_vhost_dev_cleanup(hdev);
for (i = 0; i < hdev->nvqs; ++i) {
vhost_virtqueue_cleanup(hdev->vqs + i);
}
@ -1783,6 +1785,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
trace_vhost_dev_start(hdev, vdev->name);
vdev->vhost_started = true;
hdev->started = true;
hdev->vdev = vdev;
@ -1869,6 +1873,8 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
trace_vhost_dev_stop(hdev, vdev->name);
if (hdev->vhost_ops->vhost_dev_start) {
hdev->vhost_ops->vhost_dev_start(hdev, false);
}

42
hw/virtio/virtio-stub.c

@ -0,0 +1,42 @@
#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);
}
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);
}
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);
}

1049
hw/virtio/virtio.c

File diff suppressed because it is too large

1
include/hw/cxl/cxl_device.h

@ -237,6 +237,7 @@ struct CXLType3Dev {
/* Properties */
HostMemoryBackend *hostmem;
HostMemoryBackend *lsa;
uint64_t sn;
/* State */
AddressSpace hostmem_as;

10
include/hw/firmware/smbios.h

@ -189,6 +189,16 @@ struct smbios_type_4 {
uint16_t processor_family2;
} QEMU_PACKED;
/* SMBIOS type 8 - Port Connector Information */
struct smbios_type_8 {
struct smbios_structure_header header;
uint8_t internal_reference_str;
uint8_t internal_connector_type;
uint8_t external_reference_str;
uint8_t external_connector_type;
uint8_t port_type;
} QEMU_PACKED;
/* SMBIOS type 11 - OEM strings */
struct smbios_type_11 {
struct smbios_structure_header header;

48
include/hw/pci/pci.h

@ -688,60 +688,44 @@ static inline void
pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
{
uint8_t val = pci_get_byte(config);
uint8_t rval = reg << ctz32(mask);
pci_set_byte(config, (~mask & val) | (mask & rval));
}
uint8_t rval;
static inline uint8_t
pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
{
uint8_t val = pci_get_byte(config);
return (val & mask) >> ctz32(mask);
assert(mask);
rval = reg << ctz32(mask);
pci_set_byte(config, (~mask & val) | (mask & rval));
}
static inline void
pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
{
uint16_t val = pci_get_word(config);
uint16_t rval = reg << ctz32(mask);
pci_set_word(config, (~mask & val) | (mask & rval));
}
uint16_t rval;
static inline uint16_t
pci_get_word_by_mask(uint8_t *config, uint16_t mask)
{
uint16_t val = pci_get_word(config);
return (val & mask) >> ctz32(mask);
assert(mask);
rval = reg << ctz32(mask);
pci_set_word(config, (~mask & val) | (mask & rval));
}
static inline void
pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
{
uint32_t val = pci_get_long(config);
uint32_t rval = reg << ctz32(mask);
pci_set_long(config, (~mask & val) | (mask & rval));
}
uint32_t rval;
static inline uint32_t
pci_get_long_by_mask(uint8_t *config, uint32_t mask)
{
uint32_t val = pci_get_long(config);
return (val & mask) >> ctz32(mask);
assert(mask);
rval = reg << ctz32(mask);
pci_set_long(config, (~mask & val) | (mask & rval));
}
static inline void
pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
{
uint64_t val = pci_get_quad(config);
uint64_t rval = reg << ctz32(mask);
pci_set_quad(config, (~mask & val) | (mask & rval));
}
uint64_t rval;
static inline uint64_t
pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
{
uint64_t val = pci_get_quad(config);
return (val & mask) >> ctz32(mask);
assert(mask);
rval = reg << ctz32(mask);
pci_set_quad(config, (~mask & val) | (mask & rval));
}
PCIDevice *pci_new_multifunction(int devfn, bool multifunction,

1
include/hw/virtio/vhost-user-blk.h

@ -34,7 +34,6 @@ struct VHostUserBlk {
struct virtio_blk_config blkcfg;
uint16_t num_queues;
uint32_t queue_size;
uint32_t config_wce;
struct vhost_dev dev;
struct vhost_inflight *inflight;
VhostUserState vhost_user;

35
include/hw/virtio/vhost-user-gpio.h

@ -0,0 +1,35 @@
/*
* Vhost-user GPIO virtio device
*
* Copyright (c) 2021 Viresh Kumar <viresh.kumar@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef _QEMU_VHOST_USER_GPIO_H
#define _QEMU_VHOST_USER_GPIO_H
#include "hw/virtio/virtio.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user.h"
#include "standard-headers/linux/virtio_gpio.h"
#include "chardev/char-fe.h"
#define TYPE_VHOST_USER_GPIO "vhost-user-gpio-device"
OBJECT_DECLARE_SIMPLE_TYPE(VHostUserGPIO, VHOST_USER_GPIO);
struct VHostUserGPIO {
/*< private >*/
VirtIODevice parent_obj;
CharBackend chardev;
struct virtio_gpio_config config;
struct vhost_virtqueue *vhost_vq;
struct vhost_dev vhost_dev;
VhostUserState vhost_user;
VirtQueue *command_vq;
VirtQueue *interrupt_vq;
bool connected;
/*< public >*/
};
#endif /* _QEMU_VHOST_USER_GPIO_H */

18
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 {
@ -86,11 +89,15 @@ struct vhost_dev {
/* if non-zero, minimum required value for max_queues */
int num_queues;
uint64_t features;
/** @acked_features: final set of negotiated features */
uint64_t acked_features;
/** @backend_features: backend specific feature bits */
uint64_t backend_features;
/** @protocol_features: final negotiated protocol features */
uint64_t protocol_features;
uint64_t max_queues;
uint64_t backend_cap;
/* @started: is the vhost device started? */
bool started;
bool log_enabled;
uint64_t log_size;
@ -162,6 +169,17 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
*/
void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
/**
* vhost_dev_is_started() - report status of vhost device
* @hdev: common vhost_dev structure
*
* Return the started status of the vhost device
*/
static inline bool vhost_dev_is_started(struct vhost_dev *hdev)
{
return hdev->started;
}
/**
* vhost_dev_start() - start the vhost device
* @hdev: common vhost_dev structure

20
include/hw/virtio/virtio-blk-common.h

@ -0,0 +1,20 @@
/*
* Virtio Block Device common helpers
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#ifndef VIRTIO_BLK_COMMON_H
#define VIRTIO_BLK_COMMON_H
#include "hw/virtio/virtio.h"
extern const VirtIOConfigSizeParams virtio_blk_cfg_size_params;
#endif

28
include/hw/virtio/virtio.h

@ -24,7 +24,12 @@
#include "qom/object.h"
#include "hw/virtio/vhost.h"
/* A guest should never accept this. It implies negotiation is broken. */
/*
* A guest should never accept this. It implies negotiation is broken
* between the driver frontend and the device. This bit is re-used for
* vhost-user to advertise VHOST_USER_F_PROTOCOL_FEATURES between QEMU
* and a vhost-user backend.
*/
#define VIRTIO_F_BAD_FEATURE 30
#define VIRTIO_LEGACY_FEATURES ((0x1ULL << VIRTIO_F_BAD_FEATURE) | \
@ -44,8 +49,14 @@ typedef struct VirtIOFeature {
size_t end;
} VirtIOFeature;
size_t virtio_feature_get_config_size(const VirtIOFeature *features,
uint64_t host_features);
typedef struct VirtIOConfigSizeParams {
size_t min_size;
size_t max_size;
const VirtIOFeature *feature_sizes;
} VirtIOConfigSizeParams;
size_t virtio_get_config_size(const VirtIOConfigSizeParams *params,
uint64_t host_features);
typedef struct VirtQueue VirtQueue;
@ -71,6 +82,11 @@ typedef struct VirtQueueElement
#define TYPE_VIRTIO_DEVICE "virtio-device"
OBJECT_DECLARE_TYPE(VirtIODevice, VirtioDeviceClass, VIRTIO_DEVICE)
typedef struct {
int virtio_bit;
const char *feature_desc;
} qmp_virtio_feature_map_t;
enum virtio_device_endian {
VIRTIO_DEVICE_ENDIAN_UNKNOWN,
VIRTIO_DEVICE_ENDIAN_LITTLE,
@ -95,6 +111,7 @@ struct VirtIODevice
VirtQueue *vq;
MemoryListener listener;
uint16_t device_id;
/* @vm_running: current VM running state via virtio_vmstate_change() */
bool vm_running;
bool broken; /* device in invalid state, needs reset */
bool use_disabled_flag; /* allow use of 'disable' flag when needed */
@ -110,6 +127,7 @@ struct VirtIODevice
bool use_guest_notifier_mask;
AddressSpace *dma_as;
QLIST_HEAD(, VirtQueue) *vector_queues;
QTAILQ_ENTRY(VirtIODevice) next;
};
struct VirtioDeviceClass {
@ -371,6 +389,10 @@ static inline bool virtio_device_started(VirtIODevice *vdev, uint8_t status)
return vdev->started;
}
if (!vdev->vm_running) {
return false;
}
return status & VIRTIO_CONFIG_S_DRIVER_OK;
}

5
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);

310
monitor/hmp-cmds.c

@ -43,6 +43,8 @@
#include "qapi/qapi-commands-stats.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"
@ -2472,3 +2474,311 @@ exit:
exit_no_print:
error_free(err);
}
static void hmp_virtio_dump_protocols(Monitor *mon,
VhostDeviceProtocols *pcol)
{
strList *pcol_list = pcol->protocols;
while (pcol_list) {
monitor_printf(mon, "\t%s", pcol_list->value);
pcol_list = pcol_list->next;
if (pcol_list != NULL) {
monitor_printf(mon, ",\n");
}
}
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, "\t%s", status_list->value);
status_list = status_list->next;
if (status_list != NULL) {
monitor_printf(mon, ",\n");
}
}
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, "\t%s", transport_list->value);
transport_list = transport_list->next;
if (transport_list != NULL) {
monitor_printf(mon, ",\n");
}
}
monitor_printf(mon, "\n");
strList *list = features->dev_features;
if (list) {
while (list) {
monitor_printf(mon, "\t%s", list->value);
list = list->next;
if (list != NULL) {
monitor_printf(mon, ",\n");
}
}
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:\n");
hmp_virtio_dump_status(mon, s->status);
monitor_printf(mon, " Guest features:\n");
hmp_virtio_dump_features(mon, s->guest_features);
monitor_printf(mon, " Host features:\n");
hmp_virtio_dump_features(mon, s->host_features);
monitor_printf(mon, " Backend features:\n");
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:\n");
hmp_virtio_dump_features(mon, s->vhost_dev->features);
monitor_printf(mon, " Acked features:\n");
hmp_virtio_dump_features(mon, s->vhost_dev->acked_features);
monitor_printf(mon, " Backend features:\n");
hmp_virtio_dump_features(mon, s->vhost_dev->backend_features);
monitor_printf(mon, " Protocol features:\n");
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:\n");
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, ",\n");
}
}
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);
}

1
qapi/meson.build

@ -49,6 +49,7 @@ qapi_all_modules = [
'stats',
'trace',
'transaction',
'virtio',
'yank',
]
if have_system

1
qapi/qapi-schema.json

@ -94,3 +94,4 @@
{ 'include': 'acpi.json' }
{ 'include': 'pci.json' }
{ 'include': 'stats.json' }
{ 'include': 'virtio.json' }

954
qapi/virtio.json

@ -0,0 +1,954 @@
# -*- 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.1
#
##
{ '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.1
#
# Example:
#
# -> { "execute": "x-query-virtio" }
# <- { "return": [
# {
# "name": "virtio-input",
# "path": "/machine/peripheral-anon/device[4]/virtio-backend"
# },
# {
# "name": "virtio-crypto",
# "path": "/machine/peripheral/crypto0/virtio-backend"
# },
# {
# "name": "virtio-scsi",
# "path": "/machine/peripheral-anon/device[2]/virtio-backend"
# },
# {
# "name": "virtio-net",
# "path": "/machine/peripheral-anon/device[1]/virtio-backend"
# },
# {
# "name": "virtio-serial",
# "path": "/machine/peripheral-anon/device[0]/virtio-backend"
# }
# ]
# }
#
##
{ '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.1
#
##
{ 'struct': 'VhostStatus',
'data': { 'n-mem-sections': 'int',
'n-tmp-sections': 'int',
'nvqs': 'uint32',
'vq-index': 'int',
'features': 'VirtioDeviceFeatures',
'acked-features': 'VirtioDeviceFeatures',
'backend-features': 'VirtioDeviceFeatures',
'protocol-features': 'VhostDeviceProtocols',
'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.1
#
##
{ 'struct': 'VirtioStatus',
'data': { 'name': 'str',
'device-id': 'uint16',
'vhost-started': 'bool',
'device-endian': 'str',
'guest-features': 'VirtioDeviceFeatures',
'host-features': 'VirtioDeviceFeatures',
'backend-features': 'VirtioDeviceFeatures',
'num-vqs': 'int',
'status': 'VirtioDeviceStatus',
'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.1
#
# 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": {
# "transports": [],
# "dev-features": []
# },
# "start-on-kick": false,
# "isr": 1,
# "broken": false,
# "status": {
# "statuses": [
# "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found",
# "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device",
# "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete",
# "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready"
# ]
# },
# "num-vqs": 2,
# "guest-features": {
# "dev-features": [],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"
# ]
# },
# "host-features": {
# "unknown-dev-features": 1073741824,
# "dev-features": [],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)",
# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts",
# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ"
# ]
# },
# "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": {
# "dev-features": [],
# "transports": []
# },
# "nvqs": 2,
# "protocol-features": {
# "protocols": []
# },
# "vq-index": 0,
# "log-enabled": false,
# "acked-features": {
# "dev-features": [
# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers"
# ],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"
# ]
# },
# "features": {
# "dev-features": [
# "VHOST_F_LOG_ALL: Logging write descriptors supported",
# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers"
# ],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_IOMMU_PLATFORM: Device can be used on IOMMU platform",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)",
# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts",
# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ"
# ]
# }
# },
# "backend-features": {
# "dev-features": [
# "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features negotation supported",
# "VIRTIO_NET_F_GSO: Handling GSO-type packets supported",
# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel",
# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported",
# "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported",
# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported",
# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported",
# "VIRTIO_NET_F_CTRL_VQ: Control channel available",
# "VIRTIO_NET_F_STATUS: Configuration status field available",
# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers",
# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO",
# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN",
# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6",
# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4",
# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO",
# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN",
# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6",
# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4",
# "VIRTIO_NET_F_MAC: Device has given MAC address",
# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported",
# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported",
# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported"
# ],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)",
# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts",
# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ"
# ]
# },
# "start-on-kick": false,
# "isr": 1,
# "broken": false,
# "status": {
# "statuses": [
# "VIRTIO_CONFIG_S_ACKNOWLEDGE: Valid virtio device found",
# "VIRTIO_CONFIG_S_DRIVER: Guest OS compatible with device",
# "VIRTIO_CONFIG_S_FEATURES_OK: Feature negotiation complete",
# "VIRTIO_CONFIG_S_DRIVER_OK: Driver setup and ready"
# ]
# },
# "num-vqs": 3,
# "guest-features": {
# "dev-features": [
# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel",
# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported",
# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported",
# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported",
# "VIRTIO_NET_F_CTRL_VQ: Control channel available",
# "VIRTIO_NET_F_STATUS: Configuration status field available",
# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers",
# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO",
# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN",
# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6",
# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4",
# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO",
# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN",
# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6",
# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4",
# "VIRTIO_NET_F_MAC: Device has given MAC address",
# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported",
# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported",
# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported"
# ],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)"
# ]
# },
# "host-features": {
# "dev-features": [
# "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features negotation supported",
# "VIRTIO_NET_F_GSO: Handling GSO-type packets supported",
# "VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control channel",
# "VIRTIO_NET_F_GUEST_ANNOUNCE: Driver sending gratuitous packets supported",
# "VIRTIO_NET_F_CTRL_RX_EXTRA: Extra RX mode control supported",
# "VIRTIO_NET_F_CTRL_VLAN: Control channel VLAN filtering supported",
# "VIRTIO_NET_F_CTRL_RX: Control channel RX mode supported",
# "VIRTIO_NET_F_CTRL_VQ: Control channel available",
# "VIRTIO_NET_F_STATUS: Configuration status field available",
# "VIRTIO_NET_F_MRG_RXBUF: Driver can merge receive buffers",
# "VIRTIO_NET_F_HOST_UFO: Device can receive UFO",
# "VIRTIO_NET_F_HOST_ECN: Device can receive TSO with ECN",
# "VIRTIO_NET_F_HOST_TSO6: Device can receive TSOv6",
# "VIRTIO_NET_F_HOST_TSO4: Device can receive TSOv4",
# "VIRTIO_NET_F_GUEST_UFO: Driver can receive UFO",
# "VIRTIO_NET_F_GUEST_ECN: Driver can receive TSO with ECN",
# "VIRTIO_NET_F_GUEST_TSO6: Driver can receive TSOv6",
# "VIRTIO_NET_F_GUEST_TSO4: Driver can receive TSOv4",
# "VIRTIO_NET_F_MAC: Device has given MAC address",
# "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS: Control channel offloading reconfig. supported",
# "VIRTIO_NET_F_GUEST_CSUM: Driver handling packets with partial checksum supported",
# "VIRTIO_NET_F_CSUM: Device handling packets with partial checksum supported"
# ],
# "transports": [
# "VIRTIO_RING_F_EVENT_IDX: Used & avail. event fields enabled",
# "VIRTIO_RING_F_INDIRECT_DESC: Indirect descriptors supported",
# "VIRTIO_F_VERSION_1: Device compliant for v1 spec (legacy)",
# "VIRTIO_F_ANY_LAYOUT: Device accepts arbitrary desc. layouts",
# "VIRTIO_F_NOTIFY_ON_EMPTY: Notify when device runs out of avail. descs. on VQ"
# ]
# },
# "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' ] }
##
# @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.1
##
{ '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.1
##
{ '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.1
##
{ 'struct': 'VirtioDeviceFeatures',
'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.1
#
##
{ '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.1
#
# 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,
# "name": "vhost-vsock",
# "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,
# "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,
# "name": "virtio-serial",
# "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,
# "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.1
#
##
{ '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.1
#
# 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,
# "name": "virtio-crypto",
# "used-phys": 5216127040,
# "avail-size": 2054,
# "desc-size": 16384,
# "used-size": 8198,
# "desc": 140141447430144,
# "num": 1024,
# "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,
# "name": "vhost-vsock",
# "used-phys": 5182261568,
# "avail-size": 262,
# "desc-size": 2048,
# "used-size": 1030,
# "desc": 140141413580800,
# "num": 128,
# "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' ] }
##
# @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.1
#
##
{ '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.1
#
##
{ '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.1
#
##
{ '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.1
#
##
{ '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.1
#
# 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
qemu-options.hx

@ -2572,6 +2572,8 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
" [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n"
" [,processor-id=%d]\n"
" specify SMBIOS type 4 fields\n"
"-smbios type=8[,external_reference=str][,internal_reference=str][,connector_type=%d][,port_type=%d]\n"
" specify SMBIOS type 8 fields\n"
"-smbios type=11[,value=str][,path=filename]\n"
" specify SMBIOS type 11 fields\n"
"-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n"

BIN
tests/data/acpi/pc/DSDT

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.acpierst

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.acpihmat

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.bridge

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.cphp

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.dimmpxm

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.hpbridge

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.hpbrroot

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.ipmikcs

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.memhp

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.nohpet

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.numamem

Binary file not shown.

BIN
tests/data/acpi/pc/DSDT.roothp

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.acpierst

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.acpihmat

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.applesmc

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.bridge

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.cphp

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.cxl

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.dimmpxm

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.ipmibt

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.ipmismbus

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.ivrs

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.memhp

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.mmio64

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.multi-bridge

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.nohpet

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.numamem

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.pvpanic-isa

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.tis.tpm12

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.tis.tpm2

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.viot

Binary file not shown.

BIN
tests/data/acpi/q35/DSDT.xapic

Binary file not shown.

BIN
tests/data/acpi/virt/GTDT

Binary file not shown.

BIN
tests/data/acpi/virt/GTDT.memhp

Binary file not shown.

BIN
tests/data/acpi/virt/GTDT.numamem

Binary file not shown.

1
tests/qtest/libqos/meson.build

@ -45,6 +45,7 @@ libqos_srcs = files(
'virtio-scsi.c',
'virtio-serial.c',
'virtio-iommu.c',
'virtio-gpio.c',
'generic-pcihost.c',
# qgraph machines:

171
tests/qtest/libqos/virtio-gpio.c

@ -0,0 +1,171 @@
/*
* virtio-gpio nodes for testing
*
* Copyright (c) 2022 Linaro Ltd
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "standard-headers/linux/virtio_config.h"
#include "../libqtest.h"
#include "qemu/module.h"
#include "qgraph.h"
#include "virtio-gpio.h"
static QGuestAllocator *alloc;
static void virtio_gpio_cleanup(QVhostUserGPIO *gpio)
{
QVirtioDevice *vdev = gpio->vdev;
int i;
for (i = 0; i < 2; i++) {
qvirtqueue_cleanup(vdev->bus, gpio->queues[i], alloc);
}
g_free(gpio->queues);
}
/*
* This handles the VirtIO setup from the point of view of the driver
* frontend and therefor doesn't present any vhost specific features
* and in fact masks of the re-used bit.
*/
static void virtio_gpio_setup(QVhostUserGPIO *gpio)
{
QVirtioDevice *vdev = gpio->vdev;
uint64_t features;
int i;
features = qvirtio_get_features(vdev);
features &= ~QVIRTIO_F_BAD_FEATURE;
qvirtio_set_features(vdev, features);
gpio->queues = g_new(QVirtQueue *, 2);
for (i = 0; i < 2; i++) {
gpio->queues[i] = qvirtqueue_setup(vdev, alloc, i);
}
qvirtio_set_driver_ok(vdev);
}
static void *qvirtio_gpio_get_driver(QVhostUserGPIO *v_gpio,
const char *interface)
{
if (!g_strcmp0(interface, "vhost-user-gpio")) {
return v_gpio;
}
if (!g_strcmp0(interface, "virtio")) {
return v_gpio->vdev;
}
g_assert_not_reached();
}
static void *qvirtio_gpio_device_get_driver(void *object,
const char *interface)
{
QVhostUserGPIODevice *v_gpio = object;
return qvirtio_gpio_get_driver(&v_gpio->gpio, interface);
}
/* virtio-gpio (mmio) */
static void qvirtio_gpio_device_destructor(QOSGraphObject *obj)
{
QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj;
virtio_gpio_cleanup(&gpio_dev->gpio);
}
static void qvirtio_gpio_device_start_hw(QOSGraphObject *obj)
{
QVhostUserGPIODevice *gpio_dev = (QVhostUserGPIODevice *) obj;
virtio_gpio_setup(&gpio_dev->gpio);
}
static void *virtio_gpio_device_create(void *virtio_dev,
QGuestAllocator *t_alloc,
void *addr)
{
QVhostUserGPIODevice *virtio_device = g_new0(QVhostUserGPIODevice, 1);
QVhostUserGPIO *interface = &virtio_device->gpio;
interface->vdev = virtio_dev;
alloc = t_alloc;
virtio_device->obj.get_driver = qvirtio_gpio_device_get_driver;
virtio_device->obj.start_hw = qvirtio_gpio_device_start_hw;
virtio_device->obj.destructor = qvirtio_gpio_device_destructor;
return &virtio_device->obj;
}
/* virtio-gpio-pci */
static void qvirtio_gpio_pci_destructor(QOSGraphObject *obj)
{
QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj;
QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj;
virtio_gpio_cleanup(&gpio_pci->gpio);
qvirtio_pci_destructor(pci_vobj);
}
static void qvirtio_gpio_pci_start_hw(QOSGraphObject *obj)
{
QVhostUserGPIOPCI *gpio_pci = (QVhostUserGPIOPCI *) obj;
QOSGraphObject *pci_vobj = &gpio_pci->pci_vdev.obj;
qvirtio_pci_start_hw(pci_vobj);
virtio_gpio_setup(&gpio_pci->gpio);
}
static void *qvirtio_gpio_pci_get_driver(void *object, const char *interface)
{
QVhostUserGPIOPCI *v_gpio = object;
if (!g_strcmp0(interface, "pci-device")) {
return v_gpio->pci_vdev.pdev;
}
return qvirtio_gpio_get_driver(&v_gpio->gpio, interface);
}
static void *virtio_gpio_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
void *addr)
{
QVhostUserGPIOPCI *virtio_spci = g_new0(QVhostUserGPIOPCI, 1);
QVhostUserGPIO *interface = &virtio_spci->gpio;
QOSGraphObject *obj = &virtio_spci->pci_vdev.obj;
virtio_pci_init(&virtio_spci->pci_vdev, pci_bus, addr);
interface->vdev = &virtio_spci->pci_vdev.vdev;
alloc = t_alloc;
obj->get_driver = qvirtio_gpio_pci_get_driver;
obj->start_hw = qvirtio_gpio_pci_start_hw;
obj->destructor = qvirtio_gpio_pci_destructor;
return obj;
}
static void virtio_gpio_register_nodes(void)
{
QPCIAddress addr = {
.devfn = QPCI_DEVFN(4, 0),
};
QOSGraphEdgeOptions edge_opts = { };
/* vhost-user-gpio-device */
edge_opts.extra_device_opts = "id=gpio0,chardev=chr-vhost-user-test";
qos_node_create_driver("vhost-user-gpio-device",
virtio_gpio_device_create);
qos_node_consumes("vhost-user-gpio-device", "virtio-bus", &edge_opts);
qos_node_produces("vhost-user-gpio-device", "vhost-user-gpio");
/* virtio-gpio-pci */
edge_opts.extra_device_opts = "id=gpio0,addr=04.0,chardev=chr-vhost-user-test";
add_qpci_address(&edge_opts, &addr);
qos_node_create_driver("vhost-user-gpio-pci", virtio_gpio_pci_create);
qos_node_consumes("vhost-user-gpio-pci", "pci-bus", &edge_opts);
qos_node_produces("vhost-user-gpio-pci", "vhost-user-gpio");
}
libqos_init(virtio_gpio_register_nodes);

35
tests/qtest/libqos/virtio-gpio.h

@ -0,0 +1,35 @@
/*
* virtio-gpio structures
*
* Copyright (c) 2022 Linaro Ltd
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef TESTS_LIBQOS_VIRTIO_GPIO_H
#define TESTS_LIBQOS_VIRTIO_GPIO_H
#include "qgraph.h"
#include "virtio.h"
#include "virtio-pci.h"
typedef struct QVhostUserGPIO QVhostUserGPIO;
typedef struct QVhostUserGPIOPCI QVhostUserGPIOPCI;
typedef struct QVhostUserGPIODevice QVhostUserGPIODevice;
struct QVhostUserGPIO {
QVirtioDevice *vdev;
QVirtQueue **queues;
};
struct QVhostUserGPIOPCI {
QVirtioPCIDevice pci_vdev;
QVhostUserGPIO gpio;
};
struct QVhostUserGPIODevice {
QOSGraphObject obj;
QVhostUserGPIO gpio;
};
#endif

4
tests/qtest/libqos/virtio.c

@ -101,6 +101,8 @@ uint64_t qvirtio_get_features(QVirtioDevice *d)
void qvirtio_set_features(QVirtioDevice *d, uint64_t features)
{
g_assert(!(features & QVIRTIO_F_BAD_FEATURE));
d->features = features;
d->bus->set_features(d, features);
@ -108,7 +110,7 @@ void qvirtio_set_features(QVirtioDevice *d, uint64_t features)
* This could be a separate function for drivers that want to access
* configuration space before setting FEATURES_OK, but no existing users
* need that and it's less code for callers if this is done implicitly.
*/
*/
if (features & (1ull << VIRTIO_F_VERSION_1)) {
uint8_t status = d->bus->get_status(d) |
VIRTIO_CONFIG_S_FEATURES_OK;

1
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 */

9
tests/qtest/qos-test.c

@ -185,7 +185,9 @@ static void run_one_test(const void *arg)
static void subprocess_run_one_test(const void *arg)
{
const gchar *path = arg;
g_test_trap_subprocess(path, 0, 0);
g_test_trap_subprocess(path, 180 * G_USEC_PER_SEC,
G_TEST_SUBPROCESS_INHERIT_STDOUT |
G_TEST_SUBPROCESS_INHERIT_STDERR);
g_test_trap_assert_passed();
}
@ -319,6 +321,11 @@ static void walk_path(QOSGraphNode *orig_path, int len)
int main(int argc, char **argv, char** envp)
{
g_test_init(&argc, &argv, NULL);
if (g_test_subprocess()) {
qos_printf("qos_test running single test in subprocess\n");
}
if (g_test_verbose()) {
qos_printf("ENVIRONMENT VARIABLES: {\n");
for (char **env = envp; *env != 0; env++) {

175
tests/qtest/vhost-user-test.c

@ -26,11 +26,13 @@
#include "libqos/virtio-pci.h"
#include "libqos/malloc-pc.h"
#include "libqos/qgraph_internal.h"
#include "hw/virtio/virtio-net.h"
#include "standard-headers/linux/vhost_types.h"
#include "standard-headers/linux/virtio_ids.h"
#include "standard-headers/linux/virtio_net.h"
#include "standard-headers/linux/virtio_gpio.h"
#ifdef CONFIG_LINUX
#include <sys/vfs.h>
@ -52,9 +54,12 @@
#define VHOST_MAX_VIRTQUEUES 0x100
#define VHOST_USER_F_PROTOCOL_FEATURES 30
#define VIRTIO_F_VERSION_1 32
#define VHOST_USER_PROTOCOL_F_MQ 0
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6
#define VHOST_USER_PROTOCOL_F_CONFIG 9
#define VHOST_LOG_PAGE 0x1000
@ -78,6 +83,8 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
VHOST_USER_GET_QUEUE_NUM = 17,
VHOST_USER_SET_VRING_ENABLE = 18,
VHOST_USER_GET_CONFIG = 24,
VHOST_USER_SET_CONFIG = 25,
VHOST_USER_MAX
} VhostUserRequest;
@ -137,6 +144,7 @@ enum {
enum {
VHOST_USER_NET,
VHOST_USER_GPIO,
};
typedef struct TestServer {
@ -168,10 +176,11 @@ struct vhost_user_ops {
const char *chr_opts);
/* VHOST-USER commands. */
uint64_t (*get_features)(TestServer *s);
void (*set_features)(TestServer *s, CharBackend *chr,
VhostUserMsg *msg);
VhostUserMsg *msg);
void (*get_protocol_features)(TestServer *s,
CharBackend *chr, VhostUserMsg *msg);
CharBackend *chr, VhostUserMsg *msg);
};
static const char *init_hugepagefs(void);
@ -194,6 +203,19 @@ static void append_vhost_net_opts(TestServer *s, GString *cmd_line,
chr_opts, s->chr_name);
}
/*
* For GPIO there are no other magic devices we need to add (like
* block or netdev) so all we need to worry about is the vhost-user
* chardev socket.
*/
static void append_vhost_gpio_opts(TestServer *s, GString *cmd_line,
const char *chr_opts)
{
g_string_append_printf(cmd_line, QEMU_CMD_CHR,
s->chr_name, s->socket_path,
chr_opts);
}
static void append_mem_opts(TestServer *server, GString *cmd_line,
int size, enum test_memfd memfd)
{
@ -316,7 +338,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
}
if (size != VHOST_USER_HDR_SIZE) {
g_test_message("Wrong message size received %d", size);
qos_printf("%s: Wrong message size received %d\n", __func__, size);
return;
}
@ -327,28 +349,30 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
p += VHOST_USER_HDR_SIZE;
size = qemu_chr_fe_read_all(chr, p, msg.size);
if (size != msg.size) {
g_test_message("Wrong message size received %d != %d",
size, msg.size);
qos_printf("%s: Wrong message size received %d != %d\n",
__func__, size, msg.size);
return;
}
}
switch (msg.request) {
case VHOST_USER_GET_FEATURES:
/* Mandatory for tests to define get_features */
g_assert(s->vu_ops->get_features);
/* send back features to qemu */
msg.flags |= VHOST_USER_REPLY_MASK;
msg.size = sizeof(m.payload.u64);
msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL |
0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
if (s->queues > 1) {
msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ;
}
if (s->test_flags >= TEST_FLAGS_BAD) {
msg.payload.u64 = 0;
s->test_flags = TEST_FLAGS_END;
} else {
msg.payload.u64 = s->vu_ops->get_features(s);
}
p = (uint8_t *) &msg;
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
qemu_chr_fe_write_all(chr, (uint8_t *) &msg,
VHOST_USER_HDR_SIZE + msg.size);
break;
case VHOST_USER_SET_FEATURES:
@ -357,12 +381,55 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
}
break;
case VHOST_USER_SET_OWNER:
/*
* We don't need to do anything here, the remote is just
* letting us know it is in charge. Just log it.
*/
qos_printf("set_owner: start of session\n");
break;
case VHOST_USER_GET_PROTOCOL_FEATURES:
if (s->vu_ops->get_protocol_features) {
s->vu_ops->get_protocol_features(s, chr, &msg);
}
break;
case VHOST_USER_GET_CONFIG:
/*
* Treat GET_CONFIG as a NOP and just reply and let the guest
* consider we have updated its memory. Tests currently don't
* require working configs.
*/
msg.flags |= VHOST_USER_REPLY_MASK;
p = (uint8_t *) &msg;
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
break;
case VHOST_USER_SET_PROTOCOL_FEATURES:
/*
* We did set VHOST_USER_F_PROTOCOL_FEATURES so its valid for
* the remote end to send this. There is no handshake reply so
* just log the details for debugging.
*/
qos_printf("set_protocol_features: 0x%"PRIx64 "\n", msg.payload.u64);
break;
/*
* A real vhost-user backend would actually set the size and
* address of the vrings but we can simply report them.
*/
case VHOST_USER_SET_VRING_NUM:
qos_printf("set_vring_num: %d/%d\n",
msg.payload.state.index, msg.payload.state.num);
break;
case VHOST_USER_SET_VRING_ADDR:
qos_printf("set_vring_addr: 0x%"PRIx64"/0x%"PRIx64"/0x%"PRIx64"\n",
msg.payload.addr.avail_user_addr,
msg.payload.addr.desc_user_addr,
msg.payload.addr.used_user_addr);
break;
case VHOST_USER_GET_VRING_BASE:
/* send back vring base to qemu */
msg.flags |= VHOST_USER_REPLY_MASK;
@ -427,7 +494,18 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size);
break;
case VHOST_USER_SET_VRING_ENABLE:
/*
* Another case we ignore as we don't need to respond. With a
* fully functioning vhost-user we would enable/disable the
* vring monitoring.
*/
qos_printf("set_vring(%d)=%s\n", msg.payload.state.index,
msg.payload.state.num ? "enabled" : "disabled");
break;
default:
qos_printf("vhost-user: un-handled message: %d\n", msg.request);
break;
}
@ -450,7 +528,7 @@ static const char *init_hugepagefs(void)
}
if (access(path, R_OK | W_OK | X_OK)) {
g_test_message("access on path (%s): %s", path, strerror(errno));
qos_printf("access on path (%s): %s", path, strerror(errno));
g_test_fail();
return NULL;
}
@ -460,13 +538,13 @@ static const char *init_hugepagefs(void)
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
g_test_message("statfs on path (%s): %s", path, strerror(errno));
qos_printf("statfs on path (%s): %s", path, strerror(errno));
g_test_fail();
return NULL;
}
if (fs.f_type != HUGETLBFS_MAGIC) {
g_test_message("Warning: path not on HugeTLBFS: %s", path);
qos_printf("Warning: path not on HugeTLBFS: %s", path);
g_test_fail();
return NULL;
}
@ -938,11 +1016,23 @@ static void test_multiqueue(void *obj, void *arg, QGuestAllocator *alloc)
wait_for_rings_started(s, s->queues * 2);
}
static uint64_t vu_net_get_features(TestServer *s)
{
uint64_t features = 0x1ULL << VHOST_F_LOG_ALL |
0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
if (s->queues > 1) {
features |= 0x1ULL << VIRTIO_NET_F_MQ;
}
return features;
}
static void vu_net_set_features(TestServer *s, CharBackend *chr,
VhostUserMsg *msg)
VhostUserMsg *msg)
{
g_assert_cmpint(msg->payload.u64 &
(0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL);
g_assert(msg->payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES));
if (s->test_flags == TEST_FLAGS_DISCONNECT) {
qemu_chr_fe_disconnect(chr);
s->test_flags = TEST_FLAGS_BAD;
@ -969,6 +1059,7 @@ static struct vhost_user_ops g_vu_net_ops = {
.append_opts = append_vhost_net_opts,
.get_features = vu_net_get_features,
.set_features = vu_net_set_features,
.get_protocol_features = vu_net_get_protocol_features,
};
@ -1017,3 +1108,51 @@ static void register_vhost_user_test(void)
test_multiqueue, &opts);
}
libqos_init(register_vhost_user_test);
static uint64_t vu_gpio_get_features(TestServer *s)
{
return 0x1ULL << VIRTIO_F_VERSION_1 |
0x1ULL << VIRTIO_GPIO_F_IRQ |
0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
}
/*
* This stub can't handle all the message types but we should reply
* that we support VHOST_USER_PROTOCOL_F_CONFIG as gpio would use it
* talking to a read vhost-user daemon.
*/
static void vu_gpio_get_protocol_features(TestServer *s, CharBackend *chr,
VhostUserMsg *msg)
{
/* send back features to qemu */
msg->flags |= VHOST_USER_REPLY_MASK;
msg->size = sizeof(m.payload.u64);
msg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_CONFIG;
qemu_chr_fe_write_all(chr, (uint8_t *)msg, VHOST_USER_HDR_SIZE + msg->size);
}
static struct vhost_user_ops g_vu_gpio_ops = {
.type = VHOST_USER_GPIO,
.append_opts = append_vhost_gpio_opts,
.get_features = vu_gpio_get_features,
.set_features = vu_net_set_features,
.get_protocol_features = vu_gpio_get_protocol_features,
};
static void register_vhost_gpio_test(void)
{
QOSGraphTestOptions opts = {
.before = vhost_user_test_setup,
.subprocess = true,
.arg = &g_vu_gpio_ops,
};
qemu_add_opts(&qemu_chardev_opts);
qos_add_test("read-guest-mem/memfile",
"vhost-user-gpio", test_read_guest_mem, &opts);
}
libqos_init(register_vhost_gpio_test);

Loading…
Cancel
Save