[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v9 12/22] virtio: add endian-ambivalent support to V
From: |
Greg Kurz |
Subject: |
[Qemu-devel] [PATCH v9 12/22] virtio: add endian-ambivalent support to VirtIODevice |
Date: |
Tue, 24 Jun 2014 19:38:54 +0200 |
User-agent: |
StGit/0.17-dirty |
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 <address@hidden>
---
Changes since v8:
- introduced a new virtio_current_cpu_endian() helper
- reworked the code according to Alexander Graf suggestions, for better
clarity.
hw/virtio/virtio-pci.c | 8 ++--
hw/virtio/virtio.c | 99 +++++++++++++++++++++++++++++++++++++++-----
include/hw/virtio/virtio.h | 13 ++++--
3 files changed, 101 insertions(+), 19 deletions(-)
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 972f120..aae8c60 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)
@@ -971,18 +1030,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 +1053,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)
@@ -1062,6 +1136,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)
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
- [Qemu-devel] [PATCH v9 03/22] virtio: introduce device specific migration calls, (continued)
- [Qemu-devel] [PATCH v9 03/22] virtio: introduce device specific migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 04/22] virtio-net: implement per-device migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 05/22] virtio-blk: implement per-device migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 06/22] virtio-serial: implement per-device migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 07/22] virtio-balloon: implement per-device migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 08/22] virtio-rng: implement per-device migration calls, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 09/22] virtio: add subsections to the migration stream, Greg Kurz, 2014/06/24
- Re: [Qemu-devel] [PATCH v9 00/22] legacy virtio support for cross-endian targets, Michael S. Tsirkin, 2014/06/24
- [Qemu-devel] [PATCH v9 10/22] exec: introduce target_words_bigendian() helper, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 11/22] cpu: introduce CPUClass::virtio_is_big_endian(), Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 12/22] virtio: add endian-ambivalent support to VirtIODevice,
Greg Kurz <=
- [Qemu-devel] [PATCH v9 13/22] virtio: memory accessors for endian-ambivalent targets, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 14/22] virtio: allow byte swapping for vring, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 15/22] virtio-net: use virtio wrappers to access headers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 16/22] virtio-balloon: use virtio wrappers to access page frame numbers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 17/22] virtio-blk: use virtio wrappers to access headers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 18/22] virtio-scsi: use virtio wrappers to access headers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 19/22] virtio-serial-bus: use virtio wrappers to access headers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 20/22] virtio-9p: use virtio wrappers to access headers, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 21/22] target-ppc: enable virtio endian ambivalent support, Greg Kurz, 2014/06/24
- [Qemu-devel] [PATCH v9 22/22] vhost-net: disable when cross-endian, Greg Kurz, 2014/06/24