cryptospore / 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

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