All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
@ 2019-07-29 12:57 Sergio Lopez
  2019-07-29 13:10 ` no-reply
                   ` (4 more replies)
  0 siblings, 5 replies; 27+ messages in thread
From: Sergio Lopez @ 2019-07-29 12:57 UTC (permalink / raw)
  To: mst; +Cc: peter.maydell, qemu-devel, Sergio Lopez

Implement the modern (v2) personality, according to the VirtIO 1.0
specification.

Support for v2 among guests is not as widespread as it'd be
desirable. While the Linux driver has had it for a while, support is
missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.

For this reason, the v2 personality is disabled, keeping the legacy
behavior as default. Machine types willing to use v2, can enable it
using MachineClass's compat_props.

Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 hw/virtio/virtio-mmio.c | 264 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 254 insertions(+), 10 deletions(-)

diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 97b7f35496..1da841336f 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -47,14 +47,24 @@
         OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
 
 #define VIRT_MAGIC 0x74726976 /* 'virt' */
-#define VIRT_VERSION 1
+#define VIRT_VERSION_LEGACY 1
+#define VIRT_VERSION_MODERN 2
 #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
 
+typedef struct VirtIOMMIOQueue {
+    uint16_t num;
+    bool enabled;
+    uint32_t desc[2];
+    uint32_t avail[2];
+    uint32_t used[2];
+} VirtIOMMIOQueue;
+
 typedef struct {
     /* Generic */
     SysBusDevice parent_obj;
     MemoryRegion iomem;
     qemu_irq irq;
+    bool modern;
     /* Guest accessible state needing migration and reset */
     uint32_t host_features_sel;
     uint32_t guest_features_sel;
@@ -62,6 +72,9 @@ typedef struct {
     /* virtio-bus */
     VirtioBusState bus;
     bool format_transport_address;
+    /* Fields only used for v2 (modern) devices */
+    uint32_t guest_features[2];
+    VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
 } VirtIOMMIOProxy;
 
 static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
@@ -115,7 +128,11 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
         case VIRTIO_MMIO_MAGIC_VALUE:
             return VIRT_MAGIC;
         case VIRTIO_MMIO_VERSION:
-            return VIRT_VERSION;
+            if (proxy->modern) {
+                return VIRT_VERSION_MODERN;
+            } else {
+                return VIRT_VERSION_LEGACY;
+            }
         case VIRTIO_MMIO_VENDOR_ID:
             return VIRT_VENDOR;
         default:
@@ -146,14 +163,18 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
     case VIRTIO_MMIO_MAGIC_VALUE:
         return VIRT_MAGIC;
     case VIRTIO_MMIO_VERSION:
-        return VIRT_VERSION;
+        if (proxy->modern) {
+            return VIRT_VERSION_MODERN;
+        } else {
+            return VIRT_VERSION_LEGACY;
+        }
     case VIRTIO_MMIO_DEVICE_ID:
         return vdev->device_id;
     case VIRTIO_MMIO_VENDOR_ID:
         return VIRT_VENDOR;
     case VIRTIO_MMIO_DEVICE_FEATURES:
         if (proxy->host_features_sel) {
-            return 0;
+            return vdev->host_features >> 32;
         }
         return vdev->host_features;
     case VIRTIO_MMIO_QUEUE_NUM_MAX:
@@ -162,12 +183,34 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
         }
         return VIRTQUEUE_MAX_SIZE;
     case VIRTIO_MMIO_QUEUE_PFN:
+        if (proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: read from legacy register in modern mode\n",
+                          __func__);
+            return 0;
+        }
         return virtio_queue_get_addr(vdev, vdev->queue_sel)
             >> proxy->guest_page_shift;
+    case VIRTIO_MMIO_QUEUE_READY:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: read from modern register in legacy mode\n",
+                          __func__);
+            return 0;
+        }
+        return proxy->vqs[vdev->queue_sel].enabled;
     case VIRTIO_MMIO_INTERRUPT_STATUS:
         return atomic_read(&vdev->isr);
     case VIRTIO_MMIO_STATUS:
         return vdev->status;
+    case VIRTIO_MMIO_CONFIG_GENERATION:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: read from modern register in legacy mode\n",
+                          __func__);
+            return 0;
+        }
+        return vdev->generation;
     case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
     case VIRTIO_MMIO_DRIVER_FEATURES:
     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
@@ -177,6 +220,12 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
     case VIRTIO_MMIO_QUEUE_ALIGN:
     case VIRTIO_MMIO_QUEUE_NOTIFY:
     case VIRTIO_MMIO_INTERRUPT_ACK:
+    case VIRTIO_MMIO_QUEUE_DESC_LOW:
+    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+    case VIRTIO_MMIO_QUEUE_USED_LOW:
+    case VIRTIO_MMIO_QUEUE_USED_HIGH:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: read of write-only register\n",
                       __func__);
@@ -232,14 +281,26 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
         proxy->host_features_sel = value;
         break;
     case VIRTIO_MMIO_DRIVER_FEATURES:
-        if (!proxy->guest_features_sel) {
+        if (proxy->modern) {
+            proxy->guest_features[proxy->guest_features_sel] = value;
+        } else if (!proxy->guest_features_sel) {
             virtio_set_features(vdev, value);
         }
         break;
     case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
-        proxy->guest_features_sel = value;
+        if (value) {
+            proxy->guest_features_sel = 1;
+        } else {
+            proxy->guest_features_sel = 0;
+        }
         break;
     case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+        if (proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
         proxy->guest_page_shift = ctz32(value);
         if (proxy->guest_page_shift > 31) {
             proxy->guest_page_shift = 0;
@@ -253,15 +314,29 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
         break;
     case VIRTIO_MMIO_QUEUE_NUM:
         trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
-        virtio_queue_set_num(vdev, vdev->queue_sel, value);
-        /* Note: only call this function for legacy devices */
-        virtio_queue_update_rings(vdev, vdev->queue_sel);
+        if (proxy->modern) {
+            proxy->vqs[vdev->queue_sel].num = value;
+        } else {
+            virtio_queue_set_num(vdev, vdev->queue_sel, value);
+            virtio_queue_update_rings(vdev, vdev->queue_sel);
+        }
         break;
     case VIRTIO_MMIO_QUEUE_ALIGN:
-        /* Note: this is only valid for legacy devices */
+        if (proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
         virtio_queue_set_align(vdev, vdev->queue_sel, value);
         break;
     case VIRTIO_MMIO_QUEUE_PFN:
+        if (proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
         if (value == 0) {
             virtio_reset(vdev);
         } else {
@@ -269,6 +344,24 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
                                   value << proxy->guest_page_shift);
         }
         break;
+    case VIRTIO_MMIO_QUEUE_READY:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to modern register in legacy mode\n",
+                          __func__);
+            return;
+        }
+        virtio_queue_set_num(vdev, vdev->queue_sel,
+                             proxy->vqs[vdev->queue_sel].num);
+        virtio_queue_set_rings(vdev, vdev->queue_sel,
+                       ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
+                       proxy->vqs[vdev->queue_sel].desc[0],
+                       ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
+                       proxy->vqs[vdev->queue_sel].avail[0],
+                       ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
+                       proxy->vqs[vdev->queue_sel].used[0]);
+        proxy->vqs[vdev->queue_sel].enabled = 1;
+        break;
     case VIRTIO_MMIO_QUEUE_NOTIFY:
         if (value < VIRTIO_QUEUE_MAX) {
             virtio_queue_notify(vdev, value);
@@ -283,6 +376,12 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
             virtio_mmio_stop_ioeventfd(proxy);
         }
 
+        if (proxy->modern && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
+            virtio_set_features(vdev,
+                                ((uint64_t)proxy->guest_features[1]) << 32 |
+                                proxy->guest_features[0]);
+        }
+
         virtio_set_status(vdev, value & 0xff);
 
         if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
@@ -293,6 +392,60 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
             virtio_reset(vdev);
         }
         break;
+    case VIRTIO_MMIO_QUEUE_DESC_LOW:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].desc[0] = value;
+        break;
+    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].desc[1] = value;
+        break;
+    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].avail[0] = value;
+        break;
+    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].avail[1] = value;
+        break;
+    case VIRTIO_MMIO_QUEUE_USED_LOW:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].used[0] = value;
+        break;
+    case VIRTIO_MMIO_QUEUE_USED_HIGH:
+        if (!proxy->modern) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: write to legacy register in modern mode\n",
+                          __func__);
+            return;
+        }
+        proxy->vqs[vdev->queue_sel].used[1] = value;
+        break;
     case VIRTIO_MMIO_MAGIC_VALUE:
     case VIRTIO_MMIO_VERSION:
     case VIRTIO_MMIO_DEVICE_ID:
@@ -300,6 +453,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
     case VIRTIO_MMIO_DEVICE_FEATURES:
     case VIRTIO_MMIO_QUEUE_NUM_MAX:
     case VIRTIO_MMIO_INTERRUPT_STATUS:
+    case VIRTIO_MMIO_CONFIG_GENERATION:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: write to readonly register\n",
                       __func__);
@@ -349,15 +503,90 @@ static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
     qemu_put_be32(f, proxy->guest_page_shift);
 }
 
+static const VMStateDescription vmstate_virtio_mmio_modern_queue_state = {
+    .name = "virtio_mmio/modern_queue_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(num, VirtIOMMIOQueue),
+        VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
+        VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
+        VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
+        VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_virtio_mmio_modern_state_sub = {
+    .name = "virtio_mmio/modern_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
+        VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
+                             vmstate_virtio_mmio_modern_queue_state,
+                             VirtIOMMIOQueue),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_virtio_mmio = {
+    .name = "virtio_mmio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_virtio_mmio_modern_state_sub,
+        NULL
+    }
+};
+
+static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
+{
+    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+    vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
+}
+
+static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
+{
+    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+    return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
+}
+
+static bool virtio_mmio_has_extra_state(DeviceState *opaque)
+{
+    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
+
+    return proxy->modern;
+}
+
 static void virtio_mmio_reset(DeviceState *d)
 {
     VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+    int i;
 
     virtio_mmio_stop_ioeventfd(proxy);
     virtio_bus_reset(&proxy->bus);
     proxy->host_features_sel = 0;
     proxy->guest_features_sel = 0;
     proxy->guest_page_shift = 0;
+
+    if (proxy->modern) {
+        proxy->guest_features[0] = proxy->guest_features[1] = 0;
+
+        for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+            proxy->vqs[i].enabled = 0;
+            proxy->vqs[i].num = 0;
+            proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
+            proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
+            proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
+        }
+    }
 }
 
 static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
@@ -420,11 +649,22 @@ assign_error:
     return r;
 }
 
+static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
+{
+    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
+
+    if (proxy->modern) {
+        virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+    }
+}
+
 /* virtio-mmio device */
 
 static Property virtio_mmio_properties[] = {
     DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
                      format_transport_address, true),
+    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -508,9 +748,13 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
     k->notify = virtio_mmio_update_irq;
     k->save_config = virtio_mmio_save_config;
     k->load_config = virtio_mmio_load_config;
+    k->save_extra_state = virtio_mmio_save_extra_state;
+    k->load_extra_state = virtio_mmio_load_extra_state;
+    k->has_extra_state = virtio_mmio_has_extra_state;
     k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
     k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
     k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
+    k->pre_plugged = virtio_mmio_pre_plugged;
     k->has_variable_vring_alignment = true;
     bus_class->max_dev = 1;
     bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
@ 2019-07-29 13:10 ` no-reply
  2019-07-30  7:06 ` Stefan Hajnoczi
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: no-reply @ 2019-07-29 13:10 UTC (permalink / raw)
  To: slp; +Cc: peter.maydell, qemu-devel, slp, mst

