a83cc2
From cdc537ada9528e09f8c70219f5a9a1ce8a4efa7e Mon Sep 17 00:00:00 2001
a83cc2
From: Gerd Hoffmann <kraxel@redhat.com>
a83cc2
Date: Thu, 6 May 2021 11:10:01 +0200
a83cc2
Subject: [PATCH 02/12] virtio-gpu: handle partial maps properly
a83cc2
a83cc2
RH-Author: Eric Auger <eric.auger@redhat.com>
a83cc2
RH-MergeRequest: 15: virtio-gpu: handle partial maps properly
a83cc2
RH-Commit: [1/1] f2b0fd9758251d1f3a5ff9563911c8bdb4b191f0 (eauger1/centos-qemu-kvm)
a83cc2
RH-Bugzilla: 1974795
a83cc2
RH-Acked-by: Gavin Shan <gshan@redhat.com>
a83cc2
RH-Acked-by: Andrew Jones <drjones@redhat.com>
a83cc2
RH-Acked-by: Peter Xu <Peter Xu <peterx@redhat.com>
a83cc2
a83cc2
dma_memory_map() may map only a part of the request.  Happens if the
a83cc2
request can't be mapped in one go, for example due to a iommu creating
a83cc2
a linear dma mapping for scattered physical pages.  Should that be the
a83cc2
case virtio-gpu must call dma_memory_map() again with the remaining
a83cc2
range instead of simply throwing an error.
a83cc2
a83cc2
Note that this change implies the number of iov entries may differ from
a83cc2
the number of mapping entries sent by the guest.  Therefore the iov_len
a83cc2
bookkeeping needs some updates too, we have to explicitly pass around
a83cc2
the iov length now.
a83cc2
a83cc2
Reported-by: Auger Eric <eric.auger@redhat.com>
a83cc2
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
a83cc2
Message-id: 20210506091001.1301250-1-kraxel@redhat.com
a83cc2
Reviewed-by: Eric Auger <eric.auger@redhat.com>
a83cc2
Tested-by: Eric Auger <eric.auger@redhat.com>
a83cc2
Message-Id: <20210506091001.1301250-1-kraxel@redhat.com>
a83cc2
(cherry picked from commit 9049f8bc445d50c0b5fe5500c0ec51fcc821c2ef)
a83cc2
Signed-off-by: Eric Auger <eric.auger@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 hw/display/virtio-gpu-3d.c     |  7 ++--
a83cc2
 hw/display/virtio-gpu.c        | 76 ++++++++++++++++++++--------------
a83cc2
 include/hw/virtio/virtio-gpu.h |  3 +-
a83cc2
 3 files changed, 52 insertions(+), 34 deletions(-)
a83cc2
a83cc2
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
a83cc2
index d98964858e..72c14d9132 100644
a83cc2
--- a/hw/display/virtio-gpu-3d.c
a83cc2
+++ b/hw/display/virtio-gpu-3d.c
a83cc2
@@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
a83cc2
 {
a83cc2
     struct virtio_gpu_resource_attach_backing att_rb;
a83cc2
     struct iovec *res_iovs;
a83cc2
+    uint32_t res_niov;
a83cc2
     int ret;
a83cc2
 
a83cc2
     VIRTIO_GPU_FILL_CMD(att_rb);
a83cc2
     trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
a83cc2
 
a83cc2
-    ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs);
a83cc2
+    ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov);
a83cc2
     if (ret != 0) {
a83cc2
         cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
a83cc2
         return;
a83cc2
     }
a83cc2
 
a83cc2
     ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
a83cc2
-                                             res_iovs, att_rb.nr_entries);
a83cc2
+                                             res_iovs, res_niov);
a83cc2
 
a83cc2
     if (ret != 0)
a83cc2
-        virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries);
a83cc2
+        virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov);
a83cc2
 }
a83cc2
 
