yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-libvhost-user-handle-endianness-as-mandated-by-the-s.patch

8fced6
From cadb72854b44f53c07ea60d7a6149ccac5928a82 Mon Sep 17 00:00:00 2001
8fced6
From: Claudio Imbrenda <cimbrend@redhat.com>
8fced6
Date: Tue, 27 Oct 2020 12:02:15 -0400
8fced6
Subject: [PATCH 02/18] libvhost-user: handle endianness as mandated by the
8fced6
 spec
8fced6
8fced6
RH-Author: Claudio Imbrenda <cimbrend@redhat.com>
8fced6
Message-id: <20201027120217.2997314-2-cimbrend@redhat.com>
8fced6
Patchwork-id: 98723
8fced6
O-Subject: [RHEL8.4 qemu-kvm PATCH 1/3] libvhost-user: handle endianness as mandated by the spec
8fced6
Bugzilla: 1857733
8fced6
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
8fced6
RH-Acked-by: Thomas Huth <thuth@redhat.com>
8fced6
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
8fced6
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
8fced6
8fced6
From: Marc Hartmayer <mhartmay@linux.ibm.com>
8fced6
8fced6
Since virtio existed even before it got standardized, the virtio
8fced6
standard defines the following types of virtio devices:
8fced6
8fced6
 + legacy device (pre-virtio 1.0)
8fced6
 + non-legacy or VIRTIO 1.0 device
8fced6
 + transitional device (which can act both as legacy and non-legacy)
8fced6
8fced6
Virtio 1.0 defines the fields of the virtqueues as little endian,
8fced6
while legacy uses guest's native endian [1]. Currently libvhost-user
8fced6
does not handle virtio endianness at all, i.e. it works only if the
8fced6
native endianness matches with whatever is actually needed. That means
8fced6
things break spectacularly on big-endian targets. Let us handle virtio
8fced6
endianness for non-legacy as required by the virtio specification [1]
8fced6
and fence legacy virtio, as there is no safe way to figure out the
8fced6
needed endianness conversions for all cases. The fencing of legacy
8fced6
virtio devices is done in `vu_set_features_exec`.
8fced6
8fced6
[1] https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-210003
8fced6
8fced6
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8fced6
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
8fced6
Message-id: 20200901150019.29229-3-mhartmay@linux.ibm.com
8fced6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8fced6
(cherry picked from commit 2ffc54708087c6e524297957be2fc5d543abb767)
8fced6
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
8fced6
---
8fced6
 contrib/libvhost-user/libvhost-user.c | 77 +++++++++++++++------------
8fced6
 1 file changed, 43 insertions(+), 34 deletions(-)
8fced6
8fced6
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
8fced6
index b89bf185013..b8350b067e3 100644
8fced6
--- a/contrib/libvhost-user/libvhost-user.c
8fced6
+++ b/contrib/libvhost-user/libvhost-user.c
8fced6
@@ -42,6 +42,7 @@
8fced6
 
8fced6
 #include "qemu/atomic.h"
8fced6
 #include "qemu/osdep.h"
8fced6
+#include "qemu/bswap.h"
8fced6
 #include "qemu/memfd.h"
8fced6
 
8fced6
 #include "libvhost-user.h"
8fced6
@@ -522,6 +523,14 @@ vu_set_features_exec(VuDev *dev, VhostUserMsg *vmsg)
8fced6
     DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64);
8fced6
 
8fced6
     dev->features = vmsg->payload.u64;
8fced6
+    if (!vu_has_feature(dev, VIRTIO_F_VERSION_1)) {
8fced6
+        /*
8fced6
+         * We only support devices conforming to VIRTIO 1.0 or
8fced6
+         * later
8fced6
+         */
8fced6
+        vu_panic(dev, "virtio legacy devices aren't supported by libvhost-user");
8fced6
+        return false;
8fced6
+    }
8fced6
 