Patchew URL: https://patchew.org/QEMU/20190729125755.45008-1-slp@redhat.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Subject: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
Message-id: 20190729125755.45008-1-slp@redhat.com

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20190729125755.45008-1-slp@redhat.com -> patchew/20190729125755.45008-1-slp@redhat.com
Submodule 'capstone' (https://git.qemu.org/git/capstone.git) registered for path 'capstone'
Submodule 'dtc' (https://git.qemu.org/git/dtc.git) registered for path 'dtc'
Submodule 'roms/QemuMacDrivers' (https://git.qemu.org/git/QemuMacDrivers.git) registered for path 'roms/QemuMacDrivers'
Submodule 'roms/SLOF' (https://git.qemu.org/git/SLOF.git) registered for path 'roms/SLOF'
Submodule 'roms/edk2' (https://git.qemu.org/git/edk2.git) registered for path 'roms/edk2'
Submodule 'roms/ipxe' (https://git.qemu.org/git/ipxe.git) registered for path 'roms/ipxe'
Submodule 'roms/openbios' (https://git.qemu.org/git/openbios.git) registered for path 'roms/openbios'
Submodule 'roms/openhackware' (https://git.qemu.org/git/openhackware.git) registered for path 'roms/openhackware'
Submodule 'roms/opensbi' (https://git.qemu.org/git/opensbi.git) registered for path 'roms/opensbi'
Submodule 'roms/qemu-palcode' (https://git.qemu.org/git/qemu-palcode.git) registered for path 'roms/qemu-palcode'
Submodule 'roms/seabios' (https://git.qemu.org/git/seabios.git/) registered for path 'roms/seabios'
Submodule 'roms/seabios-hppa' (https://git.qemu.org/git/seabios-hppa.git) registered for path 'roms/seabios-hppa'
Submodule 'roms/sgabios' (https://git.qemu.org/git/sgabios.git) registered for path 'roms/sgabios'
Submodule 'roms/skiboot' (https://git.qemu.org/git/skiboot.git) registered for path 'roms/skiboot'
Submodule 'roms/u-boot' (https://git.qemu.org/git/u-boot.git) registered for path 'roms/u-boot'
Submodule 'roms/u-boot-sam460ex' (https://git.qemu.org/git/u-boot-sam460ex.git) registered for path 'roms/u-boot-sam460ex'
Submodule 'slirp' (https://git.qemu.org/git/libslirp.git) registered for path 'slirp'
Submodule 'tests/fp/berkeley-softfloat-3' (https://git.qemu.org/git/berkeley-softfloat-3.git) registered for path 'tests/fp/berkeley-softfloat-3'
Submodule 'tests/fp/berkeley-testfloat-3' (https://git.qemu.org/git/berkeley-testfloat-3.git) registered for path 'tests/fp/berkeley-testfloat-3'
Submodule 'ui/keycodemapdb' (https://git.qemu.org/git/keycodemapdb.git) registered for path 'ui/keycodemapdb'
Cloning into 'capstone'...
Submodule path 'capstone': checked out '22ead3e0bfdb87516656453336160e0a37b066bf'
Cloning into 'dtc'...
Submodule path 'dtc': checked out '88f18909db731a627456f26d779445f84e449536'
Cloning into 'roms/QemuMacDrivers'...
Submodule path 'roms/QemuMacDrivers': checked out '90c488d5f4a407342247b9ea869df1c2d9c8e266'
Cloning into 'roms/SLOF'...
Submodule path 'roms/SLOF': checked out 'ba1ab360eebe6338bb8d7d83a9220ccf7e213af3'
Cloning into 'roms/edk2'...
Submodule path 'roms/edk2': checked out '20d2e5a125e34fc8501026613a71549b2a1a3e54'
Submodule 'SoftFloat' (https://github.com/ucb-bar/berkeley-softfloat-3.git) registered for path 'ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3'
Submodule 'CryptoPkg/Library/OpensslLib/openssl' (https://github.com/openssl/openssl) registered for path 'CryptoPkg/Library/OpensslLib/openssl'
Cloning into 'ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3'...
Submodule path 'roms/edk2/ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3': checked out 'b64af41c3276f97f0e181920400ee056b9c88037'
Cloning into 'CryptoPkg/Library/OpensslLib/openssl'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl': checked out '50eaac9f3337667259de725451f201e784599687'
Submodule 'boringssl' (https://boringssl.googlesource.com/boringssl) registered for path 'boringssl'
Submodule 'krb5' (https://github.com/krb5/krb5) registered for path 'krb5'
Submodule 'pyca.cryptography' (https://github.com/pyca/cryptography.git) registered for path 'pyca-cryptography'
Cloning into 'boringssl'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/boringssl': checked out '2070f8ad9151dc8f3a73bffaa146b5e6937a583f'
Cloning into 'krb5'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/krb5': checked out 'b9ad6c49505c96a088326b62a52568e3484f2168'
Cloning into 'pyca-cryptography'...
Submodule path 'roms/edk2/CryptoPkg/Library/OpensslLib/openssl/pyca-cryptography': checked out '09403100de2f6f1cdd0d484dcb8e620f1c335c8f'
Cloning into 'roms/ipxe'...
Submodule path 'roms/ipxe': checked out 'de4565cbe76ea9f7913a01f331be3ee901bb6e17'
Cloning into 'roms/openbios'...
Submodule path 'roms/openbios': checked out 'c79e0ecb84f4f1ee3f73f521622e264edd1bf174'
Cloning into 'roms/openhackware'...
Submodule path 'roms/openhackware': checked out 'c559da7c8eec5e45ef1f67978827af6f0b9546f5'
Cloning into 'roms/opensbi'...
Submodule path 'roms/opensbi': checked out 'ce228ee0919deb9957192d723eecc8aaae2697c6'
Cloning into 'roms/qemu-palcode'...
Submodule path 'roms/qemu-palcode': checked out 'bf0e13698872450164fa7040da36a95d2d4b326f'
Cloning into 'roms/seabios'...
Submodule path 'roms/seabios': checked out 'a5cab58e9a3fb6e168aba919c5669bea406573b4'
Cloning into 'roms/seabios-hppa'...
Submodule path 'roms/seabios-hppa': checked out '0f4fe84658165e96ce35870fd19fc634e182e77b'
Cloning into 'roms/sgabios'...
Submodule path 'roms/sgabios': checked out 'cbaee52287e5f32373181cff50a00b6c4ac9015a'
Cloning into 'roms/skiboot'...
Submodule path 'roms/skiboot': checked out '261ca8e779e5138869a45f174caa49be6a274501'
Cloning into 'roms/u-boot'...
Submodule path 'roms/u-boot': checked out 'd3689267f92c5956e09cc7d1baa4700141662bff'
Cloning into 'roms/u-boot-sam460ex'...
Submodule path 'roms/u-boot-sam460ex': checked out '60b3916f33e617a815973c5a6df77055b2e3a588'
Cloning into 'slirp'...
Submodule path 'slirp': checked out 'f0da6726207b740f6101028b2992f918477a4b08'
Cloning into 'tests/fp/berkeley-softfloat-3'...
Submodule path 'tests/fp/berkeley-softfloat-3': checked out 'b64af41c3276f97f0e181920400ee056b9c88037'
Cloning into 'tests/fp/berkeley-testfloat-3'...
Submodule path 'tests/fp/berkeley-testfloat-3': checked out '5a59dcec19327396a011a17fd924aed4fec416b3'
Cloning into 'ui/keycodemapdb'...
Submodule path 'ui/keycodemapdb': checked out '6b3d716e2b6472eb7189d3220552280ef3d832ce'
Switched to a new branch 'test'
b06a274 virtio-mmio: implement modern (v2) personality (virtio-1)

=== OUTPUT BEGIN ===
ERROR: spaces required around that '*' (ctx:VxV)
#352: FILE: hw/virtio/virtio-mmio.c:541:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 1 errors, 0 warnings, 401 lines checked

Commit b06a2743fbf4 (virtio-mmio: implement modern (v2) personality (virtio-1)) has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20190729125755.45008-1-slp@redhat.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
  2019-07-29 13:10 ` no-reply
@ 2019-07-30  7:06 ` Stefan Hajnoczi
  2019-07-30  8:34 ` Michael S. Tsirkin
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 27+ messages in thread
From: Stefan Hajnoczi @ 2019-07-30  7:06 UTC (permalink / raw)
  To: Sergio Lopez; +Cc: peter.maydell, qemu-devel, mst

[-- Attachment #1: Type: text/plain, Size: 710 bytes --]

On Mon, Jul 29, 2019 at 02:57:55PM +0200, Sergio Lopez wrote:
> @@ -162,12 +183,34 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>          }
>          return VIRTQUEUE_MAX_SIZE;
>      case VIRTIO_MMIO_QUEUE_PFN:
> +        if (proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: read from legacy register in modern mode\n",
> +                          __func__);

If you respin this series it would be nice to indicate which register
was accessed since these error messages are identical for the other
modern registers and there is no way to distinguish for troubleshooting.

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
  2019-07-29 13:10 ` no-reply
  2019-07-30  7:06 ` Stefan Hajnoczi
@ 2019-07-30  8:34 ` Michael S. Tsirkin
  2019-07-31 12:22   ` Sergio Lopez
  2019-07-30 10:25 ` Andrea Bolognani
  2019-07-30 16:06 ` Laszlo Ersek
  4 siblings, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-07-30  8:34 UTC (permalink / raw)
  To: Sergio Lopez; +Cc: peter.maydell, qemu-devel, ehabkost

On Mon, Jul 29, 2019 at 02:57:55PM +0200, Sergio Lopez wrote:
> Implement the modern (v2) personality, according to the VirtIO 1.0
> specification.
> 
> Support for v2 among guests is not as widespread as it'd be
> desirable. While the Linux driver has had it for a while, support is
> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.

The fact that there was no open source hypervisor implementation has
probably contributed to this :)

> For this reason, the v2 personality is disabled, keeping the legacy
> behavior as default.

I agree it's a good default for existing machine types.

> Machine types willing to use v2, can enable it
> using MachineClass's compat_props.

Hmm. Are compat_props really the recommended mechanism to
tweak defaults? I was under the impression it's
only for compatibility with old machine types.
Eduardo, any opinion on this?

> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>

Endian-ness seems to be wrong:

static const MemoryRegionOps virtio_mem_ops = {
    .read = virtio_mmio_read,
    .write = virtio_mmio_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
};

you will see this if you test a big endian guest.


> ---
>  hw/virtio/virtio-mmio.c | 264 ++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 254 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> index 97b7f35496..1da841336f 100644
> --- a/hw/virtio/virtio-mmio.c
> +++ b/hw/virtio/virtio-mmio.c
> @@ -47,14 +47,24 @@
>          OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
>  
>  #define VIRT_MAGIC 0x74726976 /* 'virt' */
> -#define VIRT_VERSION 1
> +#define VIRT_VERSION_LEGACY 1
> +#define VIRT_VERSION_MODERN 2
>  #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
>  
> +typedef struct VirtIOMMIOQueue {
> +    uint16_t num;
> +    bool enabled;
> +    uint32_t desc[2];
> +    uint32_t avail[2];
> +    uint32_t used[2];
> +} VirtIOMMIOQueue;
> +
>  typedef struct {
>      /* Generic */
>      SysBusDevice parent_obj;
>      MemoryRegion iomem;
>      qemu_irq irq;
> +    bool modern;
>      /* Guest accessible state needing migration and reset */
>      uint32_t host_features_sel;
>      uint32_t guest_features_sel;
> @@ -62,6 +72,9 @@ typedef struct {
>      /* virtio-bus */
>      VirtioBusState bus;
>      bool format_transport_address;
> +    /* Fields only used for v2 (modern) devices */
> +    uint32_t guest_features[2];
> +    VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
>  } VirtIOMMIOProxy;
>  
>  static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
> @@ -115,7 +128,11 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>          case VIRTIO_MMIO_MAGIC_VALUE:
>              return VIRT_MAGIC;
>          case VIRTIO_MMIO_VERSION:
> -            return VIRT_VERSION;
> +            if (proxy->modern) {
> +                return VIRT_VERSION_MODERN;
> +            } else {
> +                return VIRT_VERSION_LEGACY;
> +            }
>          case VIRTIO_MMIO_VENDOR_ID:
>              return VIRT_VENDOR;
>          default:
> @@ -146,14 +163,18 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>      case VIRTIO_MMIO_MAGIC_VALUE:
>          return VIRT_MAGIC;
>      case VIRTIO_MMIO_VERSION:
> -        return VIRT_VERSION;
> +        if (proxy->modern) {
> +            return VIRT_VERSION_MODERN;
> +        } else {
> +            return VIRT_VERSION_LEGACY;
> +        }
>      case VIRTIO_MMIO_DEVICE_ID:
>          return vdev->device_id;
>      case VIRTIO_MMIO_VENDOR_ID:
>          return VIRT_VENDOR;
>      case VIRTIO_MMIO_DEVICE_FEATURES:
>          if (proxy->host_features_sel) {
> -            return 0;
> +            return vdev->host_features >> 32;

I'd do vdev->host_features >> (32 * proxy->host_features_sel);

>          }
>          return vdev->host_features;
>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
> @@ -162,12 +183,34 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>          }
>          return VIRTQUEUE_MAX_SIZE;
>      case VIRTIO_MMIO_QUEUE_PFN:
> +        if (proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: read from legacy register in modern mode\n",
> +                          __func__);
> +            return 0;
> +        }
>          return virtio_queue_get_addr(vdev, vdev->queue_sel)
>              >> proxy->guest_page_shift;
> +    case VIRTIO_MMIO_QUEUE_READY:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: read from modern register in legacy mode\n",
> +                          __func__);
> +            return 0;
> +        }
> +        return proxy->vqs[vdev->queue_sel].enabled;
>      case VIRTIO_MMIO_INTERRUPT_STATUS:
>          return atomic_read(&vdev->isr);
>      case VIRTIO_MMIO_STATUS:
>          return vdev->status;
> +    case VIRTIO_MMIO_CONFIG_GENERATION:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: read from modern register in legacy mode\n",
> +                          __func__);
> +            return 0;
> +        }
> +        return vdev->generation;
>      case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
>      case VIRTIO_MMIO_DRIVER_FEATURES:
>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
> @@ -177,6 +220,12 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>      case VIRTIO_MMIO_QUEUE_ALIGN:
>      case VIRTIO_MMIO_QUEUE_NOTIFY:
>      case VIRTIO_MMIO_INTERRUPT_ACK:
> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "%s: read of write-only register\n",
>                        __func__);
> @@ -232,14 +281,26 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>          proxy->host_features_sel = value;
>          break;
>      case VIRTIO_MMIO_DRIVER_FEATURES:
> -        if (!proxy->guest_features_sel) {
> +        if (proxy->modern) {
> +            proxy->guest_features[proxy->guest_features_sel] = value;
> +        } else if (!proxy->guest_features_sel) {
>              virtio_set_features(vdev, value);
>          }
>          break;
>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
> -        proxy->guest_features_sel = value;
> +        if (value) {
> +            proxy->guest_features_sel = 1;
> +        } else {
> +            proxy->guest_features_sel = 0;
> +        }
>          break;
>      case VIRTIO_MMIO_GUEST_PAGE_SIZE:
> +        if (proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
>          proxy->guest_page_shift = ctz32(value);
>          if (proxy->guest_page_shift > 31) {
>              proxy->guest_page_shift = 0;
> @@ -253,15 +314,29 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>          break;
>      case VIRTIO_MMIO_QUEUE_NUM:
>          trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
> -        virtio_queue_set_num(vdev, vdev->queue_sel, value);
> -        /* Note: only call this function for legacy devices */
> -        virtio_queue_update_rings(vdev, vdev->queue_sel);
> +        if (proxy->modern) {
> +            proxy->vqs[vdev->queue_sel].num = value;
> +        } else {
> +            virtio_queue_set_num(vdev, vdev->queue_sel, value);
> +            virtio_queue_update_rings(vdev, vdev->queue_sel);
> +        }
>          break;
>      case VIRTIO_MMIO_QUEUE_ALIGN:
> -        /* Note: this is only valid for legacy devices */
> +        if (proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
>          virtio_queue_set_align(vdev, vdev->queue_sel, value);
>          break;
>      case VIRTIO_MMIO_QUEUE_PFN:
> +        if (proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
>          if (value == 0) {
>              virtio_reset(vdev);
>          } else {
> @@ -269,6 +344,24 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>                                    value << proxy->guest_page_shift);
>          }
>          break;
> +    case VIRTIO_MMIO_QUEUE_READY:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to modern register in legacy mode\n",
> +                          __func__);
> +            return;
> +        }
> +        virtio_queue_set_num(vdev, vdev->queue_sel,
> +                             proxy->vqs[vdev->queue_sel].num);
> +        virtio_queue_set_rings(vdev, vdev->queue_sel,
> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
> +                       proxy->vqs[vdev->queue_sel].desc[0],
> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
> +                       proxy->vqs[vdev->queue_sel].avail[0],
> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
> +                       proxy->vqs[vdev->queue_sel].used[0]);
> +        proxy->vqs[vdev->queue_sel].enabled = 1;
> +        break;

This one seems out of spec.
In this respect virtio mmio is more advanced that virtio pci:
it allows setting the ready status to 0.



>      case VIRTIO_MMIO_QUEUE_NOTIFY:
>          if (value < VIRTIO_QUEUE_MAX) {
>              virtio_queue_notify(vdev, value);
> @@ -283,6 +376,12 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>              virtio_mmio_stop_ioeventfd(proxy);
>          }
>  
> +        if (proxy->modern && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
> +            virtio_set_features(vdev,
> +                                ((uint64_t)proxy->guest_features[1]) << 32 |
> +                                proxy->guest_features[0]);
> +        }
> +
>          virtio_set_status(vdev, value & 0xff);
>  
>          if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
> @@ -293,6 +392,60 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>              virtio_reset(vdev);
>          }
>          break;
> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].desc[0] = value;
> +        break;
> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].desc[1] = value;
> +        break;
> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].avail[0] = value;
> +        break;
> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].avail[1] = value;
> +        break;
> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].used[0] = value;
> +        break;
> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
> +        if (!proxy->modern) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: write to legacy register in modern mode\n",
> +                          __func__);
> +            return;
> +        }
> +        proxy->vqs[vdev->queue_sel].used[1] = value;
> +        break;
>      case VIRTIO_MMIO_MAGIC_VALUE:
>      case VIRTIO_MMIO_VERSION:
>      case VIRTIO_MMIO_DEVICE_ID:
> @@ -300,6 +453,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>      case VIRTIO_MMIO_DEVICE_FEATURES:
>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
>      case VIRTIO_MMIO_INTERRUPT_STATUS:
> +    case VIRTIO_MMIO_CONFIG_GENERATION:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "%s: write to readonly register\n",
>                        __func__);
> @@ -349,15 +503,90 @@ static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
>      qemu_put_be32(f, proxy->guest_page_shift);
>  }
>  
> +static const VMStateDescription vmstate_virtio_mmio_modern_queue_state = {
> +    .name = "virtio_mmio/modern_queue_state",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT16(num, VirtIOMMIOQueue),
> +        VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
> +        VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
> +        VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
> +        VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_virtio_mmio_modern_state_sub = {
> +    .name = "virtio_mmio/modern_state",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
> +        VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
> +                             vmstate_virtio_mmio_modern_queue_state,
> +                             VirtIOMMIOQueue),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_virtio_mmio = {
> +    .name = "virtio_mmio",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_END_OF_LIST()
> +    },
> +    .subsections = (const VMStateDescription*[]) {
> +        &vmstate_virtio_mmio_modern_state_sub,
> +        NULL
> +    }
> +};
> +
> +static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
> +{
> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> +
> +    vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
> +}
> +
> +static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
> +{
> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> +
> +    return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> +}
> +
> +static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> +{
> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> +
> +    return proxy->modern;
> +}
> +
>  static void virtio_mmio_reset(DeviceState *d)
>  {
>      VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
> +    int i;
>  
>      virtio_mmio_stop_ioeventfd(proxy);
>      virtio_bus_reset(&proxy->bus);
>      proxy->host_features_sel = 0;
>      proxy->guest_features_sel = 0;
>      proxy->guest_page_shift = 0;
> +
> +    if (proxy->modern) {
> +        proxy->guest_features[0] = proxy->guest_features[1] = 0;
> +
> +        for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
> +            proxy->vqs[i].enabled = 0;
> +            proxy->vqs[i].num = 0;
> +            proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
> +            proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
> +            proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
> +        }
> +    }
>  }
>  
>  static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
> @@ -420,11 +649,22 @@ assign_error:
>      return r;
>  }
>  
> +static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
> +{
> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
> +    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
> +
> +    if (proxy->modern) {
> +        virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
> +    }
> +}
> +
>  /* virtio-mmio device */
>  
>  static Property virtio_mmio_properties[] = {
>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
>                       format_transport_address, true),
> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>  
> @@ -508,9 +748,13 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
>      k->notify = virtio_mmio_update_irq;
>      k->save_config = virtio_mmio_save_config;
>      k->load_config = virtio_mmio_load_config;
> +    k->save_extra_state = virtio_mmio_save_extra_state;
> +    k->load_extra_state = virtio_mmio_load_extra_state;
> +    k->has_extra_state = virtio_mmio_has_extra_state;
>      k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
>      k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
>      k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
> +    k->pre_plugged = virtio_mmio_pre_plugged;
>      k->has_variable_vring_alignment = true;
>      bus_class->max_dev = 1;
>      bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
> -- 
> 2.21.0


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
                   ` (2 preceding siblings ...)
  2019-07-30  8:34 ` Michael S. Tsirkin
@ 2019-07-30 10:25 ` Andrea Bolognani
  2019-07-30 11:35   ` Cornelia Huck
  2019-07-31 11:02   ` Sergio Lopez
  2019-07-30 16:06 ` Laszlo Ersek
  4 siblings, 2 replies; 27+ messages in thread
From: Andrea Bolognani @ 2019-07-30 10:25 UTC (permalink / raw)
  To: Sergio Lopez, mst; +Cc: peter.maydell, qemu-devel

On Mon, 2019-07-29 at 14:57 +0200, Sergio Lopez wrote:
[...]
>  /* virtio-mmio device */
>  
>  static Property virtio_mmio_properties[] = {
>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
>                       format_transport_address, true),
> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
>      DEFINE_PROP_END_OF_LIST(),
>  };

Not a QEMU developer so forgive me if I say something silly, but IIUC
you'd be able to opt into the new feature by using eg.

  -device virtio-net-device,modern=on

However, virtio-pci devices already have a mechanism to control the
VirtIO protocol version, where you use

  -device virtio-net-pci,disable-modern=no,disable-legacy=yes

to get a VirtIO 1.x-only device and

  -device virtio-net-pci,disable-modern=no,disable-legacy=no

for a transitional device.

Can you please make sure virtio-mmio uses the existing interface
instead of introducing a new one?

-- 
Andrea Bolognani / Red Hat / Virtualization



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 10:25 ` Andrea Bolognani
@ 2019-07-30 11:35   ` Cornelia Huck
  2019-07-30 12:17     ` Andrea Bolognani
  2019-07-31 11:02   ` Sergio Lopez
  1 sibling, 1 reply; 27+ messages in thread
From: Cornelia Huck @ 2019-07-30 11:35 UTC (permalink / raw)
  To: Andrea Bolognani; +Cc: peter.maydell, qemu-devel, Sergio Lopez, mst

On Tue, 30 Jul 2019 12:25:30 +0200
Andrea Bolognani <abologna@redhat.com> wrote:

> On Mon, 2019-07-29 at 14:57 +0200, Sergio Lopez wrote:
> [...]
> >  /* virtio-mmio device */
> >  
> >  static Property virtio_mmio_properties[] = {
> >      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
> >                       format_transport_address, true),
> > +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };  
> 
> Not a QEMU developer so forgive me if I say something silly, but IIUC
> you'd be able to opt into the new feature by using eg.
> 
>   -device virtio-net-device,modern=on
> 
> However, virtio-pci devices already have a mechanism to control the
> VirtIO protocol version, where you use
> 
>   -device virtio-net-pci,disable-modern=no,disable-legacy=yes
> 
> to get a VirtIO 1.x-only device and
> 
>   -device virtio-net-pci,disable-modern=no,disable-legacy=no
> 
> for a transitional device.
> 
> Can you please make sure virtio-mmio uses the existing interface
> instead of introducing a new one?
> 

FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
starter, what is 'modern'? Will we have 'ultra-modern' in the future?
It is also quite backwards with the 'disable' terminology.

We also have a different mechanism for virtio-ccw ('max_revision',
which covers a bit more than virtio-1; it doesn't have a 'min_revision',
as negotiating the revision down is fine), so I don't see why
virtio-mmio should replicate the virtio-pci mechanism.

Also, IIUC, virtio-mmio does not have transitional devices, but either
version 1 (legacy) or version 2 (virtio-1). It probably makes more
sense to expose the device version instead; either as an exact version
(especially if it isn't supposed to go up without incompatible
changes), or with some min/max concept (where version 1 would stand a
bit alone, so that would probably be a bit awkward.)


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 11:35   ` Cornelia Huck
@ 2019-07-30 12:17     ` Andrea Bolognani
  2019-07-30 13:14       ` Cornelia Huck
  0 siblings, 1 reply; 27+ messages in thread
From: Andrea Bolognani @ 2019-07-30 12:17 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: peter.maydell, qemu-devel, Sergio Lopez, mst

On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:
> On Tue, 30 Jul 2019 12:25:30 +0200
> Andrea Bolognani <abologna@redhat.com> wrote:
> > Can you please make sure virtio-mmio uses the existing interface
> > instead of introducing a new one?
> 
> FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> starter, what is 'modern'? Will we have 'ultra-modern' in the future?

AIUI the modern/legacy terminology is part of the VirtIO spec, so
while I agree that it's not necessarily the least prone to ambiguity
at least it's well defined.

> It is also quite backwards with the 'disable' terminology.

That's also true. I never claimed the way virtio-pci does it is
perfect!

> We also have a different mechanism for virtio-ccw ('max_revision',
> which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> as negotiating the revision down is fine), so I don't see why
> virtio-mmio should replicate the virtio-pci mechanism.
> 
> Also, IIUC, virtio-mmio does not have transitional devices, but either
> version 1 (legacy) or version 2 (virtio-1). It probably makes more
> sense to expose the device version instead; either as an exact version
> (especially if it isn't supposed to go up without incompatible
> changes), or with some min/max concept (where version 1 would stand a
> bit alone, so that would probably be a bit awkward.)

I think that if reinventing the wheel is generally agreed not to be
a good idea, then it stands to reason that reinventing it twice can
only be described as absolute madness :)

We should have a single way to control the VirtIO protocol version
that works for all VirtIO devices, regardless of transport. We might
even want to have virtio-*-{device,ccw}-non-transitional to mirror
the existing virtio-*-pci-non-transitional.

FWIW, libvirt already implements support for (non)-transitional
virtio-pci devices using either the dedicated devices or the base
virtio-pci plus the disable-{modern,legacy} attributes.

-- 
Andrea Bolognani / Red Hat / Virtualization



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 12:17     ` Andrea Bolognani
@ 2019-07-30 13:14       ` Cornelia Huck
  2019-07-30 20:02         ` Michael S. Tsirkin
  2019-07-30 20:18         ` Michael S. Tsirkin
  0 siblings, 2 replies; 27+ messages in thread
From: Cornelia Huck @ 2019-07-30 13:14 UTC (permalink / raw)
  To: Andrea Bolognani; +Cc: peter.maydell, qemu-devel, Sergio Lopez, mst

On Tue, 30 Jul 2019 14:17:48 +0200
Andrea Bolognani <abologna@redhat.com> wrote:

> On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:
> > On Tue, 30 Jul 2019 12:25:30 +0200
> > Andrea Bolognani <abologna@redhat.com> wrote:  
> > > Can you please make sure virtio-mmio uses the existing interface
> > > instead of introducing a new one?  
> > 
> > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> > starter, what is 'modern'? Will we have 'ultra-modern' in the future?  
> 
> AIUI the modern/legacy terminology is part of the VirtIO spec, so
> while I agree that it's not necessarily the least prone to ambiguity
> at least it's well defined.

Legacy is, modern isn't :) Devices/drivers are conforming to the
standard, I don't think there's a special term for that.

> 
> > It is also quite backwards with the 'disable' terminology.  
> 
> That's also true. I never claimed the way virtio-pci does it is
> perfect!
> 
> > We also have a different mechanism for virtio-ccw ('max_revision',
> > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> > as negotiating the revision down is fine), so I don't see why
> > virtio-mmio should replicate the virtio-pci mechanism.
> > 
> > Also, IIUC, virtio-mmio does not have transitional devices, but either
> > version 1 (legacy) or version 2 (virtio-1). It probably makes more
> > sense to expose the device version instead; either as an exact version
> > (especially if it isn't supposed to go up without incompatible
> > changes), or with some min/max concept (where version 1 would stand a
> > bit alone, so that would probably be a bit awkward.)  
> 
> I think that if reinventing the wheel is generally agreed not to be
> a good idea, then it stands to reason that reinventing it twice can
> only be described as absolute madness :)
> 
> We should have a single way to control the VirtIO protocol version
> that works for all VirtIO devices, regardless of transport. We might
> even want to have virtio-*-{device,ccw}-non-transitional to mirror
> the existing virtio-*-pci-non-transitional.
> 
> FWIW, libvirt already implements support for (non)-transitional
> virtio-pci devices using either the dedicated devices or the base
> virtio-pci plus the disable-{modern,legacy} attributes.

One problem (besides my dislike of the existing virtio-pci
interfaces :) is that pci, ccw, and mmio all have slightly different
semantics.

- pci: If we need to keep legacy support around, we cannot enable some
  features (IIRC, pci-e, maybe others as well.) That means transitional
  devices are in some ways inferior to virtio-1 only devices, so it
  makes a lot of sense to be able to configure devices without legacy
  support. The differences between legacy and virtio-1 are quite large.
- ccw: Has revisions negotiated between device and driver; virtio-1
  requires revision 1 or higher. (Legacy drivers that don't know the
  concept of revisions automatically get revision 0.) Differences
  between legacy and virtio-1 are mostly virtqueue endianness and some
  control structures.
- mmio: Has device versions offered by the device, the driver can take
  it or leave it. No transitional devices. Differences don't look as
  large as the ones for pci, either.

So, if we were to duplicate the same scheme as for pci for ccw and mmio
as well, we'd get

- ccw: devices that support revision 0 only (disable-modern), that act
  as today, or that support at least revision 1 (disable-legacy). We
  still need to keep max_revision around for backwards compatibility.
  Legacy only makes sense for compat machines (although this is
  equivalent to max_revision 0); I don't see a reason why you would
  want virtio-1 only devices, unless you'd want to rip out legacy
  support in QEMU completely.
- mmio: devices that support version 1 (disable-modern), or version 2
  (disable-legacy). You cannot have both at the same time. Whether this
  makes sense depends on whether there will be a version 3 in the
  future.

So, this might make some sense for mmio; for ccw, I don't see any
advantages other than confusing people further...


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
                   ` (3 preceding siblings ...)
  2019-07-30 10:25 ` Andrea Bolognani
@ 2019-07-30 16:06 ` Laszlo Ersek
  2019-07-31 23:58   ` Paolo Bonzini
  2019-08-01  8:37   ` Sergio Lopez
  4 siblings, 2 replies; 27+ messages in thread
From: Laszlo Ersek @ 2019-07-30 16:06 UTC (permalink / raw)
  To: Sergio Lopez, mst; +Cc: peter.maydell, qemu-devel

On 07/29/19 14:57, Sergio Lopez wrote:
> Implement the modern (v2) personality, according to the VirtIO 1.0
> specification.
> 
> Support for v2 among guests is not as widespread as it'd be
> desirable. While the Linux driver has had it for a while, support is
> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.

That's right; not only are there no plans to implement virtio-mmio/1.0
for OVMF (to my knowledge), I'd even argue against such efforts.

OVMF is a heavy-weight guest firmware, which I see entirely out of scope
for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
unwelcome complication, from the OVMF maintainership perspective.

(This should not be construed as an argument against "micro VMs" -- I
always say, identify your use case, then pick the right components for
it. I never try to convince people to use OVMF indiscriminately.)

> For this reason, the v2 personality is disabled, keeping the legacy
> behavior as default. Machine types willing to use v2, can enable it
> using MachineClass's compat_props.

This approach makes me happy (with the understanding that edk2 guest
firmware is not going to target the new machine type(s) in question).

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 13:14       ` Cornelia Huck
@ 2019-07-30 20:02         ` Michael S. Tsirkin
  2019-07-30 20:18         ` Michael S. Tsirkin
  1 sibling, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-07-30 20:02 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: peter.maydell, Andrea Bolognani, Sergio Lopez, qemu-devel

On Tue, Jul 30, 2019 at 03:14:00PM +0200, Cornelia Huck wrote:
> On Tue, 30 Jul 2019 14:17:48 +0200
> Andrea Bolognani <abologna@redhat.com> wrote:
> 
> > On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:
> > > On Tue, 30 Jul 2019 12:25:30 +0200
> > > Andrea Bolognani <abologna@redhat.com> wrote:  
> > > > Can you please make sure virtio-mmio uses the existing interface
> > > > instead of introducing a new one?  
> > > 
> > > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> > > starter, what is 'modern'? Will we have 'ultra-modern' in the future?  
> > 
> > AIUI the modern/legacy terminology is part of the VirtIO spec, so
> > while I agree that it's not necessarily the least prone to ambiguity
> > at least it's well defined.
> 
> Legacy is, modern isn't :) Devices/drivers are conforming to the
> standard, I don't think there's a special term for that.

Right, the best we have is "non-transitional":

	Devices or drivers with no legacy compatibility are referred to as non-transitional devices and drivers, re-
	spectively.

> > 
> > > It is also quite backwards with the 'disable' terminology.  
> > 
> > That's also true. I never claimed the way virtio-pci does it is
> > perfect!
> > 
> > > We also have a different mechanism for virtio-ccw ('max_revision',
> > > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> > > as negotiating the revision down is fine), so I don't see why
> > > virtio-mmio should replicate the virtio-pci mechanism.
> > > 
> > > Also, IIUC, virtio-mmio does not have transitional devices, but either
> > > version 1 (legacy) or version 2 (virtio-1). It probably makes more
> > > sense to expose the device version instead; either as an exact version
> > > (especially if it isn't supposed to go up without incompatible
> > > changes), or with some min/max concept (where version 1 would stand a
> > > bit alone, so that would probably be a bit awkward.)  
> > 
> > I think that if reinventing the wheel is generally agreed not to be
> > a good idea, then it stands to reason that reinventing it twice can
> > only be described as absolute madness :)
> > 
> > We should have a single way to control the VirtIO protocol version
> > that works for all VirtIO devices, regardless of transport. We might
> > even want to have virtio-*-{device,ccw}-non-transitional to mirror
> > the existing virtio-*-pci-non-transitional.
> > 
> > FWIW, libvirt already implements support for (non)-transitional
> > virtio-pci devices using either the dedicated devices or the base
> > virtio-pci plus the disable-{modern,legacy} attributes.
> 
> One problem (besides my dislike of the existing virtio-pci
> interfaces :) is that pci, ccw, and mmio all have slightly different
> semantics.
> 
> - pci: If we need to keep legacy support around, we cannot enable some
>   features (IIRC, pci-e, maybe others as well.)
>	 That means transitional
>   devices are in some ways inferior to virtio-1 only devices, so it
>   makes a lot of sense to be able to configure devices without legacy
>   support.

That's not coming from the spec though. You can put a transitional
device on pci-e, in some configurations legacy guests will fail to boot
but modern ones will always work.

QEMU made modern a requirement for pcie to simplify things, such
that you can always be sure transitional supports a legacy guest.
We can relax that if we like.

> The differences between legacy and virtio-1 are quite large.
>
> - ccw: Has revisions negotiated between device and driver; virtio-1
>   requires revision 1 or higher. (Legacy drivers that don't know the
>   concept of revisions automatically get revision 0.) Differences
>   between legacy and virtio-1 are mostly virtqueue endianness and some
>   control structures.
> - mmio: Has device versions offered by the device, the driver can take
>   it or leave it. No transitional devices. Differences don't look as
>   large as the ones for pci, either.
> 
> So, if we were to duplicate the same scheme as for pci for ccw and mmio
> as well, we'd get
> 
> - ccw: devices that support revision 0 only (disable-modern), that act
>   as today, or that support at least revision 1 (disable-legacy). We
>   still need to keep max_revision around for backwards compatibility.
>   Legacy only makes sense for compat machines (although this is
>   equivalent to max_revision 0); I don't see a reason why you would
>   want virtio-1 only devices, unless you'd want to rip out legacy
>   support in QEMU completely.
> - mmio: devices that support version 1 (disable-modern), or version 2
>   (disable-legacy). You cannot have both at the same time. Whether this
>   makes sense depends on whether there will be a version 3 in the
>   future.

Told you so ;) When the TC approved the decision not to
have transitional support I tried to complain but
enough people felt there will be more devices/drivers in the
future than in the past, so we should not worry too much.

Here we are, lots of time passed and now MMIO is held
back from even offering virtio 1 by default because
people want to run legacy guests and no one has the
energy to upgrade legacy drivers.

I don't think we'll repeat the mistake again though,
so I don't really expect another incompatible upgrade.

> So, this might make some sense for mmio; for ccw, I don't see any
> advantages other than confusing people further...


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 13:14       ` Cornelia Huck
  2019-07-30 20:02         ` Michael S. Tsirkin
@ 2019-07-30 20:18         ` Michael S. Tsirkin
  2019-07-31 11:04           ` Sergio Lopez
  2019-07-31 13:55           ` Cornelia Huck
  1 sibling, 2 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-07-30 20:18 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: peter.maydell, Andrea Bolognani, Sergio Lopez, qemu-devel

On Tue, Jul 30, 2019 at 03:14:00PM +0200, Cornelia Huck wrote:
> On Tue, 30 Jul 2019 14:17:48 +0200
> Andrea Bolognani <abologna@redhat.com> wrote:
> 
> > On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:
> > > On Tue, 30 Jul 2019 12:25:30 +0200
> > > Andrea Bolognani <abologna@redhat.com> wrote:  
> > > > Can you please make sure virtio-mmio uses the existing interface
> > > > instead of introducing a new one?  
> > > 
> > > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> > > starter, what is 'modern'? Will we have 'ultra-modern' in the future?  
> > 
> > AIUI the modern/legacy terminology is part of the VirtIO spec, so
> > while I agree that it's not necessarily the least prone to ambiguity
> > at least it's well defined.
> 
> Legacy is, modern isn't :) Devices/drivers are conforming to the
> standard, I don't think there's a special term for that.

Right, if we followed the spec, disable-modern would have been
force-legacy.

I'm fine with adding force-legacy for everyone and asking tools to
transition if there. Document it's same as disable-modern for pci.
Cornelia?


> > 
> > > It is also quite backwards with the 'disable' terminology.  
> > 
> > That's also true. I never claimed the way virtio-pci does it is
> > perfect!
> > 
> > > We also have a different mechanism for virtio-ccw ('max_revision',
> > > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> > > as negotiating the revision down is fine), so I don't see why
> > > virtio-mmio should replicate the virtio-pci mechanism.
> > > 
> > > Also, IIUC, virtio-mmio does not have transitional devices, but either
> > > version 1 (legacy) or version 2 (virtio-1). It probably makes more
> > > sense to expose the device version instead; either as an exact version
> > > (especially if it isn't supposed to go up without incompatible
> > > changes), or with some min/max concept (where version 1 would stand a
> > > bit alone, so that would probably be a bit awkward.)  
> > 
> > I think that if reinventing the wheel is generally agreed not to be
> > a good idea, then it stands to reason that reinventing it twice can
> > only be described as absolute madness :)
> > 
> > We should have a single way to control the VirtIO protocol version
> > that works for all VirtIO devices, regardless of transport. We might
> > even want to have virtio-*-{device,ccw}-non-transitional to mirror
> > the existing virtio-*-pci-non-transitional.
> > 
> > FWIW, libvirt already implements support for (non)-transitional
> > virtio-pci devices using either the dedicated devices or the base
> > virtio-pci plus the disable-{modern,legacy} attributes.
> 
> One problem (besides my dislike of the existing virtio-pci
> interfaces :) is that pci, ccw, and mmio all have slightly different
> semantics.
> 
> - pci: If we need to keep legacy support around, we cannot enable some
>   features (IIRC, pci-e, maybe others as well.) That means transitional
>   devices are in some ways inferior to virtio-1 only devices, so it
>   makes a lot of sense to be able to configure devices without legacy
>   support. The differences between legacy and virtio-1 are quite large.
> - ccw: Has revisions negotiated between device and driver; virtio-1
>   requires revision 1 or higher. (Legacy drivers that don't know the
>   concept of revisions automatically get revision 0.) Differences
>   between legacy and virtio-1 are mostly virtqueue endianness and some
>   control structures.
> - mmio: Has device versions offered by the device, the driver can take
>   it or leave it. No transitional devices. Differences don't look as
>   large as the ones for pci, either.
> 
> So, if we were to duplicate the same scheme as for pci for ccw and mmio
> as well, we'd get
> 
> - ccw: devices that support revision 0 only (disable-modern), that act
>   as today, or that support at least revision 1 (disable-legacy). We
>   still need to keep max_revision around for backwards compatibility.
>   Legacy only makes sense for compat machines (although this is
>   equivalent to max_revision 0); I don't see a reason why you would
>   want virtio-1 only devices, unless you'd want to rip out legacy
>   support in QEMU completely.

Reduce security attack surface slightly. Save some cycles
(down the road) on branches in the endian-ness handling.
Make sure your guests
are all up to date in preparation to the day when legacy will go away.

Not a huge win, for sure, but hey - it's something.

> - mmio: devices that support version 1 (disable-modern), or version 2
>   (disable-legacy). You cannot have both at the same time. Whether this
>   makes sense depends on whether there will be a version 3 in the
>   future.
> 
> So, this might make some sense for mmio; for ccw, I don't see any
> advantages other than confusing people further...


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 10:25 ` Andrea Bolognani
  2019-07-30 11:35   ` Cornelia Huck
@ 2019-07-31 11:02   ` Sergio Lopez
  2019-08-01 12:17     ` Michael S. Tsirkin
  1 sibling, 1 reply; 27+ messages in thread
From: Sergio Lopez @ 2019-07-31 11:02 UTC (permalink / raw)
  To: Andrea Bolognani; +Cc: peter.maydell, qemu-devel, mst

[-- Attachment #1: Type: text/plain, Size: 1437 bytes --]


Andrea Bolognani <abologna@redhat.com> writes:

> On Mon, 2019-07-29 at 14:57 +0200, Sergio Lopez wrote:
> [...]
>>  /* virtio-mmio device */
>>  
>>  static Property virtio_mmio_properties[] = {
>>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
>>                       format_transport_address, true),
>> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
>>      DEFINE_PROP_END_OF_LIST(),
>>  };
>
> Not a QEMU developer so forgive me if I say something silly, but IIUC
> you'd be able to opt into the new feature by using eg.
>
>   -device virtio-net-device,modern=on
>
> However, virtio-pci devices already have a mechanism to control the
> VirtIO protocol version, where you use
>
>   -device virtio-net-pci,disable-modern=no,disable-legacy=yes
>
> to get a VirtIO 1.x-only device and
>
>   -device virtio-net-pci,disable-modern=no,disable-legacy=no
>
> for a transitional device.
>
> Can you please make sure virtio-mmio uses the existing interface
> instead of introducing a new one?

The problem here is that virtio-pci devices register an specific type
for each kind of supported device (virtio-net-pci, virtio-blk-pci...),
while virtio-mmio doesn't. This saves a lot of boilerplate, but also
implies that bus properties can't be passed through the attached device
(virtio-blk-device can't carry properties for it's virtio-mmio parent
bus).

Sergio.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 20:18         ` Michael S. Tsirkin
@ 2019-07-31 11:04           ` Sergio Lopez
  2019-07-31 13:55           ` Cornelia Huck
  1 sibling, 0 replies; 27+ messages in thread
From: Sergio Lopez @ 2019-07-31 11:04 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: peter.maydell, Cornelia Huck, Andrea Bolognani, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5232 bytes --]


Michael S. Tsirkin <mst@redhat.com> writes:

> On Tue, Jul 30, 2019 at 03:14:00PM +0200, Cornelia Huck wrote:
>> On Tue, 30 Jul 2019 14:17:48 +0200
>> Andrea Bolognani <abologna@redhat.com> wrote:
>> 
>> > On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:
>> > > On Tue, 30 Jul 2019 12:25:30 +0200
>> > > Andrea Bolognani <abologna@redhat.com> wrote:  
>> > > > Can you please make sure virtio-mmio uses the existing interface
>> > > > instead of introducing a new one?  
>> > > 
>> > > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
>> > > starter, what is 'modern'? Will we have 'ultra-modern' in the future?  
>> > 
>> > AIUI the modern/legacy terminology is part of the VirtIO spec, so
>> > while I agree that it's not necessarily the least prone to ambiguity
>> > at least it's well defined.
>> 
>> Legacy is, modern isn't :) Devices/drivers are conforming to the
>> standard, I don't think there's a special term for that.
>
> Right, if we followed the spec, disable-modern would have been
> force-legacy.
>
> I'm fine with adding force-legacy for everyone and asking tools to
> transition if there. Document it's same as disable-modern for pci.
> Cornelia?

FWIW, for this patch, I'm perfectly fine with changing the "modern"
property to "force-legacy", with "true" as the default value.

>> > 
>> > > It is also quite backwards with the 'disable' terminology.  
>> > 
>> > That's also true. I never claimed the way virtio-pci does it is
>> > perfect!
>> > 
>> > > We also have a different mechanism for virtio-ccw ('max_revision',
>> > > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
>> > > as negotiating the revision down is fine), so I don't see why
>> > > virtio-mmio should replicate the virtio-pci mechanism.
>> > > 
>> > > Also, IIUC, virtio-mmio does not have transitional devices, but either
>> > > version 1 (legacy) or version 2 (virtio-1). It probably makes more
>> > > sense to expose the device version instead; either as an exact version
>> > > (especially if it isn't supposed to go up without incompatible
>> > > changes), or with some min/max concept (where version 1 would stand a
>> > > bit alone, so that would probably be a bit awkward.)  
>> > 
>> > I think that if reinventing the wheel is generally agreed not to be
>> > a good idea, then it stands to reason that reinventing it twice can
>> > only be described as absolute madness :)
>> > 
>> > We should have a single way to control the VirtIO protocol version
>> > that works for all VirtIO devices, regardless of transport. We might
>> > even want to have virtio-*-{device,ccw}-non-transitional to mirror
>> > the existing virtio-*-pci-non-transitional.
>> > 
>> > FWIW, libvirt already implements support for (non)-transitional
>> > virtio-pci devices using either the dedicated devices or the base
>> > virtio-pci plus the disable-{modern,legacy} attributes.
>> 
>> One problem (besides my dislike of the existing virtio-pci
>> interfaces :) is that pci, ccw, and mmio all have slightly different
>> semantics.
>> 
>> - pci: If we need to keep legacy support around, we cannot enable some
>>   features (IIRC, pci-e, maybe others as well.) That means transitional
>>   devices are in some ways inferior to virtio-1 only devices, so it
>>   makes a lot of sense to be able to configure devices without legacy
>>   support. The differences between legacy and virtio-1 are quite large.
>> - ccw: Has revisions negotiated between device and driver; virtio-1
>>   requires revision 1 or higher. (Legacy drivers that don't know the
>>   concept of revisions automatically get revision 0.) Differences
>>   between legacy and virtio-1 are mostly virtqueue endianness and some
>>   control structures.
>> - mmio: Has device versions offered by the device, the driver can take
>>   it or leave it. No transitional devices. Differences don't look as
>>   large as the ones for pci, either.
>> 
>> So, if we were to duplicate the same scheme as for pci for ccw and mmio
>> as well, we'd get
>> 
>> - ccw: devices that support revision 0 only (disable-modern), that act
>>   as today, or that support at least revision 1 (disable-legacy). We
>>   still need to keep max_revision around for backwards compatibility.
>>   Legacy only makes sense for compat machines (although this is
>>   equivalent to max_revision 0); I don't see a reason why you would
>>   want virtio-1 only devices, unless you'd want to rip out legacy
>>   support in QEMU completely.
>
> Reduce security attack surface slightly. Save some cycles
> (down the road) on branches in the endian-ness handling.
> Make sure your guests
> are all up to date in preparation to the day when legacy will go away.
>
> Not a huge win, for sure, but hey - it's something.
>
>> - mmio: devices that support version 1 (disable-modern), or version 2
>>   (disable-legacy). You cannot have both at the same time. Whether this
>>   makes sense depends on whether there will be a version 3 in the
>>   future.
>> 
>> So, this might make some sense for mmio; for ccw, I don't see any
>> advantages other than confusing people further...


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30  8:34 ` Michael S. Tsirkin
@ 2019-07-31 12:22   ` Sergio Lopez
  2019-07-31 19:34     ` Michael S. Tsirkin
  2019-07-31 21:22     ` Eduardo Habkost
  0 siblings, 2 replies; 27+ messages in thread
From: Sergio Lopez @ 2019-07-31 12:22 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: peter.maydell, qemu-devel, ehabkost

[-- Attachment #1: Type: text/plain, Size: 20826 bytes --]


Michael S. Tsirkin <mst@redhat.com> writes:

> On Mon, Jul 29, 2019 at 02:57:55PM +0200, Sergio Lopez wrote:
>> Implement the modern (v2) personality, according to the VirtIO 1.0
>> specification.
>> 
>> Support for v2 among guests is not as widespread as it'd be
>> desirable. While the Linux driver has had it for a while, support is
>> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
>
> The fact that there was no open source hypervisor implementation has
> probably contributed to this :)
>
>> For this reason, the v2 personality is disabled, keeping the legacy
>> behavior as default.
>
> I agree it's a good default for existing machine types.
>
>> Machine types willing to use v2, can enable it
>> using MachineClass's compat_props.
>
> Hmm. Are compat_props really the recommended mechanism to
> tweak defaults? I was under the impression it's
> only for compatibility with old machine types.
> Eduardo, any opinion on this?

Stefan suggested using something like "-global virtio-mmio.modern=true"
which does the trick for the command line, but I'd also like a way to
set it to true by default on microvm. We can discuss the best way to
achieve that (if using compat_props isn't acceptable) on the next
microvm patch series.

>> 
>> Signed-off-by: Sergio Lopez <slp@redhat.com>
>
> Endian-ness seems to be wrong:
>
> static const MemoryRegionOps virtio_mem_ops = {
>     .read = virtio_mmio_read,
>     .write = virtio_mmio_write,
>     .endianness = DEVICE_NATIVE_ENDIAN,
> };
>
> you will see this if you test a big endian guest.

Interesting, a Linux kernel compiled for aarch64_be works just
fine. Looking further, seems like, on ARM, Linux assumes all memory I/O
operations are little-endian and swaps the data if necessary:

arch/arm64/include/asm/io.h:
/*
 * Relaxed I/O memory access primitives. These follow the Device memory
 * ordering rules but do not guarantee any ordering relative to Normal memory
 * accesses.
 */
#define readb_relaxed(c)	({ u8  __r = __raw_readb(c); __r; })
#define readw_relaxed(c)	({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; })
#define readl_relaxed(c)	({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; })
#define readq_relaxed(c)	({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; })

#define writeb_relaxed(v,c)	((void)__raw_writeb((v),(c)))
#define writew_relaxed(v,c)	((void)__raw_writew((__force u16)cpu_to_le16(v),(c)))
#define writel_relaxed(v,c)	((void)__raw_writel((__force u32)cpu_to_le32(v),(c)))
#define writeq_relaxed(v,c)	((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))

The Apendix X from virtio-0.9.5 specs states that "The endianness of the
registers follows the native endianness of the Guest". Luckily for us,
this isn't the case, as with DEVICE_NATIVE_ENDIAN
memory.c:adjust_endianness doesn't attempt any kind of transformation.

In any, I guess we should follow the spec, and keep DEVICE_NATIVE_ENDIAN
for the legacy mode while using DEVICE_LITTLE_ENDIAN for
virtio-mmio-2/virtio-1.

>> ---
>>  hw/virtio/virtio-mmio.c | 264 ++++++++++++++++++++++++++++++++++++++--
>>  1 file changed, 254 insertions(+), 10 deletions(-)
>> 
>> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
>> index 97b7f35496..1da841336f 100644
>> --- a/hw/virtio/virtio-mmio.c
>> +++ b/hw/virtio/virtio-mmio.c
>> @@ -47,14 +47,24 @@
>>          OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
>>  
>>  #define VIRT_MAGIC 0x74726976 /* 'virt' */
>> -#define VIRT_VERSION 1
>> +#define VIRT_VERSION_LEGACY 1
>> +#define VIRT_VERSION_MODERN 2
>>  #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
>>  
>> +typedef struct VirtIOMMIOQueue {
>> +    uint16_t num;
>> +    bool enabled;
>> +    uint32_t desc[2];
>> +    uint32_t avail[2];
>> +    uint32_t used[2];
>> +} VirtIOMMIOQueue;
>> +
>>  typedef struct {
>>      /* Generic */
>>      SysBusDevice parent_obj;
>>      MemoryRegion iomem;
>>      qemu_irq irq;
>> +    bool modern;
>>      /* Guest accessible state needing migration and reset */
>>      uint32_t host_features_sel;
>>      uint32_t guest_features_sel;
>> @@ -62,6 +72,9 @@ typedef struct {
>>      /* virtio-bus */
>>      VirtioBusState bus;
>>      bool format_transport_address;
>> +    /* Fields only used for v2 (modern) devices */
>> +    uint32_t guest_features[2];
>> +    VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
>>  } VirtIOMMIOProxy;
>>  
>>  static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
>> @@ -115,7 +128,11 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>>          case VIRTIO_MMIO_MAGIC_VALUE:
>>              return VIRT_MAGIC;
>>          case VIRTIO_MMIO_VERSION:
>> -            return VIRT_VERSION;
>> +            if (proxy->modern) {
>> +                return VIRT_VERSION_MODERN;
>> +            } else {
>> +                return VIRT_VERSION_LEGACY;
>> +            }
>>          case VIRTIO_MMIO_VENDOR_ID:
>>              return VIRT_VENDOR;
>>          default:
>> @@ -146,14 +163,18 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>>      case VIRTIO_MMIO_MAGIC_VALUE:
>>          return VIRT_MAGIC;
>>      case VIRTIO_MMIO_VERSION:
>> -        return VIRT_VERSION;
>> +        if (proxy->modern) {
>> +            return VIRT_VERSION_MODERN;
>> +        } else {
>> +            return VIRT_VERSION_LEGACY;
>> +        }
>>      case VIRTIO_MMIO_DEVICE_ID:
>>          return vdev->device_id;
>>      case VIRTIO_MMIO_VENDOR_ID:
>>          return VIRT_VENDOR;
>>      case VIRTIO_MMIO_DEVICE_FEATURES:
>>          if (proxy->host_features_sel) {
>> -            return 0;
>> +            return vdev->host_features >> 32;
>
> I'd do vdev->host_features >> (32 * proxy->host_features_sel);

OK, looks nicer. I'll sanitize the value host_features_sel on
VIRTIO_MMIO_DEVICE_FEATURES too, as I'm already doing with
guest_features_sel.

>>          }
>>          return vdev->host_features;
>>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
>> @@ -162,12 +183,34 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>>          }
>>          return VIRTQUEUE_MAX_SIZE;
>>      case VIRTIO_MMIO_QUEUE_PFN:
>> +        if (proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: read from legacy register in modern mode\n",
>> +                          __func__);
>> +            return 0;
>> +        }
>>          return virtio_queue_get_addr(vdev, vdev->queue_sel)
>>              >> proxy->guest_page_shift;
>> +    case VIRTIO_MMIO_QUEUE_READY:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: read from modern register in legacy mode\n",
>> +                          __func__);
>> +            return 0;
>> +        }
>> +        return proxy->vqs[vdev->queue_sel].enabled;
>>      case VIRTIO_MMIO_INTERRUPT_STATUS:
>>          return atomic_read(&vdev->isr);
>>      case VIRTIO_MMIO_STATUS:
>>          return vdev->status;
>> +    case VIRTIO_MMIO_CONFIG_GENERATION:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: read from modern register in legacy mode\n",
>> +                          __func__);
>> +            return 0;
>> +        }
>> +        return vdev->generation;
>>      case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
>>      case VIRTIO_MMIO_DRIVER_FEATURES:
>>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
>> @@ -177,6 +220,12 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>>      case VIRTIO_MMIO_QUEUE_ALIGN:
>>      case VIRTIO_MMIO_QUEUE_NOTIFY:
>>      case VIRTIO_MMIO_INTERRUPT_ACK:
>> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
>> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
>> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
>> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
>> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
>> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
>>          qemu_log_mask(LOG_GUEST_ERROR,
>>                        "%s: read of write-only register\n",
>>                        __func__);
>> @@ -232,14 +281,26 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>          proxy->host_features_sel = value;
>>          break;
>>      case VIRTIO_MMIO_DRIVER_FEATURES:
>> -        if (!proxy->guest_features_sel) {
>> +        if (proxy->modern) {
>> +            proxy->guest_features[proxy->guest_features_sel] = value;
>> +        } else if (!proxy->guest_features_sel) {
>>              virtio_set_features(vdev, value);
>>          }
>>          break;
>>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
>> -        proxy->guest_features_sel = value;
>> +        if (value) {
>> +            proxy->guest_features_sel = 1;
>> +        } else {
>> +            proxy->guest_features_sel = 0;
>> +        }
>>          break;
>>      case VIRTIO_MMIO_GUEST_PAGE_SIZE:
>> +        if (proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>>          proxy->guest_page_shift = ctz32(value);
>>          if (proxy->guest_page_shift > 31) {
>>              proxy->guest_page_shift = 0;
>> @@ -253,15 +314,29 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>          break;
>>      case VIRTIO_MMIO_QUEUE_NUM:
>>          trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
>> -        virtio_queue_set_num(vdev, vdev->queue_sel, value);
>> -        /* Note: only call this function for legacy devices */
>> -        virtio_queue_update_rings(vdev, vdev->queue_sel);
>> +        if (proxy->modern) {
>> +            proxy->vqs[vdev->queue_sel].num = value;
>> +        } else {
>> +            virtio_queue_set_num(vdev, vdev->queue_sel, value);
>> +            virtio_queue_update_rings(vdev, vdev->queue_sel);
>> +        }
>>          break;
>>      case VIRTIO_MMIO_QUEUE_ALIGN:
>> -        /* Note: this is only valid for legacy devices */
>> +        if (proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>>          virtio_queue_set_align(vdev, vdev->queue_sel, value);
>>          break;
>>      case VIRTIO_MMIO_QUEUE_PFN:
>> +        if (proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>>          if (value == 0) {
>>              virtio_reset(vdev);
>>          } else {
>> @@ -269,6 +344,24 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>                                    value << proxy->guest_page_shift);
>>          }
>>          break;
>> +    case VIRTIO_MMIO_QUEUE_READY:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to modern register in legacy mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        virtio_queue_set_num(vdev, vdev->queue_sel,
>> +                             proxy->vqs[vdev->queue_sel].num);
>> +        virtio_queue_set_rings(vdev, vdev->queue_sel,
>> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
>> +                       proxy->vqs[vdev->queue_sel].desc[0],
>> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
>> +                       proxy->vqs[vdev->queue_sel].avail[0],
>> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
>> +                       proxy->vqs[vdev->queue_sel].used[0]);
>> +        proxy->vqs[vdev->queue_sel].enabled = 1;
>> +        break;
>
> This one seems out of spec.
> In this respect virtio mmio is more advanced that virtio pci:
> it allows setting the ready status to 0.

You're right, I'll fix it.

>>      case VIRTIO_MMIO_QUEUE_NOTIFY:
>>          if (value < VIRTIO_QUEUE_MAX) {
>>              virtio_queue_notify(vdev, value);
>> @@ -283,6 +376,12 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>              virtio_mmio_stop_ioeventfd(proxy);
>>          }
>>  
>> +        if (proxy->modern && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
>> +            virtio_set_features(vdev,
>> +                                ((uint64_t)proxy->guest_features[1]) << 32 |
>> +                                proxy->guest_features[0]);
>> +        }
>> +
>>          virtio_set_status(vdev, value & 0xff);
>>  
>>          if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
>> @@ -293,6 +392,60 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>              virtio_reset(vdev);
>>          }
>>          break;
>> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].desc[0] = value;
>> +        break;
>> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].desc[1] = value;
>> +        break;
>> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].avail[0] = value;
>> +        break;
>> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].avail[1] = value;
>> +        break;
>> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].used[0] = value;
>> +        break;
>> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
>> +        if (!proxy->modern) {
>> +            qemu_log_mask(LOG_GUEST_ERROR,
>> +                          "%s: write to legacy register in modern mode\n",
>> +                          __func__);
>> +            return;
>> +        }
>> +        proxy->vqs[vdev->queue_sel].used[1] = value;
>> +        break;
>>      case VIRTIO_MMIO_MAGIC_VALUE:
>>      case VIRTIO_MMIO_VERSION:
>>      case VIRTIO_MMIO_DEVICE_ID:
>> @@ -300,6 +453,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
>>      case VIRTIO_MMIO_DEVICE_FEATURES:
>>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
>>      case VIRTIO_MMIO_INTERRUPT_STATUS:
>> +    case VIRTIO_MMIO_CONFIG_GENERATION:
>>          qemu_log_mask(LOG_GUEST_ERROR,
>>                        "%s: write to readonly register\n",
>>                        __func__);
>> @@ -349,15 +503,90 @@ static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
>>      qemu_put_be32(f, proxy->guest_page_shift);
>>  }
>>  
>> +static const VMStateDescription vmstate_virtio_mmio_modern_queue_state = {
>> +    .name = "virtio_mmio/modern_queue_state",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT16(num, VirtIOMMIOQueue),
>> +        VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
>> +        VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
>> +        VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
>> +        VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static const VMStateDescription vmstate_virtio_mmio_modern_state_sub = {
>> +    .name = "virtio_mmio/modern_state",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
>> +        VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
>> +                             vmstate_virtio_mmio_modern_queue_state,
>> +                             VirtIOMMIOQueue),
>> +        VMSTATE_END_OF_LIST()
>> +    }
>> +};
>> +
>> +static const VMStateDescription vmstate_virtio_mmio = {
>> +    .name = "virtio_mmio",
>> +    .version_id = 1,
>> +    .minimum_version_id = 1,
>> +    .minimum_version_id_old = 1,
>> +    .fields = (VMStateField[]) {
>> +        VMSTATE_END_OF_LIST()
>> +    },
>> +    .subsections = (const VMStateDescription*[]) {
>> +        &vmstate_virtio_mmio_modern_state_sub,
>> +        NULL
>> +    }
>> +};
>> +
>> +static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
>> +{
>> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
>> +
>> +    vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
>> +}
>> +
>> +static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
>> +{
>> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
>> +
>> +    return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
>> +}
>> +
>> +static bool virtio_mmio_has_extra_state(DeviceState *opaque)
>> +{
>> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
>> +
>> +    return proxy->modern;
>> +}
>> +
>>  static void virtio_mmio_reset(DeviceState *d)
>>  {
>>      VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
>> +    int i;
>>  
>>      virtio_mmio_stop_ioeventfd(proxy);
>>      virtio_bus_reset(&proxy->bus);
>>      proxy->host_features_sel = 0;
>>      proxy->guest_features_sel = 0;
>>      proxy->guest_page_shift = 0;
>> +
>> +    if (proxy->modern) {
>> +        proxy->guest_features[0] = proxy->guest_features[1] = 0;
>> +
>> +        for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
>> +            proxy->vqs[i].enabled = 0;
>> +            proxy->vqs[i].num = 0;
>> +            proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
>> +            proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
>> +            proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
>> +        }
>> +    }
>>  }
>>  
>>  static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
>> @@ -420,11 +649,22 @@ assign_error:
>>      return r;
>>  }
>>  
>> +static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
>> +{
>> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
>> +    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
>> +
>> +    if (proxy->modern) {
>> +        virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
>> +    }
>> +}
>> +
>>  /* virtio-mmio device */
>>  
>>  static Property virtio_mmio_properties[] = {
>>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
>>                       format_transport_address, true),
>> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
>>      DEFINE_PROP_END_OF_LIST(),
>>  };
>>  
>> @@ -508,9 +748,13 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
>>      k->notify = virtio_mmio_update_irq;
>>      k->save_config = virtio_mmio_save_config;
>>      k->load_config = virtio_mmio_load_config;
>> +    k->save_extra_state = virtio_mmio_save_extra_state;
>> +    k->load_extra_state = virtio_mmio_load_extra_state;
>> +    k->has_extra_state = virtio_mmio_has_extra_state;
>>      k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
>>      k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
>>      k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
>> +    k->pre_plugged = virtio_mmio_pre_plugged;
>>      k->has_variable_vring_alignment = true;
>>      bus_class->max_dev = 1;
>>      bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
>> -- 
>> 2.21.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 20:18         ` Michael S. Tsirkin
  2019-07-31 11:04           ` Sergio Lopez
@ 2019-07-31 13:55           ` Cornelia Huck
  2019-07-31 19:06             ` Michael S. Tsirkin
  1 sibling, 1 reply; 27+ messages in thread
From: Cornelia Huck @ 2019-07-31 13:55 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: peter.maydell, Andrea Bolognani, Sergio Lopez, qemu-devel

On Tue, 30 Jul 2019 16:18:52 -0400
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Tue, Jul 30, 2019 at 03:14:00PM +0200, Cornelia Huck wrote:
> > On Tue, 30 Jul 2019 14:17:48 +0200
> > Andrea Bolognani <abologna@redhat.com> wrote:
> >   
> > > On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:  
> > > > On Tue, 30 Jul 2019 12:25:30 +0200
> > > > Andrea Bolognani <abologna@redhat.com> wrote:    
> > > > > Can you please make sure virtio-mmio uses the existing interface
> > > > > instead of introducing a new one?    
> > > > 
> > > > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> > > > starter, what is 'modern'? Will we have 'ultra-modern' in the future?    
> > > 
> > > AIUI the modern/legacy terminology is part of the VirtIO spec, so
> > > while I agree that it's not necessarily the least prone to ambiguity
> > > at least it's well defined.  
> > 
> > Legacy is, modern isn't :) Devices/drivers are conforming to the
> > standard, I don't think there's a special term for that.  
> 
> Right, if we followed the spec, disable-modern would have been
> force-legacy.
> 
> I'm fine with adding force-legacy for everyone and asking tools to
> transition if there. Document it's same as disable-modern for pci.
> Cornelia?

'force-legacy' is certainly better than 'disable-modern'. Not sure if
it's much of a gain at this point in time, and it does not really add
anything over limiting the revision to 0 for ccw, but I don't really
object to it.

> 
> 
> > >   
> > > > It is also quite backwards with the 'disable' terminology.    
> > > 
> > > That's also true. I never claimed the way virtio-pci does it is
> > > perfect!
> > >   
> > > > We also have a different mechanism for virtio-ccw ('max_revision',
> > > > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> > > > as negotiating the revision down is fine), so I don't see why
> > > > virtio-mmio should replicate the virtio-pci mechanism.
> > > > 
> > > > Also, IIUC, virtio-mmio does not have transitional devices, but either
> > > > version 1 (legacy) or version 2 (virtio-1). It probably makes more
> > > > sense to expose the device version instead; either as an exact version
> > > > (especially if it isn't supposed to go up without incompatible
> > > > changes), or with some min/max concept (where version 1 would stand a
> > > > bit alone, so that would probably be a bit awkward.)    
> > > 
> > > I think that if reinventing the wheel is generally agreed not to be
> > > a good idea, then it stands to reason that reinventing it twice can
> > > only be described as absolute madness :)
> > > 
> > > We should have a single way to control the VirtIO protocol version
> > > that works for all VirtIO devices, regardless of transport. We might
> > > even want to have virtio-*-{device,ccw}-non-transitional to mirror
> > > the existing virtio-*-pci-non-transitional.
> > > 
> > > FWIW, libvirt already implements support for (non)-transitional
> > > virtio-pci devices using either the dedicated devices or the base
> > > virtio-pci plus the disable-{modern,legacy} attributes.  
> > 
> > One problem (besides my dislike of the existing virtio-pci
> > interfaces :) is that pci, ccw, and mmio all have slightly different
> > semantics.
> > 
> > - pci: If we need to keep legacy support around, we cannot enable some
> >   features (IIRC, pci-e, maybe others as well.) That means transitional
> >   devices are in some ways inferior to virtio-1 only devices, so it
> >   makes a lot of sense to be able to configure devices without legacy
> >   support. The differences between legacy and virtio-1 are quite large.
> > - ccw: Has revisions negotiated between device and driver; virtio-1
> >   requires revision 1 or higher. (Legacy drivers that don't know the
> >   concept of revisions automatically get revision 0.) Differences
> >   between legacy and virtio-1 are mostly virtqueue endianness and some
> >   control structures.
> > - mmio: Has device versions offered by the device, the driver can take
> >   it or leave it. No transitional devices. Differences don't look as
> >   large as the ones for pci, either.
> > 
> > So, if we were to duplicate the same scheme as for pci for ccw and mmio
> > as well, we'd get
> > 
> > - ccw: devices that support revision 0 only (disable-modern), that act
> >   as today, or that support at least revision 1 (disable-legacy). We
> >   still need to keep max_revision around for backwards compatibility.
> >   Legacy only makes sense for compat machines (although this is
> >   equivalent to max_revision 0); I don't see a reason why you would
> >   want virtio-1 only devices, unless you'd want to rip out legacy
> >   support in QEMU completely.  
> 
> Reduce security attack surface slightly. Save some cycles
> (down the road) on branches in the endian-ness handling.

Most of that stuff is actually in the core code, right? Ripping out
legacy will have much more impact outside of ccw, I guess.

> Make sure your guests
> are all up to date in preparation to the day when legacy will go away.

If legacy goes away, legacy guests will be busted anyway :)

(There should not be many, if any, of these -- ccw switched on virtio-1
by default quite some time ago, and the s390x legacy virtio transport
was s390-virtio anyway :)

> 
> Not a huge win, for sure, but hey - it's something.
> 
> > - mmio: devices that support version 1 (disable-modern), or version 2
> >   (disable-legacy). You cannot have both at the same time. Whether this
> >   makes sense depends on whether there will be a version 3 in the
> >   future.
> > 
> > So, this might make some sense for mmio; for ccw, I don't see any
> > advantages other than confusing people further...  



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 13:55           ` Cornelia Huck
@ 2019-07-31 19:06             ` Michael S. Tsirkin
  2019-08-01  8:18               ` Cornelia Huck
  0 siblings, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-07-31 19:06 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: peter.maydell, Andrea Bolognani, Sergio Lopez, qemu-devel

On Wed, Jul 31, 2019 at 03:55:51PM +0200, Cornelia Huck wrote:
> On Tue, 30 Jul 2019 16:18:52 -0400
> "Michael S. Tsirkin" <mst@redhat.com> wrote:
> 
> > On Tue, Jul 30, 2019 at 03:14:00PM +0200, Cornelia Huck wrote:
> > > On Tue, 30 Jul 2019 14:17:48 +0200
> > > Andrea Bolognani <abologna@redhat.com> wrote:
> > >   
> > > > On Tue, 2019-07-30 at 13:35 +0200, Cornelia Huck wrote:  
> > > > > On Tue, 30 Jul 2019 12:25:30 +0200
> > > > > Andrea Bolognani <abologna@redhat.com> wrote:    
> > > > > > Can you please make sure virtio-mmio uses the existing interface
> > > > > > instead of introducing a new one?    
> > > > > 
> > > > > FWIW, I really hate virtio-pci's disable-modern/disable-legacy... for a
> > > > > starter, what is 'modern'? Will we have 'ultra-modern' in the future?    
> > > > 
> > > > AIUI the modern/legacy terminology is part of the VirtIO spec, so
> > > > while I agree that it's not necessarily the least prone to ambiguity
> > > > at least it's well defined.  
> > > 
> > > Legacy is, modern isn't :) Devices/drivers are conforming to the
> > > standard, I don't think there's a special term for that.  
> > 
> > Right, if we followed the spec, disable-modern would have been
> > force-legacy.
> > 
> > I'm fine with adding force-legacy for everyone and asking tools to
> > transition if there. Document it's same as disable-modern for pci.
> > Cornelia?
> 
> 'force-legacy' is certainly better than 'disable-modern'. Not sure if
> it's much of a gain at this point in time, and it does not really add
> anything over limiting the revision to 0 for ccw, but I don't really
> object to it.
> 
> > 
> > 
> > > >   
> > > > > It is also quite backwards with the 'disable' terminology.    
> > > > 
> > > > That's also true. I never claimed the way virtio-pci does it is
> > > > perfect!
> > > >   
> > > > > We also have a different mechanism for virtio-ccw ('max_revision',
> > > > > which covers a bit more than virtio-1; it doesn't have a 'min_revision',
> > > > > as negotiating the revision down is fine), so I don't see why
> > > > > virtio-mmio should replicate the virtio-pci mechanism.
> > > > > 
> > > > > Also, IIUC, virtio-mmio does not have transitional devices, but either
> > > > > version 1 (legacy) or version 2 (virtio-1). It probably makes more
> > > > > sense to expose the device version instead; either as an exact version
> > > > > (especially if it isn't supposed to go up without incompatible
> > > > > changes), or with some min/max concept (where version 1 would stand a
> > > > > bit alone, so that would probably be a bit awkward.)    
> > > > 
> > > > I think that if reinventing the wheel is generally agreed not to be
> > > > a good idea, then it stands to reason that reinventing it twice can
> > > > only be described as absolute madness :)
> > > > 
> > > > We should have a single way to control the VirtIO protocol version
> > > > that works for all VirtIO devices, regardless of transport. We might
> > > > even want to have virtio-*-{device,ccw}-non-transitional to mirror
> > > > the existing virtio-*-pci-non-transitional.
> > > > 
> > > > FWIW, libvirt already implements support for (non)-transitional
> > > > virtio-pci devices using either the dedicated devices or the base
> > > > virtio-pci plus the disable-{modern,legacy} attributes.  
> > > 
> > > One problem (besides my dislike of the existing virtio-pci
> > > interfaces :) is that pci, ccw, and mmio all have slightly different
> > > semantics.
> > > 
> > > - pci: If we need to keep legacy support around, we cannot enable some
> > >   features (IIRC, pci-e, maybe others as well.) That means transitional
> > >   devices are in some ways inferior to virtio-1 only devices, so it
> > >   makes a lot of sense to be able to configure devices without legacy
> > >   support. The differences between legacy and virtio-1 are quite large.
> > > - ccw: Has revisions negotiated between device and driver; virtio-1
> > >   requires revision 1 or higher. (Legacy drivers that don't know the
> > >   concept of revisions automatically get revision 0.) Differences
> > >   between legacy and virtio-1 are mostly virtqueue endianness and some
> > >   control structures.
> > > - mmio: Has device versions offered by the device, the driver can take
> > >   it or leave it. No transitional devices. Differences don't look as
> > >   large as the ones for pci, either.
> > > 
> > > So, if we were to duplicate the same scheme as for pci for ccw and mmio
> > > as well, we'd get
> > > 
> > > - ccw: devices that support revision 0 only (disable-modern), that act
> > >   as today, or that support at least revision 1 (disable-legacy). We
> > >   still need to keep max_revision around for backwards compatibility.
> > >   Legacy only makes sense for compat machines (although this is
> > >   equivalent to max_revision 0); I don't see a reason why you would
> > >   want virtio-1 only devices, unless you'd want to rip out legacy
> > >   support in QEMU completely.  
> > 
> > Reduce security attack surface slightly. Save some cycles
> > (down the road) on branches in the endian-ness handling.
> 
> Most of that stuff is actually in the core code, right? Ripping out
> legacy will have much more impact outside of ccw, I guess.
> 
> > Make sure your guests
> > are all up to date in preparation to the day when legacy will go away.
> 
> If legacy goes away, legacy guests will be busted anyway :)

It'll take a while for it to go away. But we can try to
push guests in the direction of coding up modern
support e.g. by forcing modern by default.

> (There should not be many, if any, of these -- ccw switched on virtio-1
> by default quite some time ago, and the s390x legacy virtio transport
> was s390-virtio anyway :)
> 
> > 
> > Not a huge win, for sure, but hey - it's something.
> > 
> > > - mmio: devices that support version 1 (disable-modern), or version 2
> > >   (disable-legacy). You cannot have both at the same time. Whether this
> > >   makes sense depends on whether there will be a version 3 in the
> > >   future.
> > > 
> > > So, this might make some sense for mmio; for ccw, I don't see any
> > > advantages other than confusing people further...  


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 12:22   ` Sergio Lopez
@ 2019-07-31 19:34     ` Michael S. Tsirkin
  2019-07-31 21:22     ` Eduardo Habkost
  1 sibling, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-07-31 19:34 UTC (permalink / raw)
  To: Sergio Lopez; +Cc: peter.maydell, qemu-devel, ehabkost

On Wed, Jul 31, 2019 at 02:22:09PM +0200, Sergio Lopez wrote:
> 
> Michael S. Tsirkin <mst@redhat.com> writes:
> 
> > On Mon, Jul 29, 2019 at 02:57:55PM +0200, Sergio Lopez wrote:
> >> Implement the modern (v2) personality, according to the VirtIO 1.0
> >> specification.
> >> 
> >> Support for v2 among guests is not as widespread as it'd be
> >> desirable. While the Linux driver has had it for a while, support is
> >> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
> >
> > The fact that there was no open source hypervisor implementation has
> > probably contributed to this :)
> >
> >> For this reason, the v2 personality is disabled, keeping the legacy
> >> behavior as default.
> >
> > I agree it's a good default for existing machine types.
> >
> >> Machine types willing to use v2, can enable it
> >> using MachineClass's compat_props.
> >
> > Hmm. Are compat_props really the recommended mechanism to
> > tweak defaults? I was under the impression it's
> > only for compatibility with old machine types.
> > Eduardo, any opinion on this?
> 
> Stefan suggested using something like "-global virtio-mmio.modern=true"
> which does the trick for the command line, but I'd also like a way to
> set it to true by default on microvm. We can discuss the best way to
> achieve that (if using compat_props isn't acceptable) on the next
> microvm patch series.

I'm not saying it's wrong, just asking.

> >> 
> >> Signed-off-by: Sergio Lopez <slp@redhat.com>
> >
> > Endian-ness seems to be wrong:
> >
> > static const MemoryRegionOps virtio_mem_ops = {
> >     .read = virtio_mmio_read,
> >     .write = virtio_mmio_write,
> >     .endianness = DEVICE_NATIVE_ENDIAN,
> > };
> >
> > you will see this if you test a big endian guest.
> 
> Interesting, a Linux kernel compiled for aarch64_be works just
> fine. Looking further, seems like, on ARM, Linux assumes all memory I/O
> operations are little-endian and swaps the data if necessary:
> 
> arch/arm64/include/asm/io.h:
> /*
>  * Relaxed I/O memory access primitives. These follow the Device memory
>  * ordering rules but do not guarantee any ordering relative to Normal memory
>  * accesses.
>  */
> #define readb_relaxed(c)	({ u8  __r = __raw_readb(c); __r; })
> #define readw_relaxed(c)	({ u16 __r = le16_to_cpu((__force __le16)__raw_readw(c)); __r; })
> #define readl_relaxed(c)	({ u32 __r = le32_to_cpu((__force __le32)__raw_readl(c)); __r; })
> #define readq_relaxed(c)	({ u64 __r = le64_to_cpu((__force __le64)__raw_readq(c)); __r; })
> 
> #define writeb_relaxed(v,c)	((void)__raw_writeb((v),(c)))
> #define writew_relaxed(v,c)	((void)__raw_writew((__force u16)cpu_to_le16(v),(c)))
> #define writel_relaxed(v,c)	((void)__raw_writel((__force u32)cpu_to_le32(v),(c)))
> #define writeq_relaxed(v,c)	((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
> 
> The Apendix X from virtio-0.9.5 specs states that "The endianness of the
> registers follows the native endianness of the Guest". Luckily for us,
> this isn't the case, as with DEVICE_NATIVE_ENDIAN
> memory.c:adjust_endianness doesn't attempt any kind of transformation.

Oh sorry, I should have said big endian *host*. DEVICE_NATIVE_ENDIAN
follows the host endian-ness.


> In any, I guess we should follow the spec, and keep DEVICE_NATIVE_ENDIAN
> for the legacy mode while using DEVICE_LITTLE_ENDIAN for
> virtio-mmio-2/virtio-1.
> 
> >> ---
> >>  hw/virtio/virtio-mmio.c | 264 ++++++++++++++++++++++++++++++++++++++--
> >>  1 file changed, 254 insertions(+), 10 deletions(-)
> >> 
> >> diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
> >> index 97b7f35496..1da841336f 100644
> >> --- a/hw/virtio/virtio-mmio.c
> >> +++ b/hw/virtio/virtio-mmio.c
> >> @@ -47,14 +47,24 @@
> >>          OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO)
> >>  
> >>  #define VIRT_MAGIC 0x74726976 /* 'virt' */
> >> -#define VIRT_VERSION 1
> >> +#define VIRT_VERSION_LEGACY 1
> >> +#define VIRT_VERSION_MODERN 2
> >>  #define VIRT_VENDOR 0x554D4551 /* 'QEMU' */
> >>  
> >> +typedef struct VirtIOMMIOQueue {
> >> +    uint16_t num;
> >> +    bool enabled;
> >> +    uint32_t desc[2];
> >> +    uint32_t avail[2];
> >> +    uint32_t used[2];
> >> +} VirtIOMMIOQueue;
> >> +
> >>  typedef struct {
> >>      /* Generic */
> >>      SysBusDevice parent_obj;
> >>      MemoryRegion iomem;
> >>      qemu_irq irq;
> >> +    bool modern;
> >>      /* Guest accessible state needing migration and reset */
> >>      uint32_t host_features_sel;
> >>      uint32_t guest_features_sel;
> >> @@ -62,6 +72,9 @@ typedef struct {
> >>      /* virtio-bus */
> >>      VirtioBusState bus;
> >>      bool format_transport_address;
> >> +    /* Fields only used for v2 (modern) devices */
> >> +    uint32_t guest_features[2];
> >> +    VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
> >>  } VirtIOMMIOProxy;
> >>  
> >>  static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
> >> @@ -115,7 +128,11 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
> >>          case VIRTIO_MMIO_MAGIC_VALUE:
> >>              return VIRT_MAGIC;
> >>          case VIRTIO_MMIO_VERSION:
> >> -            return VIRT_VERSION;
> >> +            if (proxy->modern) {
> >> +                return VIRT_VERSION_MODERN;
> >> +            } else {
> >> +                return VIRT_VERSION_LEGACY;
> >> +            }
> >>          case VIRTIO_MMIO_VENDOR_ID:
> >>              return VIRT_VENDOR;
> >>          default:
> >> @@ -146,14 +163,18 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
> >>      case VIRTIO_MMIO_MAGIC_VALUE:
> >>          return VIRT_MAGIC;
> >>      case VIRTIO_MMIO_VERSION:
> >> -        return VIRT_VERSION;
> >> +        if (proxy->modern) {
> >> +            return VIRT_VERSION_MODERN;
> >> +        } else {
> >> +            return VIRT_VERSION_LEGACY;
> >> +        }
> >>      case VIRTIO_MMIO_DEVICE_ID:
> >>          return vdev->device_id;
> >>      case VIRTIO_MMIO_VENDOR_ID:
> >>          return VIRT_VENDOR;
> >>      case VIRTIO_MMIO_DEVICE_FEATURES:
> >>          if (proxy->host_features_sel) {
> >> -            return 0;
> >> +            return vdev->host_features >> 32;
> >
> > I'd do vdev->host_features >> (32 * proxy->host_features_sel);
> 
> OK, looks nicer. I'll sanitize the value host_features_sel on
> VIRTIO_MMIO_DEVICE_FEATURES too, as I'm already doing with
> guest_features_sel.
> 
> >>          }
> >>          return vdev->host_features;
> >>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
> >> @@ -162,12 +183,34 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
> >>          }
> >>          return VIRTQUEUE_MAX_SIZE;
> >>      case VIRTIO_MMIO_QUEUE_PFN:
> >> +        if (proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: read from legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return 0;
> >> +        }
> >>          return virtio_queue_get_addr(vdev, vdev->queue_sel)
> >>              >> proxy->guest_page_shift;
> >> +    case VIRTIO_MMIO_QUEUE_READY:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: read from modern register in legacy mode\n",
> >> +                          __func__);
> >> +            return 0;
> >> +        }
> >> +        return proxy->vqs[vdev->queue_sel].enabled;
> >>      case VIRTIO_MMIO_INTERRUPT_STATUS:
> >>          return atomic_read(&vdev->isr);
> >>      case VIRTIO_MMIO_STATUS:
> >>          return vdev->status;
> >> +    case VIRTIO_MMIO_CONFIG_GENERATION:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: read from modern register in legacy mode\n",
> >> +                          __func__);
> >> +            return 0;
> >> +        }
> >> +        return vdev->generation;
> >>      case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
> >>      case VIRTIO_MMIO_DRIVER_FEATURES:
> >>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
> >> @@ -177,6 +220,12 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
> >>      case VIRTIO_MMIO_QUEUE_ALIGN:
> >>      case VIRTIO_MMIO_QUEUE_NOTIFY:
> >>      case VIRTIO_MMIO_INTERRUPT_ACK:
> >> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
> >> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
> >> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
> >> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
> >> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
> >> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
> >>          qemu_log_mask(LOG_GUEST_ERROR,
> >>                        "%s: read of write-only register\n",
> >>                        __func__);
> >> @@ -232,14 +281,26 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>          proxy->host_features_sel = value;
> >>          break;
> >>      case VIRTIO_MMIO_DRIVER_FEATURES:
> >> -        if (!proxy->guest_features_sel) {
> >> +        if (proxy->modern) {
> >> +            proxy->guest_features[proxy->guest_features_sel] = value;
> >> +        } else if (!proxy->guest_features_sel) {
> >>              virtio_set_features(vdev, value);
> >>          }
> >>          break;
> >>      case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
> >> -        proxy->guest_features_sel = value;
> >> +        if (value) {
> >> +            proxy->guest_features_sel = 1;
> >> +        } else {
> >> +            proxy->guest_features_sel = 0;
> >> +        }
> >>          break;
> >>      case VIRTIO_MMIO_GUEST_PAGE_SIZE:
> >> +        if (proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >>          proxy->guest_page_shift = ctz32(value);
> >>          if (proxy->guest_page_shift > 31) {
> >>              proxy->guest_page_shift = 0;
> >> @@ -253,15 +314,29 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>          break;
> >>      case VIRTIO_MMIO_QUEUE_NUM:
> >>          trace_virtio_mmio_queue_write(value, VIRTQUEUE_MAX_SIZE);
> >> -        virtio_queue_set_num(vdev, vdev->queue_sel, value);
> >> -        /* Note: only call this function for legacy devices */
> >> -        virtio_queue_update_rings(vdev, vdev->queue_sel);
> >> +        if (proxy->modern) {
> >> +            proxy->vqs[vdev->queue_sel].num = value;
> >> +        } else {
> >> +            virtio_queue_set_num(vdev, vdev->queue_sel, value);
> >> +            virtio_queue_update_rings(vdev, vdev->queue_sel);
> >> +        }
> >>          break;
> >>      case VIRTIO_MMIO_QUEUE_ALIGN:
> >> -        /* Note: this is only valid for legacy devices */
> >> +        if (proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >>          virtio_queue_set_align(vdev, vdev->queue_sel, value);
> >>          break;
> >>      case VIRTIO_MMIO_QUEUE_PFN:
> >> +        if (proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >>          if (value == 0) {
> >>              virtio_reset(vdev);
> >>          } else {
> >> @@ -269,6 +344,24 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>                                    value << proxy->guest_page_shift);
> >>          }
> >>          break;
> >> +    case VIRTIO_MMIO_QUEUE_READY:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to modern register in legacy mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        virtio_queue_set_num(vdev, vdev->queue_sel,
> >> +                             proxy->vqs[vdev->queue_sel].num);
> >> +        virtio_queue_set_rings(vdev, vdev->queue_sel,
> >> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
> >> +                       proxy->vqs[vdev->queue_sel].desc[0],
> >> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
> >> +                       proxy->vqs[vdev->queue_sel].avail[0],
> >> +                       ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
> >> +                       proxy->vqs[vdev->queue_sel].used[0]);
> >> +        proxy->vqs[vdev->queue_sel].enabled = 1;
> >> +        break;
> >
> > This one seems out of spec.
> > In this respect virtio mmio is more advanced that virtio pci:
> > it allows setting the ready status to 0.
> 
> You're right, I'll fix it.
> 
> >>      case VIRTIO_MMIO_QUEUE_NOTIFY:
> >>          if (value < VIRTIO_QUEUE_MAX) {
> >>              virtio_queue_notify(vdev, value);
> >> @@ -283,6 +376,12 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>              virtio_mmio_stop_ioeventfd(proxy);
> >>          }
> >>  
> >> +        if (proxy->modern && (value & VIRTIO_CONFIG_S_FEATURES_OK)) {
> >> +            virtio_set_features(vdev,
> >> +                                ((uint64_t)proxy->guest_features[1]) << 32 |
> >> +                                proxy->guest_features[0]);
> >> +        }
> >> +
> >>          virtio_set_status(vdev, value & 0xff);
> >>  
> >>          if (value & VIRTIO_CONFIG_S_DRIVER_OK) {
> >> @@ -293,6 +392,60 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>              virtio_reset(vdev);
> >>          }
> >>          break;
> >> +    case VIRTIO_MMIO_QUEUE_DESC_LOW:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].desc[0] = value;
> >> +        break;
> >> +    case VIRTIO_MMIO_QUEUE_DESC_HIGH:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].desc[1] = value;
> >> +        break;
> >> +    case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].avail[0] = value;
> >> +        break;
> >> +    case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].avail[1] = value;
> >> +        break;
> >> +    case VIRTIO_MMIO_QUEUE_USED_LOW:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].used[0] = value;
> >> +        break;
> >> +    case VIRTIO_MMIO_QUEUE_USED_HIGH:
> >> +        if (!proxy->modern) {
> >> +            qemu_log_mask(LOG_GUEST_ERROR,
> >> +                          "%s: write to legacy register in modern mode\n",
> >> +                          __func__);
> >> +            return;
> >> +        }
> >> +        proxy->vqs[vdev->queue_sel].used[1] = value;
> >> +        break;
> >>      case VIRTIO_MMIO_MAGIC_VALUE:
> >>      case VIRTIO_MMIO_VERSION:
> >>      case VIRTIO_MMIO_DEVICE_ID:
> >> @@ -300,6 +453,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
> >>      case VIRTIO_MMIO_DEVICE_FEATURES:
> >>      case VIRTIO_MMIO_QUEUE_NUM_MAX:
> >>      case VIRTIO_MMIO_INTERRUPT_STATUS:
> >> +    case VIRTIO_MMIO_CONFIG_GENERATION:
> >>          qemu_log_mask(LOG_GUEST_ERROR,
> >>                        "%s: write to readonly register\n",
> >>                        __func__);
> >> @@ -349,15 +503,90 @@ static void virtio_mmio_save_config(DeviceState *opaque, QEMUFile *f)
> >>      qemu_put_be32(f, proxy->guest_page_shift);
> >>  }
> >>  
> >> +static const VMStateDescription vmstate_virtio_mmio_modern_queue_state = {
> >> +    .name = "virtio_mmio/modern_queue_state",
> >> +    .version_id = 1,
> >> +    .minimum_version_id = 1,
> >> +    .fields = (VMStateField[]) {
> >> +        VMSTATE_UINT16(num, VirtIOMMIOQueue),
> >> +        VMSTATE_BOOL(enabled, VirtIOMMIOQueue),
> >> +        VMSTATE_UINT32_ARRAY(desc, VirtIOMMIOQueue, 2),
> >> +        VMSTATE_UINT32_ARRAY(avail, VirtIOMMIOQueue, 2),
> >> +        VMSTATE_UINT32_ARRAY(used, VirtIOMMIOQueue, 2),
> >> +        VMSTATE_END_OF_LIST()
> >> +    }
> >> +};
> >> +
> >> +static const VMStateDescription vmstate_virtio_mmio_modern_state_sub = {
> >> +    .name = "virtio_mmio/modern_state",
> >> +    .version_id = 1,
> >> +    .minimum_version_id = 1,
> >> +    .fields = (VMStateField[]) {
> >> +        VMSTATE_UINT32_ARRAY(guest_features, VirtIOMMIOProxy, 2),
> >> +        VMSTATE_STRUCT_ARRAY(vqs, VirtIOMMIOProxy, VIRTIO_QUEUE_MAX, 0,
> >> +                             vmstate_virtio_mmio_modern_queue_state,
> >> +                             VirtIOMMIOQueue),
> >> +        VMSTATE_END_OF_LIST()
> >> +    }
> >> +};
> >> +
> >> +static const VMStateDescription vmstate_virtio_mmio = {
> >> +    .name = "virtio_mmio",
> >> +    .version_id = 1,
> >> +    .minimum_version_id = 1,
> >> +    .minimum_version_id_old = 1,
> >> +    .fields = (VMStateField[]) {
> >> +        VMSTATE_END_OF_LIST()
> >> +    },
> >> +    .subsections = (const VMStateDescription*[]) {
> >> +        &vmstate_virtio_mmio_modern_state_sub,
> >> +        NULL
> >> +    }
> >> +};
> >> +
> >> +static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
> >> +{
> >> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> >> +
> >> +    vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL);
> >> +}
> >> +
> >> +static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
> >> +{
> >> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> >> +
> >> +    return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1);
> >> +}
> >> +
> >> +static bool virtio_mmio_has_extra_state(DeviceState *opaque)
> >> +{
> >> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
> >> +
> >> +    return proxy->modern;
> >> +}
> >> +
> >>  static void virtio_mmio_reset(DeviceState *d)
> >>  {
> >>      VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
> >> +    int i;
> >>  
> >>      virtio_mmio_stop_ioeventfd(proxy);
> >>      virtio_bus_reset(&proxy->bus);
> >>      proxy->host_features_sel = 0;
> >>      proxy->guest_features_sel = 0;
> >>      proxy->guest_page_shift = 0;
> >> +
> >> +    if (proxy->modern) {
> >> +        proxy->guest_features[0] = proxy->guest_features[1] = 0;
> >> +
> >> +        for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
> >> +            proxy->vqs[i].enabled = 0;
> >> +            proxy->vqs[i].num = 0;
> >> +            proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
> >> +            proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
> >> +            proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
> >> +        }
> >> +    }
> >>  }
> >>  
> >>  static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
> >> @@ -420,11 +649,22 @@ assign_error:
> >>      return r;
> >>  }
> >>  
> >> +static void virtio_mmio_pre_plugged(DeviceState *d, Error **errp)
> >> +{
> >> +    VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
> >> +    VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
> >> +
> >> +    if (proxy->modern) {
> >> +        virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
> >> +    }
> >> +}
> >> +
> >>  /* virtio-mmio device */
> >>  
> >>  static Property virtio_mmio_properties[] = {
> >>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
> >>                       format_transport_address, true),
> >> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
> >>      DEFINE_PROP_END_OF_LIST(),
> >>  };
> >>  
> >> @@ -508,9 +748,13 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
> >>      k->notify = virtio_mmio_update_irq;
> >>      k->save_config = virtio_mmio_save_config;
> >>      k->load_config = virtio_mmio_load_config;
> >> +    k->save_extra_state = virtio_mmio_save_extra_state;
> >> +    k->load_extra_state = virtio_mmio_load_extra_state;
> >> +    k->has_extra_state = virtio_mmio_has_extra_state;
> >>      k->set_guest_notifiers = virtio_mmio_set_guest_notifiers;
> >>      k->ioeventfd_enabled = virtio_mmio_ioeventfd_enabled;
> >>      k->ioeventfd_assign = virtio_mmio_ioeventfd_assign;
> >> +    k->pre_plugged = virtio_mmio_pre_plugged;
> >>      k->has_variable_vring_alignment = true;
> >>      bus_class->max_dev = 1;
> >>      bus_class->get_dev_path = virtio_mmio_bus_get_dev_path;
> >> -- 
> >> 2.21.0
> 




