From: Greg Kurz <gkurz@linux.vnet.ibm.com>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Juan Quintela" <quintela@redhat.com>,
"Rusty Russell" <rusty@rustcorp.com.au>,
"Alexander Graf" <agraf@suse.de>,
"Michael S. Tsirkin" <mst@redhat.com>,
aneesh.kumar@linux.vnet.ibm.com,
"Anthony Liguori" <aliguori@amazon.com>,
"Amit Shah" <amit.shah@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: [Qemu-devel] [PATCH v8 11/20] virtio: add endian-ambivalent support to VirtIODevice
Date: Fri, 13 Jun 2014 13:23:16 +0200 [thread overview]
Message-ID: <20140613112226.22108.50811.stgit@bahia.local> (raw)
In-Reply-To: <20140613111703.22108.14322.stgit@bahia.local>
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>
---
Changes since last version (virtio migration RFC):
- endianness cached at device reset time
- reworked migration support
hw/virtio/virtio-pci.c | 8 ++--
hw/virtio/virtio.c | 100 +++++++++++++++++++++++++++++++++++++++-----
include/hw/virtio/virtio.h | 12 ++++-
3 files changed, 102 insertions(+), 18 deletions(-)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 390c8d2..2ffceb8 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 16b73d9..6235df8 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -545,6 +545,24 @@ void virtio_set_status(VirtIODevice *vdev, uint8_t val)
vdev->status = val;
}
+static void virtio_set_endian_target_default(VirtIODevice *vdev)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ vdev->device_endian = VIRTIO_DEVICE_ENDIAN_BIG;
+#else
+ vdev->device_endian = VIRTIO_DEVICE_ENDIAN_LITTLE;
+#endif
+}
+
+static void virtio_set_endian_cpu(VirtIODevice *vdev, CPUState *cpu)
+{
+ if (cpu_virtio_is_big_endian(cpu)) {
+ vdev->device_endian = VIRTIO_DEVICE_ENDIAN_BIG;
+ } else {
+ vdev->device_endian = VIRTIO_DEVICE_ENDIAN_LITTLE;
+ }
+}
+
void virtio_reset(void *opaque)
{
VirtIODevice *vdev = opaque;
@@ -552,6 +570,13 @@ void virtio_reset(void *opaque)
int i;
virtio_set_status(vdev, 0);
+ if (current_cpu) {
+ /* Guest initiated reset */
+ virtio_set_endian_cpu(vdev, current_cpu);
+ } else {
+ /* System reset */
+ virtio_set_endian_target_default(vdev);
+ }
if (k->reset) {
k->reset(vdev);
@@ -840,6 +865,28 @@ 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);
+#ifdef TARGET_WORDS_BIGENDIAN
+ return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE;
+#else
+ return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
+#endif
+}
+
+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 +894,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 +979,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)
@@ -971,18 +1031,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",
@@ -1005,7 +1054,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) {
+ virtio_set_endian_target_default(vdev);
+ }
+
+ 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)
@@ -1062,6 +1137,7 @@ void virtio_init(VirtIODevice *vdev, const char *name,
}
vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
vdev);
+ virtio_set_endian_target_default(vdev);
}
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index daf0bb2..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,8 +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);
-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
next prev parent reply other threads:[~2014-06-13 11:23 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-13 11:18 [Qemu-devel] [PATCH v8 00/20] virtio endian-ambivalent target Greg Kurz
2014-06-13 11:18 ` [Qemu-devel] [PATCH v8 01/20] virtio-serial: don't migrate the config space Greg Kurz
2014-06-13 11:33 ` Alexander Graf
2014-06-19 10:40 ` Amit Shah
2014-06-19 11:17 ` Greg Kurz
2014-06-19 11:32 ` Michael S. Tsirkin
2014-06-13 11:19 ` [Qemu-devel] [PATCH v8 02/20] virtio: introduce device specific migration calls Greg Kurz
2014-06-13 11:19 ` [Qemu-devel] [PATCH v8 03/20] virtio-net: implement per-device " Greg Kurz
2014-06-13 11:19 ` [Qemu-devel] [PATCH v8 04/20] virtio-blk: " Greg Kurz
2014-06-13 11:20 ` [Qemu-devel] [PATCH v8 05/20] virtio-serial: " Greg Kurz
2014-06-13 11:20 ` [Qemu-devel] [PATCH v8 06/20] virtio-balloon: " Greg Kurz
2014-06-13 11:21 ` [Qemu-devel] [PATCH v8 07/20] virtio-rng: " Greg Kurz
2014-06-13 11:21 ` [Qemu-devel] [PATCH v8 08/20] virtio: add subsections to the migration stream Greg Kurz
2014-06-13 11:21 ` [Qemu-devel] [PATCH v8 09/20] exec: introduce target_words_bigendian() helper Greg Kurz
2014-06-13 11:41 ` Alexander Graf
2014-06-13 12:05 ` Greg Kurz
2014-06-13 11:22 ` [Qemu-devel] [PATCH v8 10/20] cpu: introduce CPUClass::virtio_is_big_endian() Greg Kurz
2014-06-13 11:42 ` Alexander Graf
2014-06-13 12:08 ` Greg Kurz
2014-06-13 11:23 ` Greg Kurz [this message]
2014-06-13 11:46 ` [Qemu-devel] [PATCH v8 11/20] virtio: add endian-ambivalent support to VirtIODevice Alexander Graf
2014-06-13 12:14 ` Greg Kurz
2014-06-13 12:41 ` Alexander Graf
2014-06-13 12:52 ` Greg Kurz
2014-06-13 11:23 ` [Qemu-devel] [PATCH v8 12/20] virtio: memory accessors for endian-ambivalent targets Greg Kurz
2014-06-13 11:24 ` [Qemu-devel] [PATCH v8 13/20] virtio: allow byte swapping for vring Greg Kurz
2014-06-13 11:24 ` [Qemu-devel] [PATCH v8 14/20] virtio-net: use virtio wrappers to access headers Greg Kurz
2014-06-13 11:52 ` Alexander Graf
2014-06-13 12:24 ` Cedric Le Goater
2014-06-13 12:40 ` Greg Kurz
2014-06-13 11:24 ` [Qemu-devel] [PATCH v8 15/20] virtio-balloon: use virtio wrappers to access page frame numbers Greg Kurz
2014-06-13 11:24 ` [Qemu-devel] [PATCH v8 16/20] virtio-blk: use virtio wrappers to access headers Greg Kurz
2014-06-13 11:24 ` [Qemu-devel] [PATCH v8 17/20] virtio-scsi: " Greg Kurz
2014-06-19 15:05 ` Greg Kurz
2014-06-20 8:24 ` Paolo Bonzini
2014-06-20 8:33 ` Greg Kurz
2014-06-13 11:25 ` [Qemu-devel] [PATCH v8 18/20] virtio-serial-bus: " Greg Kurz
2014-06-13 11:25 ` [Qemu-devel] [PATCH v8 19/20] virtio-9p: " Greg Kurz
2014-06-13 11:26 ` [Qemu-devel] [PATCH v8 20/20] target-ppc: enable virtio endian ambivalent support Greg Kurz
2014-06-13 11:56 ` [Qemu-devel] [PATCH v8 00/20] virtio endian-ambivalent target Alexander Graf
2014-06-16 15:07 ` Greg Kurz
2014-06-16 16:53 ` Amit Shah
2014-06-17 7:36 ` Stefan Hajnoczi
2014-06-17 7:40 ` Alexander Graf
2014-06-18 10:38 ` Stefan Hajnoczi
2014-06-18 12:35 ` Greg Kurz
2014-06-18 15:12 ` Michael S. Tsirkin
2014-06-18 15:14 ` Alexander Graf
2014-06-18 15:26 ` Michael S. Tsirkin
2014-06-19 9:51 ` Stefan Hajnoczi
2014-06-18 12:53 ` Peter Maydell
2014-06-18 13:42 ` Michael S. Tsirkin
2014-06-18 14:28 ` Greg Kurz
2014-06-18 15:05 ` Michael S. Tsirkin
2014-06-18 15:35 ` Peter Maydell
2014-06-18 15:37 ` Alexander Graf
2014-06-18 15:40 ` Peter Maydell
2014-06-18 15:41 ` Alexander Graf
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=20140613112226.22108.50811.stgit@bahia.local \
--to=gkurz@linux.vnet.ibm.com \
--cc=afaerber@suse.de \
--cc=agraf@suse.de \
--cc=aliguori@amazon.com \
--cc=amit.shah@redhat.com \
--cc=aneesh.kumar@linux.vnet.ibm.com \
--cc=kwolf@redhat.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=rusty@rustcorp.com.au \
--cc=stefanha@redhat.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).