All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	=?UTF-8?q?Andreas=20F=C3=A4rber?= <afaerber@suse.de>,
	"Anthony Liguori" <aliguori@amazon.com>,
	"Greg Kurz" <gkurz@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PULL 26/37] virtio: add endian-ambivalent support to VirtIODevice
Date: Sun, 29 Jun 2014 19:59:35 +0300	[thread overview]
Message-ID: <1404060115-27410-27-git-send-email-mst@redhat.com> (raw)
In-Reply-To: <1404060115-27410-1-git-send-email-mst@redhat.com>

From: Greg Kurz <gkurz@linux.vnet.ibm.com>

Some CPU families can dynamically change their endianness. This means we
can have little endian ppc or big endian arm guests for example. This has
an impact on legacy virtio data structures since they are target endian.
We hence introduce a new property to track the endianness of each virtio
device. It is reasonnably assumed that endianness won't change while the
device is in use : we hence capture the device endianness when it gets
reset.

We migrate this property in a subsection, after the device descriptor. This
means the load code must not rely on it until it is restored. As a consequence,
the vring sanity checks had to be moved after the call to vmstate_load_state().
We enforce paranoia by poisoning the property at the begining of virtio_load().

Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 include/hw/virtio/virtio.h | 13 ++++--
 hw/virtio/virtio-pci.c     |  8 ++--
 hw/virtio/virtio.c         | 99 ++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 101 insertions(+), 19 deletions(-)

diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 9000ee2..a60104c 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -104,6 +104,12 @@ typedef struct VirtQueueElement
 #define VIRTIO_DEVICE(obj) \
         OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE)
 