a83cc2
 static void virgl_resource_detach_backing(VirtIOGPU *g,
a83cc2
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
a83cc2
index c9f5e36fd0..6f3791deb3 100644
a83cc2
--- a/hw/display/virtio-gpu.c
a83cc2
+++ b/hw/display/virtio-gpu.c
a83cc2
@@ -608,11 +608,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
a83cc2
 int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
a83cc2
                                   struct virtio_gpu_resource_attach_backing *ab,
a83cc2
                                   struct virtio_gpu_ctrl_command *cmd,
a83cc2
-                                  uint64_t **addr, struct iovec **iov)
a83cc2
+                                  uint64_t **addr, struct iovec **iov,
a83cc2
+                                  uint32_t *niov)
a83cc2
 {
a83cc2
     struct virtio_gpu_mem_entry *ents;
a83cc2
     size_t esize, s;
a83cc2
-    int i;
a83cc2
+    int e, v;
a83cc2
 
a83cc2
     if (ab->nr_entries > 16384) {
a83cc2
         qemu_log_mask(LOG_GUEST_ERROR,
a83cc2
@@ -633,37 +634,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
a83cc2
         return -1;
a83cc2
     }
a83cc2
 
a83cc2
-    *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
a83cc2
+    *iov = NULL;
a83cc2
     if (addr) {
a83cc2
-        *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
a83cc2
+        *addr = NULL;
a83cc2
     }
a83cc2
-    for (i = 0; i < ab->nr_entries; i++) {
a83cc2
-        uint64_t a = le64_to_cpu(ents[i].addr);
a83cc2
-        uint32_t l = le32_to_cpu(ents[i].length);
a83cc2
-        hwaddr len = l;
a83cc2
-        (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
a83cc2
-                                            a, &len, DMA_DIRECTION_TO_DEVICE);
a83cc2
-        (*iov)[i].iov_len = len;
a83cc2
-        if (addr) {
a83cc2
-            (*addr)[i] = a;
a83cc2
-        }
a83cc2
-        if (!(*iov)[i].iov_base || len != l) {
a83cc2
-            qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
a83cc2
-                          " resource %d element %d\n",
a83cc2
-                          __func__, ab->resource_id, i);
a83cc2
-            if ((*iov)[i].iov_base) {
a83cc2
-                i++; /* cleanup the 'i'th map */
a83cc2
+    for (e = 0, v = 0; e < ab->nr_entries; e++) {
a83cc2
+        uint64_t a = le64_to_cpu(ents[e].addr);
a83cc2
+        uint32_t l = le32_to_cpu(ents[e].length);
a83cc2
+        hwaddr len;
a83cc2
+        void *map;
a83cc2
+
a83cc2
+        do {
a83cc2
+            len = l;
a83cc2
+            map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
a83cc2
+                                 a, &len, DMA_DIRECTION_TO_DEVICE);
a83cc2
+            if (!map) {
a83cc2
+                qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
a83cc2
+                              " resource %d element %d\n",
a83cc2
+                              __func__, ab->resource_id, e);
a83cc2
+                virtio_gpu_cleanup_mapping_iov(g, *iov, v);
a83cc2
+                g_free(ents);
a83cc2
+                *iov = NULL;
a83cc2
+                if (addr) {
a83cc2
+                    g_free(*addr);
a83cc2
+                    *addr = NULL;
a83cc2
+                }
a83cc2
+                return -1;
a83cc2
+            }
a83cc2
+
a83cc2
+            if (!(v % 16)) {
a83cc2
+                *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16));
a83cc2
+                if (addr) {
a83cc2
+                    *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16));
a83cc2
+                }
a83cc2
             }
a83cc2
-            virtio_gpu_cleanup_mapping_iov(g, *iov, i);
a83cc2
-            g_free(ents);
a83cc2
-            *iov = NULL;
a83cc2
+            (*iov)[v].iov_base = map;
a83cc2
+            (*iov)[v].iov_len = len;
a83cc2
             if (addr) {
a83cc2
-                g_free(*addr);
a83cc2
-                *addr = NULL;
a83cc2
+                (*addr)[v] = a;
a83cc2
             }
a83cc2
-            return -1;
a83cc2
-        }
a83cc2
+
a83cc2
+            a += len;
a83cc2
+            l -= len;
a83cc2
+            v += 1;
a83cc2
+        } while (l > 0);
a83cc2
     }
a83cc2
+    *niov = v;
a83cc2
+
a83cc2
     g_free(ents);
a83cc2
     return 0;
a83cc2
 }
a83cc2
@@ -717,13 +734,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
a83cc2
         return;
a83cc2
     }
a83cc2
 
a83cc2
-    ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov);
a83cc2
+    ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs,
a83cc2
+                                        &res->iov, &res->iov_cnt);
a83cc2
     if (ret != 0) {
a83cc2
         cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
a83cc2
         return;
a83cc2
     }
a83cc2
-
a83cc2
-    res->iov_cnt = ab.nr_entries;
a83cc2
 }
a83cc2
 
a83cc2
 static void
a83cc2
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
a83cc2
index fae149235c..0d15af41d9 100644
a83cc2
--- a/include/hw/virtio/virtio-gpu.h
a83cc2
+++ b/include/hw/virtio/virtio-gpu.h
a83cc2
@@ -209,7 +209,8 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
a83cc2
 int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
a83cc2
                                   struct virtio_gpu_resource_attach_backing *ab,
a83cc2
                                   struct virtio_gpu_ctrl_command *cmd,
a83cc2
-                                  uint64_t **addr, struct iovec **iov);
a83cc2
+                                  uint64_t **addr, struct iovec **iov,
a83cc2
+                                  uint32_t *niov);
a83cc2
 void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
a83cc2
                                     struct iovec *iov, uint32_t count);
a83cc2
 void virtio_gpu_process_cmdq(VirtIOGPU *g);
a83cc2
-- 
a83cc2
2.27.0
a83cc2