8fced6
     if (!(dev->features & VHOST_USER_F_PROTOCOL_FEATURES)) {
8fced6
         vu_set_enable_all_rings(dev, true);
8fced6
@@ -886,7 +895,7 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg)
8fced6
         return false;
8fced6
     }
8fced6
 
8fced6
-    vq->used_idx = vq->vring.used->idx;
8fced6
+    vq->used_idx = lduw_le_p(&vq->vring.used->idx);
8fced6
 
8fced6
     if (vq->last_avail_idx != vq->used_idx) {
8fced6
         bool resume = dev->iface->queue_is_processed_in_order &&
8fced6
@@ -998,7 +1007,7 @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq)
8fced6
         return 0;
8fced6
     }
8fced6
 
8fced6
-    vq->used_idx = vq->vring.used->idx;
8fced6
+    vq->used_idx = lduw_le_p(&vq->vring.used->idx);
8fced6
     vq->resubmit_num = 0;
8fced6
     vq->resubmit_list = NULL;
8fced6
     vq->counter = 0;
8fced6
@@ -1737,13 +1746,13 @@ vu_queue_started(const VuDev *dev, const VuVirtq *vq)
8fced6
 static inline uint16_t
8fced6
 vring_avail_flags(VuVirtq *vq)
8fced6
 {
8fced6
-    return vq->vring.avail->flags;
8fced6
+    return lduw_le_p(&vq->vring.avail->flags);
8fced6
 }
8fced6
 
8fced6
 static inline uint16_t
8fced6
 vring_avail_idx(VuVirtq *vq)
8fced6
 {
8fced6
-    vq->shadow_avail_idx = vq->vring.avail->idx;
8fced6
+    vq->shadow_avail_idx = lduw_le_p(&vq->vring.avail->idx);
8fced6
 
8fced6
     return vq->shadow_avail_idx;
8fced6
 }
8fced6
@@ -1751,7 +1760,7 @@ vring_avail_idx(VuVirtq *vq)
8fced6
 static inline uint16_t
8fced6
 vring_avail_ring(VuVirtq *vq, int i)
8fced6
 {
8fced6
-    return vq->vring.avail->ring[i];
8fced6
+    return lduw_le_p(&vq->vring.avail->ring[i]);
8fced6
 }
8fced6
 
8fced6
 static inline uint16_t
8fced6
@@ -1839,12 +1848,12 @@ virtqueue_read_next_desc(VuDev *dev, struct vring_desc *desc,
8fced6
                          int i, unsigned int max, unsigned int *next)