+enum virtio_device_endian {
+    VIRTIO_DEVICE_ENDIAN_UNKNOWN,
+    VIRTIO_DEVICE_ENDIAN_LITTLE,
+    VIRTIO_DEVICE_ENDIAN_BIG,
+};
+
 struct VirtIODevice
 {
     DeviceState parent_obj;
@@ -121,6 +127,7 @@ struct VirtIODevice
     bool vm_running;
     VMChangeStateEntry *vmstate;
     char *bus_name;
+    uint8_t device_endian;
 };
 
 typedef struct VirtioDeviceClass {
@@ -256,9 +263,9 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
 void virtio_queue_notify_vq(VirtQueue *vq);
 void virtio_irq(VirtQueue *vq);
 
-bool target_words_bigendian(void);
-static inline bool virtio_is_big_endian(void)
+static inline bool virtio_is_big_endian(VirtIODevice *vdev)
 {
-    return target_words_bigendian();
+    assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
+    return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
 }
 #endif
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index e11f759..317324f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -406,13 +406,13 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
         break;
     case 2:
         val = virtio_config_readw(vdev, addr);
-        if (virtio_is_big_endian()) {
+        if (virtio_is_big_endian(vdev)) {
             val = bswap16(val);
         }
         break;
     case 4:
         val = virtio_config_readl(vdev, addr);
-        if (virtio_is_big_endian()) {
+        if (virtio_is_big_endian(vdev)) {
             val = bswap32(val);
         }
         break;
@@ -440,13 +440,13 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr,
         virtio_config_writeb(vdev, addr, val);
         break;
     case 2:
-        if (virtio_is_big_endian()) {
+        if (virtio_is_big_endian(vdev)) {
             val = bswap16(val);
         }
         virtio_config_writew(vdev, addr, val);
         break;
     case 4:
-        if (virtio_is_big_endian()) {
+        if (virtio_is_big_endian(vdev)) {
             val = bswap32(val);
         }
         virtio_config_writel(vdev, addr, val);
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7b317ce..a0676e0 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -545,6 +545,27 @@ void virtio_set_status(VirtIODevice *vdev, uint8_t val)
     vdev->status = val;
 }
 
+bool target_words_bigendian(void);
+static enum virtio_device_endian virtio_default_endian(void)
+{
+    if (target_words_bigendian()) {
+        return VIRTIO_DEVICE_ENDIAN_BIG;
+    } else {
+        return VIRTIO_DEVICE_ENDIAN_LITTLE;
+    }
+}
+
+static enum virtio_device_endian virtio_current_cpu_endian(void)
+{
+    CPUClass *cc = CPU_GET_CLASS(current_cpu);
+
+    if (cc->virtio_is_big_endian(current_cpu)) {
+        return VIRTIO_DEVICE_ENDIAN_BIG;
+    } else {
+        return VIRTIO_DEVICE_ENDIAN_LITTLE;
+    }
+}
+
 void virtio_reset(void *opaque)
 {
     VirtIODevice *vdev = opaque;
@@ -552,6 +573,13 @@ void virtio_reset(void *opaque)
     int i;
 
     virtio_set_status(vdev, 0);
+    if (current_cpu) {
+        /* Guest initiated reset */
+        vdev->device_endian = virtio_current_cpu_endian();
+    } else {
+        /* System reset */
+        vdev->device_endian = virtio_default_endian();
+    }
 
     if (k->reset) {
         k->reset(vdev);
@@ -840,6 +868,24 @@ void virtio_notify_config(VirtIODevice *vdev)
     virtio_notify_vector(vdev, vdev->config_vector);
 }
 
+static bool virtio_device_endian_needed(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+
+    assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
+    return vdev->device_endian != virtio_default_endian();
+}
+
+static const VMStateDescription vmstate_virtio_device_endian = {
+    .name = "virtio/device_endian",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(device_endian, VirtIODevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_virtio = {
     .name = "virtio",
     .version_id = 1,
@@ -847,6 +893,13 @@ static const VMStateDescription vmstate_virtio = {
     .minimum_version_id_old = 1,
     .fields = (VMStateField[]) {
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_virtio_device_endian,
+            .needed = &virtio_device_endian_needed
+        },
+        { 0 }
     }
 };
 
@@ -925,6 +978,12 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
 
+    /*
+     * We poison the endianness to ensure it does not get used before
+     * subsections have been loaded.
+     */
+    vdev->device_endian = VIRTIO_DEVICE_ENDIAN_UNKNOWN;
+
     if (k->load_config) {
         ret = k->load_config(qbus->parent, f);
         if (ret)
@@ -977,18 +1036,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
         vdev->vq[i].notification = true;
 
         if (vdev->vq[i].pa) {
-            uint16_t nheads;
             virtqueue_init(&vdev->vq[i]);
-            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
-            /* Check it isn't doing very strange things with descriptor numbers. */
-            if (nheads > vdev->vq[i].vring.num) {
-                error_report("VQ %d size 0x%x Guest index 0x%x "
-                             "inconsistent with Host index 0x%x: delta 0x%x",
-                             i, vdev->vq[i].vring.num,
-                             vring_avail_idx(&vdev->vq[i]),
-                             vdev->vq[i].last_avail_idx, nheads);
-                return -1;
-            }
         } else if (vdev->vq[i].last_avail_idx) {
             error_report("VQ %d address 0x0 "
                          "inconsistent with Host index 0x%x",
@@ -1011,7 +1059,33 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
         }
     }
 
-    return vmstate_load_state(f, &vmstate_virtio, vdev, 1);
+    /* Subsections */
+    ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1);
+    if (ret) {
+        return ret;
+    }
+
+    if (vdev->device_endian == VIRTIO_DEVICE_ENDIAN_UNKNOWN) {
+        vdev->device_endian = virtio_default_endian();
+    }
+
+    for (i = 0; i < num; i++) {
+        if (vdev->vq[i].pa) {
+            uint16_t nheads;
+            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+            /* Check it isn't doing strange things with descriptor numbers. */
+            if (nheads > vdev->vq[i].vring.num) {
+                error_report("VQ %d size 0x%x Guest index 0x%x "
+                             "inconsistent with Host index 0x%x: delta 0x%x",
+                             i, vdev->vq[i].vring.num,
+                             vring_avail_idx(&vdev->vq[i]),
+                             vdev->vq[i].last_avail_idx, nheads);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
 }
 
 void virtio_cleanup(VirtIODevice *vdev)
@@ -1068,6 +1142,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
     }
     vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
                                                      vdev);
+    vdev->device_endian = virtio_default_endian();
 }
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
-- 
MST

  parent reply	other threads:[~2014-06-29 16:59 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-29 16:58 [Qemu-devel] [PULL 00/37] pc,vhost,virtio fixes, enhancements Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 01/37] numa: fix comment Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 02/37] openrisc: " Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 03/37] numa: " Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 04/37] pc: Move q35 compat props to PC_COMPAT_* Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 05/37] pc: Fix "prog_if" typo on PC_COMPAT_2_0 Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 06/37] mc146818rtc: add rtc-reset-reinjection QMP command Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 07/37] vhost-user: fix wrong ids in documentation Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 08/37] pc: make isapc and pc-0.10 to pc-0.13 have 1.7.0 memory layout Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 09/37] Allow mismatched virtio config-len Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 10/37] numa: Keep track of NUMA nodes present on the command-line Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 11/37] numa: Reject duplicate node IDs Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 12/37] numa: Reject configuration if not all node IDs are present Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 13/37] vhost-user: fix regions provied with VHOST_USER_SET_MEM_TABLE message Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 14/37] vhost-user: typo fixups Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 15/37] virtio-net: byteswap virtio-net header Michael S. Tsirkin