^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 12:22   ` Sergio Lopez
  2019-07-31 19:34     ` Michael S. Tsirkin
@ 2019-07-31 21:22     ` Eduardo Habkost
  1 sibling, 0 replies; 27+ messages in thread
From: Eduardo Habkost @ 2019-07-31 21:22 UTC (permalink / raw)
  To: Sergio Lopez; +Cc: peter.maydell, qemu-devel, Michael S. Tsirkin

On Wed, Jul 31, 2019 at 02:22:09PM +0200, Sergio Lopez wrote:
> 
> Michael S. Tsirkin <mst@redhat.com> writes:
> 
> > On Mon, Jul 29, 2019 at 02:57:55PM +0200, Sergio Lopez wrote:
> >> Implement the modern (v2) personality, according to the VirtIO 1.0
> >> specification.
> >> 
> >> Support for v2 among guests is not as widespread as it'd be
> >> desirable. While the Linux driver has had it for a while, support is
> >> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
> >
> > The fact that there was no open source hypervisor implementation has
> > probably contributed to this :)
> >
> >> For this reason, the v2 personality is disabled, keeping the legacy
> >> behavior as default.
> >
> > I agree it's a good default for existing machine types.
> >
> >> Machine types willing to use v2, can enable it
> >> using MachineClass's compat_props.
> >
> > Hmm. Are compat_props really the recommended mechanism to
> > tweak defaults? I was under the impression it's
> > only for compatibility with old machine types.
> > Eduardo, any opinion on this?
> 
> Stefan suggested using something like "-global virtio-mmio.modern=true"
> which does the trick for the command line, but I'd also like a way to
> set it to true by default on microvm. We can discuss the best way to
> achieve that (if using compat_props isn't acceptable) on the next
> microvm patch series.

Compatibility is the most common use case, but IMO compat_props
can be used for other kinds of machine-specific defaults.  It's
better than burying defaults inside non-introspectable machine
initialization functions.

-- 
Eduardo


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 16:06 ` Laszlo Ersek
@ 2019-07-31 23:58   ` Paolo Bonzini
  2019-08-01 19:45     ` Michael S. Tsirkin
  2019-08-02  0:26     ` Laszlo Ersek
  2019-08-01  8:37   ` Sergio Lopez
  1 sibling, 2 replies; 27+ messages in thread