8fced6
 {
8fced6
     /* If this descriptor says it doesn't chain, we're done. */
8fced6
-    if (!(desc[i].flags & VRING_DESC_F_NEXT)) {
8fced6
+    if (!(lduw_le_p(&desc[i].flags) & VRING_DESC_F_NEXT)) {
8fced6
         return VIRTQUEUE_READ_DESC_DONE;
8fced6
     }
8fced6
 
8fced6
     /* Check they're not leading us off end of descriptors. */
8fced6
-    *next = desc[i].next;
8fced6
+    *next = lduw_le_p(&desc[i].next);
8fced6
     /* Make sure compiler knows to grab that: we don't want it changing! */
8fced6
     smp_wmb();
8fced6
 
8fced6
@@ -1887,8 +1896,8 @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes,
8fced6
         }
8fced6
         desc = vq->vring.desc;
8fced6
 
8fced6
-        if (desc[i].flags & VRING_DESC_F_INDIRECT) {
8fced6
-            if (desc[i].len % sizeof(struct vring_desc)) {
8fced6
+        if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) {
8fced6
+            if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) {
8fced6
                 vu_panic(dev, "Invalid size for indirect buffer table");
8fced6
                 goto err;
8fced6
             }
8fced6
@@ -1901,8 +1910,8 @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes,
8fced6
 
8fced6
             /* loop over the indirect descriptor table */
8fced6
             indirect = 1;
8fced6
-            desc_addr = desc[i].addr;
8fced6
-            desc_len = desc[i].len;
8fced6
+            desc_addr = ldq_le_p(&desc[i].addr);
8fced6
+            desc_len = ldl_le_p(&desc[i].len);
8fced6
             max = desc_len / sizeof(struct vring_desc);
8fced6
             read_len = desc_len;
8fced6
             desc = vu_gpa_to_va(dev, &read_len, desc_addr);
8fced6
@@ -1929,10 +1938,10 @@ vu_queue_get_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int *in_bytes,
8fced6
                 goto err;
8fced6
             }
8fced6
 
8fced6
-            if (desc[i].flags & VRING_DESC_F_WRITE) {
8fced6
-                in_total += desc[i].len;
8fced6
+            if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) {
8fced6
+                in_total += ldl_le_p(&desc[i].len);
8fced6
             } else {
8fced6
-                out_total += desc[i].len;
8fced6
+                out_total += ldl_le_p(&desc[i].len);
8fced6
             }
8fced6
             if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
8fced6
                 goto done;
8fced6
@@ -2047,7 +2056,7 @@ vring_used_flags_set_bit(VuVirtq *vq, int mask)
8fced6
 
8fced6
     flags = (uint16_t *)((char*)vq->vring.used +
8fced6
                          offsetof(struct vring_used, flags));
8fced6
-    *flags |= mask;
8fced6
+    stw_le_p(flags, lduw_le_p(flags) | mask);
8fced6
 }
8fced6
 
8fced6
 static inline void
8fced6
@@ -2057,7 +2066,7 @@ vring_used_flags_unset_bit(VuVirtq *vq, int mask)
8fced6
 
8fced6
     flags = (uint16_t *)((char*)vq->vring.used +
8fced6
                          offsetof(struct vring_used, flags));
8fced6
-    *flags &= ~mask;
8fced6
+    stw_le_p(flags, lduw_le_p(flags) & ~mask);
8fced6
 }
8fced6
 
8fced6
 static inline void
8fced6
@@ -2067,7 +2076,7 @@ vring_set_avail_event(VuVirtq *vq, uint16_t val)
8fced6
         return;
8fced6
     }
8fced6
 
8fced6
-    *((uint16_t *) &vq->vring.used->ring[vq->vring.num]) = val;
8fced6
+    stw_le_p(&vq->vring.used->ring[vq->vring.num], val);
8fced6
 }
8fced6
 
8fced6
 void
8fced6
@@ -2156,14 +2165,14 @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz)
8fced6
     struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE];
8fced6
     int rc;
8fced6
 
8fced6
-    if (desc[i].flags & VRING_DESC_F_INDIRECT) {
8fced6
-        if (desc[i].len % sizeof(struct vring_desc)) {
8fced6
+    if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) {
8fced6
+        if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) {
8fced6
             vu_panic(dev, "Invalid size for indirect buffer table");
8fced6
         }
8fced6
 
8fced6
         /* loop over the indirect descriptor table */
8fced6
-        desc_addr = desc[i].addr;
8fced6
-        desc_len = desc[i].len;
8fced6
+        desc_addr = ldq_le_p(&desc[i].addr);
8fced6
+        desc_len = ldl_le_p(&desc[i].len);
8fced6
         max = desc_len / sizeof(struct vring_desc);
8fced6
         read_len = desc_len;
8fced6
         desc = vu_gpa_to_va(dev, &read_len, desc_addr);
8fced6
@@ -2185,10 +2194,10 @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz)
8fced6
 
8fced6
     /* Collect all the descriptors */
