qemu-devel
[Top][All Lists]
Advanced

[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,




reply via email to

[Prev in Thread] Current Thread [Next in Thread]