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

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