From: Paolo Bonzini @ 2019-07-31 23:58 UTC (permalink / raw)
  To: Laszlo Ersek, Michael S. Tsirkin, Sergio Lopez Pascual,
	Peter Maydell, qemu-devel

On 30/07/19 18:06, Laszlo Ersek wrote:
> On 07/29/19 14:57, Sergio Lopez wrote:
>> Implement the modern (v2) personality, according to the VirtIO 1.0
>> specification.
>>
>> Support for v2 among guests is not as widespread as it'd be
>> desirable. While the Linux driver has had it for a while, support is
>> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
> 
> That's right; not only are there no plans to implement virtio-mmio/1.0
> for OVMF (to my knowledge), I'd even argue against such efforts.
> 
> OVMF is a heavy-weight guest firmware, which I see entirely out of scope
> for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
> unwelcome complication, from the OVMF maintainership perspective.

But given that, why not rip out virtio-mmio completely?

Paolo


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 19:06             ` Michael S. Tsirkin
@ 2019-08-01  8:18               ` Cornelia Huck
  0 siblings, 0 replies; 27+ messages in thread
From: Cornelia Huck @ 2019-08-01  8:18 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: peter.maydell, Andrea Bolognani, Sergio Lopez, qemu-devel

On Wed, 31 Jul 2019 15:06:11 -0400
"Michael S. Tsirkin" <mst@redhat.com> wrote:

