summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorVivek Kasireddy2021-05-27 01:14:18 +0200
committerGerd Hoffmann2021-05-27 12:06:37 +0200
commit9b60cdf98723b52d32fdd131f709923e05c0000f (patch)
tree9ae8590f80a311df9f74a04049ad16da150a1ddf /hw
parentheaders: Add udmabuf.h (diff)
downloadqemu-9b60cdf98723b52d32fdd131f709923e05c0000f.tar.gz
qemu-9b60cdf98723b52d32fdd131f709923e05c0000f.tar.xz
qemu-9b60cdf98723b52d32fdd131f709923e05c0000f.zip
virtio-gpu: Add udmabuf helpers
Add helper functions to create a dmabuf for a resource and mmap it. Also, introduce the fields blob and blob_size so that these helpers can start to use them but the full picture will emerge only after adding create_blob API in patch 8 of this series. To be able to create a dmabuf using the udmabuf driver, Qemu needs to be lauched with the memfd memory backend like this: qemu-system-x86_64 -m 8192m -object memory-backend-memfd,id=mem1,size=8192M -machine memory-backend=mem1 Based-on-patch-by: Gerd Hoffmann <kraxel@redhat.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com> Message-Id: <20210526231429.1045476-4-vivek.kasireddy@intel.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/display/meson.build1
-rw-r--r--hw/display/virtio-gpu-udmabuf.c158
2 files changed, 159 insertions, 0 deletions
diff --git a/hw/display/meson.build b/hw/display/meson.build
index aaf797c5e9..e1f473c1df 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -56,6 +56,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
virtio_gpu_ss = ss.source_set()
virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU',
if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman])
+ virtio_gpu_ss.add(when: 'CONFIG_LINUX', if_true: files('virtio-gpu-udmabuf.c'))
virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c'))
hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
new file mode 100644
index 0000000000..71c4672e32
--- /dev/null
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -0,0 +1,158 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ * Dave Airlie <airlied@redhat.com>
+ * Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "ui/console.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-pixman.h"
+#include "trace.h"
+#include "exec/ramblock.h"
+#include "sysemu/hostmem.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/memfd.h>
+#include "qemu/memfd.h"
+#include "standard-headers/linux/udmabuf.h"
+
+static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res)
+{
+ struct udmabuf_create_list *list;
+ RAMBlock *rb;
+ ram_addr_t offset;
+ int udmabuf, i;
+
+ udmabuf = udmabuf_fd();
+ if (udmabuf < 0) {
+ return;
+ }
+
+ list = g_malloc0(sizeof(struct udmabuf_create_list) +
+ sizeof(struct udmabuf_create_item) * res->iov_cnt);
+
+ for (i = 0; i < res->iov_cnt; i++) {
+ rcu_read_lock();
+ rb = qemu_ram_block_from_host(res->iov[i].iov_base, false, &offset);
+ rcu_read_unlock();
+
+ if (!rb || rb->fd < 0) {
+ g_free(list);
+ return;
+ }
+
+ list->list[i].memfd = rb->fd;
+ list->list[i].offset = offset;
+ list->list[i].size = res->iov[i].iov_len;
+ }
+
+ list->count = res->iov_cnt;
+ list->flags = UDMABUF_FLAGS_CLOEXEC;
+
+ res->dmabuf_fd = ioctl(udmabuf, UDMABUF_CREATE_LIST, list);
+ if (res->dmabuf_fd < 0) {
+ warn_report("%s: UDMABUF_CREATE_LIST: %s", __func__,
+ strerror(errno));
+ }
+ g_free(list);
+}
+
+static void virtio_gpu_remap_udmabuf(struct virtio_gpu_simple_resource *res)
+{
+ res->remapped = mmap(NULL, res->blob_size, PROT_READ,
+ MAP_SHARED, res->dmabuf_fd, 0);
+ if (res->remapped == MAP_FAILED) {
+ warn_report("%s: dmabuf mmap failed: %s", __func__,
+ strerror(errno));
+ res->remapped = NULL;
+ }
+}
+
+static void virtio_gpu_destroy_udmabuf(struct virtio_gpu_simple_resource *res)
+{
+ if (res->remapped) {
+ munmap(res->remapped, res->blob_size);
+ res->remapped = NULL;
+ }
+ if (res->dmabuf_fd >= 0) {
+ close(res->dmabuf_fd);
+ res->dmabuf_fd = -1;
+ }
+}
+
+static int find_memory_backend_type(Object *obj, void *opaque)
+{
+ bool *memfd_backend = opaque;
+ int ret;
+
+ if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+ RAMBlock *rb = backend->mr.ram_block;
+
+ if (rb && rb->fd > 0) {
+ ret = fcntl(rb->fd, F_GET_SEALS);
+ if (ret > 0) {
+ *memfd_backend = true;
+ }
+ }
+ }
+
+ return 0;
+}
+
+bool virtio_gpu_have_udmabuf(void)
+{
+ Object *memdev_root;
+ int udmabuf;
+ bool memfd_backend = false;
+
+ udmabuf = udmabuf_fd();
+ if (udmabuf < 0) {
+ return false;
+ }
+
+ memdev_root = object_resolve_path("/objects", NULL);
+ object_child_foreach(memdev_root, find_memory_backend_type, &memfd_backend);
+
+ return memfd_backend;
+}
+
+void virtio_gpu_init_udmabuf(struct virtio_gpu_simple_resource *res)
+{
+ void *pdata = NULL;
+
+ res->dmabuf_fd = -1;
+ if (res->iov_cnt == 1) {
+ pdata = res->iov[0].iov_base;
+ } else {
+ virtio_gpu_create_udmabuf(res);
+ if (res->dmabuf_fd < 0) {
+ return;
+ }
+ virtio_gpu_remap_udmabuf(res);
+ if (!res->remapped) {
+ return;
+ }
+ pdata = res->remapped;
+ }
+
+ res->blob = pdata;
+}
+
+void virtio_gpu_fini_udmabuf(struct virtio_gpu_simple_resource *res)
+{
+ if (res->remapped) {
+ virtio_gpu_destroy_udmabuf(res);
+ }
+}