2014-06-29 16:58 ` [Qemu-devel] [PULL 16/37] virtio-serial: don't migrate the config space Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 17/37] virtio: introduce device specific migration calls Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 18/37] virtio-net: implement per-device " Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 19/37] virtio-blk: " Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 20/37] virtio-serial: " Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 21/37] virtio-balloon: " Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 22/37] virtio-rng: " Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 23/37] virtio: add subsections to the migration stream Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 24/37] exec: introduce target_words_bigendian() helper Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 25/37] cpu: introduce CPUClass::virtio_is_big_endian() Michael S. Tsirkin
2014-06-29 16:59 ` Michael S. Tsirkin [this message]
2014-06-29 16:59 ` [Qemu-devel] [PULL 27/37] virtio: memory accessors for endian-ambivalent targets Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 28/37] virtio: allow byte swapping for vring Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 29/37] virtio-net: use virtio wrappers to access headers Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 30/37] virtio-balloon: use virtio wrappers to access page frame numbers Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 31/37] virtio-blk: use virtio wrappers to access headers Michael S. Tsirkin
2014-06-29 16:59 ` [Qemu-devel] [PULL 32/37] virtio-scsi: " Michael S. Tsirkin
2014-06-29 17:00 ` [Qemu-devel] [PULL 33/37] virtio-serial-bus: " Michael S. Tsirkin
2014-06-29 17:00 ` [Qemu-devel] [PULL 34/37] virtio-9p: " Michael S. Tsirkin
2014-06-29 17:00 ` [Qemu-devel] [PULL 35/37] target-ppc: enable virtio endian ambivalent support Michael S. Tsirkin
2014-06-29 17:00 ` [Qemu-devel] [PULL 36/37] vhost-net: disable when cross-endian Michael S. Tsirkin
2014-06-29 17:00 ` [Qemu-devel] [PULL 37/37] tests: add human format test for string output visitor Michael S. Tsirkin
2014-07-09 19:14   ` Andreas Färber
2014-07-09 19:34     ` Peter Maydell
2014-06-29 17:36 ` [Qemu-devel] [PULL 00/37] pc,vhost,virtio fixes, enhancements Peter Maydell
2014-06-29 20:34   ` Michael S. Tsirkin
2014-06-29 20:41     ` Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1404060115-27410-27-git-send-email-mst@redhat.com \
    --to=mst@redhat.com \
    --cc=afaerber@suse.de \
    --cc=aliguori@amazon.com \
    --cc=gkurz@linux.vnet.ibm.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.