> On Wed, Jul 31, 2019 at 03:55:51PM +0200, Cornelia Huck wrote:
> > On Tue, 30 Jul 2019 16:18:52 -0400
> > "Michael S. Tsirkin" <mst@redhat.com> wrote:

> > > Make sure your guests
> > > are all up to date in preparation to the day when legacy will go away.  
> > 
> > If legacy goes away, legacy guests will be busted anyway :)  
> 
> It'll take a while for it to go away. But we can try to
> push guests in the direction of coding up modern
> support e.g. by forcing modern by default.

Actually, ccw defaulted to transitional devices right back when we
introduced support for virtio-1 - starting with QEMU 2.5.

I'm not sure how many (if any) supported guest OSs (various variants of
Linux) support virtio-ccw devices in legacy mode only. We can probably
neglect that issue, but I would not really complain if someone
submitted a patch to optionally turn off legacy support for ccw.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-30 16:06 ` Laszlo Ersek
  2019-07-31 23:58   ` Paolo Bonzini
@ 2019-08-01  8:37   ` Sergio Lopez
  1 sibling, 0 replies; 27+ messages in thread
From: Sergio Lopez @ 2019-08-01  8:37 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: peter.maydell, qemu-devel, mst

[-- Attachment #1: Type: text/plain, Size: 1456 bytes --]


Laszlo Ersek <lersek@redhat.com> writes:

> On 07/29/19 14:57, Sergio Lopez wrote:
>> Implement the modern (v2) personality, according to the VirtIO 1.0
>> specification.
>> 
>> Support for v2 among guests is not as widespread as it'd be
>> desirable. While the Linux driver has had it for a while, support is
>> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
>
> That's right; not only are there no plans to implement virtio-mmio/1.0
> for OVMF (to my knowledge), I'd even argue against such efforts.

That's good to know, because I was planning to work on that (the changes
are quite small, actually) in a couple weeks. ;-)

> OVMF is a heavy-weight guest firmware, which I see entirely out of scope
> for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
> unwelcome complication, from the OVMF maintainership perspective.
>
> (This should not be construed as an argument against "micro VMs" -- I
> always say, identify your use case, then pick the right components for
> it. I never try to convince people to use OVMF indiscriminately.)
>
>> For this reason, the v2 personality is disabled, keeping the legacy
>> behavior as default. Machine types willing to use v2, can enable it
>> using MachineClass's compat_props.
>
> This approach makes me happy (with the understanding that edk2 guest
> firmware is not going to target the new machine type(s) in question).
>
> Thanks!
> Laszlo


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 11:02   ` Sergio Lopez
@ 2019-08-01 12:17     ` Michael S. Tsirkin
  0 siblings, 0 replies; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-08-01 12:17 UTC (permalink / raw)
  To: Sergio Lopez; +Cc: peter.maydell, Andrea Bolognani, qemu-devel

On Wed, Jul 31, 2019 at 01:02:13PM +0200, Sergio Lopez wrote:
> 
> Andrea Bolognani <abologna@redhat.com> writes:
> 
> > On Mon, 2019-07-29 at 14:57 +0200, Sergio Lopez wrote:
> > [...]
> >>  /* virtio-mmio device */
> >>  
> >>  static Property virtio_mmio_properties[] = {
> >>      DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
> >>                       format_transport_address, true),
> >> +    DEFINE_PROP_BOOL("modern", VirtIOMMIOProxy, modern, false),
> >>      DEFINE_PROP_END_OF_LIST(),
> >>  };
> >
> > Not a QEMU developer so forgive me if I say something silly, but IIUC
> > you'd be able to opt into the new feature by using eg.
> >
> >   -device virtio-net-device,modern=on
> >
> > However, virtio-pci devices already have a mechanism to control the
> > VirtIO protocol version, where you use
> >
> >   -device virtio-net-pci,disable-modern=no,disable-legacy=yes
> >
> > to get a VirtIO 1.x-only device and
> >
> >   -device virtio-net-pci,disable-modern=no,disable-legacy=no
> >
> > for a transitional device.
> >
> > Can you please make sure virtio-mmio uses the existing interface
> > instead of introducing a new one?
> 
> The problem here is that virtio-pci devices register an specific type
> for each kind of supported device (virtio-net-pci, virtio-blk-pci...),
> while virtio-mmio doesn't. This saves a lot of boilerplate, but also
> implies that bus properties can't be passed through the attached device
> (virtio-blk-device can't carry properties for it's virtio-mmio parent
> bus).
> 
> Sergio.

That's something we wanted to fix a long time ago though.

-- 
MST


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 23:58   ` Paolo Bonzini
@ 2019-08-01 19:45     ` Michael S. Tsirkin
  2019-08-02  9:24       ` Paolo Bonzini
  2019-08-02  0:26     ` Laszlo Ersek
  1 sibling, 1 reply; 27+ messages in thread
From: Michael S. Tsirkin @ 2019-08-01 19:45 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Peter Maydell, Laszlo Ersek, qemu-devel, Sergio Lopez Pascual

On Thu, Aug 01, 2019 at 01:58:35AM +0200, Paolo Bonzini wrote:
> On 30/07/19 18:06, Laszlo Ersek wrote:
> > On 07/29/19 14:57, Sergio Lopez wrote:
> >> Implement the modern (v2) personality, according to the VirtIO 1.0
> >> specification.
> >>
> >> Support for v2 among guests is not as widespread as it'd be
> >> desirable. While the Linux driver has had it for a while, support is
> >> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
> > 
> > That's right; not only are there no plans to implement virtio-mmio/1.0
> > for OVMF (to my knowledge), I'd even argue against such efforts.
> > 
> > OVMF is a heavy-weight guest firmware, which I see entirely out of scope
> > for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
> > unwelcome complication, from the OVMF maintainership perspective.
> 
> But given that, why not rip out virtio-mmio completely?
> 
> Paolo

From OVMF?


-- 
MST


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-07-31 23:58   ` Paolo Bonzini
  2019-08-01 19:45     ` Michael S. Tsirkin
@ 2019-08-02  0:26     ` Laszlo Ersek
  2019-08-02  9:20       ` Peter Maydell
  1 sibling, 1 reply; 27+ messages in thread
From: Laszlo Ersek @ 2019-08-02  0:26 UTC (permalink / raw)
  To: Paolo Bonzini, Michael S. Tsirkin, Sergio Lopez Pascual,
	Peter Maydell, qemu-devel

On 08/01/19 01:58, Paolo Bonzini wrote:
> On 30/07/19 18:06, Laszlo Ersek wrote:
>> On 07/29/19 14:57, Sergio Lopez wrote:
>>> Implement the modern (v2) personality, according to the VirtIO 1.0
>>> specification.
>>>
>>> Support for v2 among guests is not as widespread as it'd be
>>> desirable. While the Linux driver has had it for a while, support is
>>> missing, at least, from Tianocore EDK II, NetBSD and FreeBSD.
>>
>> That's right; not only are there no plans to implement virtio-mmio/1.0
>> for OVMF (to my knowledge), I'd even argue against such efforts.
>>
>> OVMF is a heavy-weight guest firmware, which I see entirely out of scope
>> for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
>> unwelcome complication, from the OVMF maintainership perspective.
> 
> But given that, why not rip out virtio-mmio completely?

Virtio-mmio used to be necessary because "qemu-system-aarch64 -M virt"
lacked a PCI host originally. (The relevant commit is 4ab29b8214cc,
"arm: Add PCIe host bridge in virt machine", 2015-02-13; part of v2.3.0.)

Indeed I don't expect anyone to use virtio-mmio nowadays, and removing
it would simplify both our home-grown VIRTIO_DEVICE_PROTOCOL, and the
virtio drivers.

But it's extra work, not entirely risk-free (regressions), and I can't
tell if someone out there still uses virtio-mmio (despite me thinking
that would be unreasonable). I wouldn't like to see more work sunk into
it either way :)

Laszlo


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-08-02  0:26     ` Laszlo Ersek
@ 2019-08-02  9:20       ` Peter Maydell
  2019-08-02 22:33         ` Laszlo Ersek
  0 siblings, 1 reply; 27+ messages in thread