8fced6
     do {
8fced6
-        if (desc[i].flags & VRING_DESC_F_WRITE) {
8fced6
+        if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) {
8fced6
             virtqueue_map_desc(dev, &in_num, iov + out_num,
8fced6
                                VIRTQUEUE_MAX_SIZE - out_num, true,
8fced6
-                               desc[i].addr, desc[i].len);
8fced6
+                               ldq_le_p(&desc[i].addr), ldl_le_p(&desc[i].len));
8fced6
         } else {
8fced6
             if (in_num) {
8fced6
                 vu_panic(dev, "Incorrect order for descriptors");
8fced6
@@ -2196,7 +2205,7 @@ vu_queue_map_desc(VuDev *dev, VuVirtq *vq, unsigned int idx, size_t sz)
8fced6
             }
8fced6
             virtqueue_map_desc(dev, &out_num, iov,
8fced6
                                VIRTQUEUE_MAX_SIZE, false,
8fced6
-                               desc[i].addr, desc[i].len);
8fced6
+                               ldq_le_p(&desc[i].addr), ldl_le_p(&desc[i].len));
8fced6
         }
8fced6
 
8fced6
         /* If we've got too many, that implies a descriptor loop. */
8fced6
@@ -2392,14 +2401,14 @@ vu_log_queue_fill(VuDev *dev, VuVirtq *vq,
8fced6
     max = vq->vring.num;
8fced6
     i = elem->index;
8fced6
 
8fced6
-    if (desc[i].flags & VRING_DESC_F_INDIRECT) {
8fced6
-        if (desc[i].len % sizeof(struct vring_desc)) {
8fced6
+    if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_INDIRECT) {
8fced6
+        if (ldl_le_p(&desc[i].len) % sizeof(struct vring_desc)) {
8fced6
             vu_panic(dev, "Invalid size for indirect buffer table");
8fced6
         }
8fced6
 
8fced6
         /* loop over the indirect descriptor table */
8fced6
-        desc_addr = desc[i].addr;
8fced6
-        desc_len = desc[i].len;
8fced6
+        desc_addr = ldq_le_p(&desc[i].addr);
8fced6
+        desc_len = ldl_le_p(&desc[i].len);
8fced6
         max = desc_len / sizeof(struct vring_desc);
8fced6
         read_len = desc_len;
8fced6
         desc = vu_gpa_to_va(dev, &read_len, desc_addr);
8fced6
@@ -2425,9 +2434,9 @@ vu_log_queue_fill(VuDev *dev, VuVirtq *vq,
8fced6
             return;
8fced6
         }
8fced6
 
8fced6
-        if (desc[i].flags & VRING_DESC_F_WRITE) {
8fced6
-            min = MIN(desc[i].len, len);
8fced6
-            vu_log_write(dev, desc[i].addr, min);
8fced6
+        if (lduw_le_p(&desc[i].flags) & VRING_DESC_F_WRITE) {
8fced6
+            min = MIN(ldl_le_p(&desc[i].len), len);
8fced6
+            vu_log_write(dev, ldq_le_p(&desc[i].addr), min);
8fced6
             len -= min;
8fced6
         }
8fced6
 
8fced6
@@ -2452,15 +2461,15 @@ vu_queue_fill(VuDev *dev, VuVirtq *vq,
8fced6
 
8fced6
     idx = (idx + vq->used_idx) % vq->vring.num;
8fced6
 
8fced6
-    uelem.id = elem->index;
8fced6
-    uelem.len = len;
8fced6
+    stl_le_p(&uelem.id, elem->index);
8fced6
+    stl_le_p(&uelem.len, len);
8fced6
     vring_used_write(dev, vq, &uelem, idx);
8fced6
 }
8fced6
 
8fced6
 static inline
8fced6
 void vring_used_idx_set(VuDev *dev, VuVirtq *vq, uint16_t val)
8fced6
 {
8fced6
-    vq->vring.used->idx = val;
8fced6
+    stw_le_p(&vq->vring.used->idx, val);
8fced6
     vu_log_write(dev,
8fced6
                  vq->vring.log_guest_addr + offsetof(struct vring_used, idx),
8fced6
                  sizeof(vq->vring.used->idx));
8fced6
-- 
8fced6
2.27.0
8fced6