[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 3/3] vhost: set vring endianness for legacy virti
From: |
Greg Kurz |
Subject: |
[Qemu-devel] [PATCH v2 3/3] vhost: set vring endianness for legacy virtio |
Date: |
Thu, 02 Apr 2015 16:04:12 +0200 |
User-agent: |
StGit/0.17-dirty |
Legacy virtio is native endian: if the guest and host endianness differ,
we have to tell vhost so it can swap bytes where appropriate. This is
done through a vhost ring ioctl.
The support for this ioctl is advertised by a vhost feature. QEMU may
choose to use it if a cross-endian situation is detected. Of course,
virtio 1.0 doesn't need this and will never ack the feature back to
vhost.
Signed-off-by: Greg Kurz <address@hidden>
---
hw/virtio/vhost.c | 46 +++++++++++++++++++++++++++++++++++----------
include/hw/virtio/vhost.h | 1 +
2 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 771abae..db52898 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -548,13 +548,18 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
return 0;
}
-static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
+static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log,
+ bool enable_cross_endian)
{
uint64_t features = dev->acked_features;
int r;
if (enable_log) {
features |= 0x1ULL << VHOST_F_LOG_ALL;
}
+ if (!enable_cross_endian) {
+ features &= ~(1ULL << VHOST_F_SET_ENDIAN_LEGACY);
+ }
+
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features);
return r < 0 ? -errno : 0;
}
@@ -562,7 +567,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev,
bool enable_log)
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
{
int r, t, i;
- r = vhost_dev_set_features(dev, enable_log);
+ r = vhost_dev_set_features(dev, enable_log, dev->cross_endian_enabled);
if (r < 0) {
goto err_features;
}
@@ -580,7 +585,7 @@ err_vq:
dev->log_enabled);
assert(t >= 0);
}
- t = vhost_dev_set_features(dev, dev->log_enabled);
+ t = vhost_dev_set_features(dev, dev->log_enabled,
dev->cross_endian_enabled);
assert(t >= 0);
err_features:
return r;
@@ -650,9 +655,9 @@ static void vhost_log_stop(MemoryListener *listener,
}
static int vhost_virtqueue_start(struct vhost_dev *dev,
- struct VirtIODevice *vdev,
- struct vhost_virtqueue *vq,
- unsigned idx)
+ struct VirtIODevice *vdev,
+ struct vhost_virtqueue *vq,
+ unsigned idx)
{
hwaddr s, l, a;
int r;
@@ -663,6 +668,9 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
struct vhost_vring_state state = {
.index = vhost_vq_index
};
+ struct vhost_vring_endian endian = {
+ .index = vhost_vq_index
+ };
struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
@@ -679,6 +687,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
return -errno;
}
+ if (dev->cross_endian_enabled) {
+ endian.is_big_endian = virtio_is_big_endian(vdev);
+ r = dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN_LEGACY,
+ &endian);
+ if (r) {
+ return -errno;
+ }
+ }
+
s = l = virtio_queue_get_desc_size(vdev, idx);
a = virtio_queue_get_desc_addr(vdev, idx);
vq->desc = cpu_physical_memory_map(a, &l, 0);
@@ -877,6 +894,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
hdev->memory_changed = false;
memory_listener_register(&hdev->memory_listener, &address_space_memory);
hdev->force = force;
+ hdev->cross_endian_enabled = false;
return 0;
fail_vq:
while (--i >= 0) {
@@ -1046,14 +1064,22 @@ int vhost_dev_start(struct vhost_dev *hdev,
VirtIODevice *vdev)
{
int i, r;
- if (virtio_legacy_is_cross_endian(vdev)) {
- error_report("vhost does not support cross-endian");
- return -ENOSYS;
+ if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+ virtio_legacy_is_cross_endian(vdev)) {
+ if (hdev->features & (1ULL << VHOST_F_SET_ENDIAN_LEGACY)) {
+ hdev->cross_endian_enabled = true;
+ } else {
+ error_report("vhost does not support cross-endian");
+ return -ENOSYS;
+ }
+ } else {
+ hdev->cross_endian_enabled = false;
}
hdev->started = true;
- r = vhost_dev_set_features(hdev, hdev->log_enabled);
+ r = vhost_dev_set_features(hdev, hdev->log_enabled,
+ hdev->cross_endian_enabled);
if (r < 0) {
goto fail_features;
}
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 88e1e56..61569bf 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -52,6 +52,7 @@ struct vhost_dev {
hwaddr mem_changed_end_addr;
const VhostOps *vhost_ops;
void *opaque;
+ bool cross_endian_enabled;
};
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,