From: Peter Maydell @ 2019-08-02  9:20 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Paolo Bonzini, qemu-devel, Sergio Lopez Pascual, Michael S. Tsirkin

On Fri, 2 Aug 2019 at 01:26, Laszlo Ersek <lersek@redhat.com> wrote:
> But it's extra work, not entirely risk-free (regressions), and I can't
> tell if someone out there still uses virtio-mmio (despite me thinking
> that would be unreasonable). I wouldn't like to see more work sunk into
> it either way :)

The main reasons I still see people using virtio-mmio for
the 'virt' board are:
 * still using old but working command lines
 * newer setups that were put together working from older tutorials
   that recommended virtio-mmio because they predated virtio-pci
   support being widespread
 * using older (eg distro) kernels -- for 32-bit kernels in
   particular it was a while before the virtio-pci support
   got built in the default configs I think, and then longer
   again until those got into stable distro releases

I wouldn't be surprised if some of those applied also to
via-OVMF boot setups as well as direct kernel boot. So it
depends a bit what your tolerance for breaking existing
user setups is.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-08-01 19:45     ` Michael S. Tsirkin
@ 2019-08-02  9:24       ` Paolo Bonzini
  0 siblings, 0 replies; 27+ messages in thread
From: Paolo Bonzini @ 2019-08-02  9:24 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Peter Maydell, Laszlo Ersek, qemu-devel, Sergio Lopez Pascual

On 01/08/19 21:45, Michael S. Tsirkin wrote:
>>> OVMF is a heavy-weight guest firmware, which I see entirely out of scope
>>> for "micro VMs". And so virtio-mmio/1.0 would seem like a needless &
>>> unwelcome complication, from the OVMF maintainership perspective.
>> But given that, why not rip out virtio-mmio completely?
>
> From OVMF?

Yes, of course.

Paolo


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1)
  2019-08-02  9:20       ` Peter Maydell
@ 2019-08-02 22:33         ` Laszlo Ersek
  0 siblings, 0 replies; 27+ messages in thread
From: Laszlo Ersek @ 2019-08-02 22:33 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Paolo Bonzini, qemu-devel, Sergio Lopez Pascual, Michael S. Tsirkin

On 08/02/19 11:20, Peter Maydell wrote:
> On Fri, 2 Aug 2019 at 01:26, Laszlo Ersek <lersek@redhat.com> wrote:
>> But it's extra work, not entirely risk-free (regressions), and I can't
>> tell if someone out there still uses virtio-mmio (despite me thinking
>> that would be unreasonable). I wouldn't like to see more work sunk into
>> it either way :)
> 
> The main reasons I still see people using virtio-mmio for
> the 'virt' board are:
>  * still using old but working command lines
>  * newer setups that were put together working from older tutorials
>    that recommended virtio-mmio because they predated virtio-pci
>    support being widespread
>  * using older (eg distro) kernels -- for 32-bit kernels in
>    particular it was a while before the virtio-pci support
>    got built in the default configs I think, and then longer
>    again until those got into stable distro releases

There was one time when edk2 core modules gained a feature for marking
the DXE phase stack non-executable. We happily enabled it in OVMF. Then
people reported that UEFI grub in their old Debian guests had broken --
on their hosts carrying OVMF binaries built from upstream. :) We had to
flip the default off in OVMF, and we've stuck with that ever since...

  https://github.com/tianocore/edk2/commit/d20b06a3afdf

> I wouldn't be surprised if some of those applied also to
> via-OVMF boot setups as well as direct kernel boot. So it
> depends a bit what your tolerance for breaking existing
> user setups is.

Near zero. :)

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2019-08-02 22:34 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-29 12:57 [Qemu-devel] [RFC] virtio-mmio: implement modern (v2) personality (virtio-1) Sergio Lopez
2019-07-29 13:10 ` no-reply
2019-07-30  7:06 ` Stefan Hajnoczi
2019-07-30  8:34 ` Michael S. Tsirkin
2019-07-31 12:22   ` Sergio Lopez
2019-07-31 19:34     ` Michael S. Tsirkin
2019-07-31 21:22     ` Eduardo Habkost
2019-07-30 10:25 ` Andrea Bolognani
2019-07-30 11:35   ` Cornelia Huck
2019-07-30 12:17     ` Andrea Bolognani
2019-07-30 13:14       ` Cornelia Huck
2019-07-30 20:02         ` Michael S. Tsirkin
2019-07-30 20:18         ` Michael S. Tsirkin
2019-07-31 11:04           ` Sergio Lopez
2019-07-31 13:55           ` Cornelia Huck
2019-07-31 19:06             ` Michael S. Tsirkin
2019-08-01  8:18               ` Cornelia Huck
2019-07-31 11:02   ` Sergio Lopez
2019-08-01 12:17     ` Michael S. Tsirkin
2019-07-30 16:06 ` Laszlo Ersek
2019-07-31 23:58   ` Paolo Bonzini
2019-08-01 19:45     ` Michael S. Tsirkin
2019-08-02  9:24       ` Paolo Bonzini
2019-08-02  0:26     ` Laszlo Ersek
2019-08-02  9:20       ` Peter Maydell
2019-08-02 22:33         ` Laszlo Ersek
2019-08-01  8:37   ` Sergio Lopez

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.