diff mbox series

[RFC,1/1] vhost-vdmabuf: Add virtio based Dmabuf device

Message ID 20210208233225.2084469-2-vivek.kasireddy@intel.com (mailing list archive)
State New, archived
Headers show
Series vhost-vdmabuf: Add virtio based Dmabuf device | expand

Commit Message

Kasireddy, Vivek Feb. 8, 2021, 11:32 p.m. UTC
This patch provides the implementation of the virtio dmabuf device
that is used to share a dmabuf created in the Guest with the Host.
Once the vhost vdmabuf kernel driver on the Host alerts Qemu about
a new dmabuf from the Guest, it is first imported and then converted
into a texture using EGL and eventually displayed on the screen.

Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
---
 configure                                   |   8 +
 hw/virtio/meson.build                       |   1 +
 hw/virtio/vhost-backend.c                   |  10 +
 hw/virtio/vhost-vdmabuf.c                   | 526 ++++++++++++++++++++
 include/hw/pci/pci.h                        |   1 +
 include/hw/virtio/vhost-backend.h           |   2 +
 include/hw/virtio/vhost-vdmabuf.h           |  76 +++
 include/standard-headers/linux/virtio_ids.h |   1 +
 include/ui/console.h                        |   1 +
 linux-headers/linux/vhost.h                 |   3 +
 meson.build                                 |   1 +
 ui/console.c                                |   7 +
 12 files changed, 637 insertions(+)
 create mode 100644 hw/virtio/vhost-vdmabuf.c
 create mode 100644 include/hw/virtio/vhost-vdmabuf.h
diff mbox series

Patch

diff --git a/configure b/configure
index a34f91171d..90a35317bf 100755
--- a/configure
+++ b/configure
@@ -345,6 +345,7 @@  vhost_net="$default_feature"
 vhost_crypto="$default_feature"
 vhost_scsi="$default_feature"
 vhost_vsock="$default_feature"
+vhost_vdmabuf="$default_feature"
 vhost_user="no"
 vhost_user_blk_server="auto"
 vhost_user_fs="$default_feature"
@@ -1263,6 +1264,10 @@  for opt do
   ;;
   --enable-vhost-vsock) vhost_vsock="yes"
   ;;
+  --disable-vhost-vdmabuf) vhost_vdmabuf="no"
+  ;;
+  --enable-vhost-vdmabuf) vhost_vdmabuf="yes"
+  ;;
   --disable-vhost-user-blk-server) vhost_user_blk_server="disabled"
   ;;
   --enable-vhost-user-blk-server) vhost_user_blk_server="enabled"
@@ -5766,6 +5771,9 @@  if test "$vhost_vsock" = "yes" ; then
     echo "CONFIG_VHOST_USER_VSOCK=y" >> $config_host_mak
   fi
 fi
+if test "$vhost_vdmabuf" = "yes" ; then
+  echo "CONFIG_VHOST_VDMABUF=y" >> $config_host_mak
+fi
 if test "$vhost_kernel" = "yes" ; then
   echo "CONFIG_VHOST_KERNEL=y" >> $config_host_mak
 fi
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index fbff9bc9d4..f2f5408fda 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -21,6 +21,7 @@  virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c'))
 virtio_ss.add(when: ['CONFIG_VHOST_USER_FS', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-fs-pci.c'))
 virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c'))
 virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', 'vhost-vsock-common.c'))
+virtio_ss.add(when: 'CONFIG_VHOST_VDMABUF', if_true: files('vhost-vdmabuf.c'))
 virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c', 'vhost-vsock-common.c'))
 virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c'))
 virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c'))
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 31b33bde37..39a64e101d 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -214,6 +214,13 @@  static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
 }
 #endif /* CONFIG_VHOST_VSOCK */
 
+#ifdef CONFIG_VHOST_VDMABUF
+static int vhost_kernel_vdmabuf_set_running(struct vhost_dev *dev, int start)
+{
+    return vhost_kernel_call(dev, VHOST_VDMABUF_SET_RUNNING, &start);
+}
+#endif /* CONFIG_VHOST_VDMABUF */
+
 static void vhost_kernel_iotlb_read(void *opaque)
 {
     struct vhost_dev *dev = opaque;
@@ -321,6 +328,9 @@  static const VhostOps kernel_ops = {
         .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
         .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
 #endif /* CONFIG_VHOST_VSOCK */
+#ifdef CONFIG_VHOST_VDMABUF
+        .vhost_vdmabuf_set_running = vhost_kernel_vdmabuf_set_running,
+#endif /* CONFIG_VHOST_VDMABUF */
         .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
         .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
 };
diff --git a/hw/virtio/vhost-vdmabuf.c b/hw/virtio/vhost-vdmabuf.c
new file mode 100644
index 0000000000..06890e6b2a
--- /dev/null
+++ b/hw/virtio/vhost-vdmabuf.c
@@ -0,0 +1,526 @@ 
+/*
+ * Implementation of Virtio based Dmabuf device -- mostly inspired by
+ * vfio/display.c and vhost-vsock.c.
+ *
+ * Copyright 2021 Intel Corporation.
+ *
+ * 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 <sys/ioctl.h>
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/typedefs.h"
+#include "monitor/monitor.h"
+#include "virtio-pci.h"
+#include "qemu/module.h"
+#include "qemu/uuid.h"
+#include "sysemu/sysemu.h"
+#include "ui/console.h"
+#include "qapi/error.h"
+#include "trace.h"
+
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/drm/drm_fourcc.h"
+#include "hw/qdev-properties.h"
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-access.h"
+#include "hw/virtio/vhost-vdmabuf.h"
+
+#define TYPE_VHOST_VDMABUF "vhost-vdmabuf"
+#define VHOST_VDMABUF(obj) \
+        OBJECT_CHECK(VHostVdmabuf, (obj), TYPE_VHOST_VDMABUF)
+
+#define TYPE_VHOST_VDMABUF_PCI "vhost-vdmabuf-pci-base"
+#define VHOST_VDMABUF_PCI(obj) \
+        OBJECT_CHECK(VHostVdmabufPCI, (obj), TYPE_VHOST_VDMABUF_PCI)
+
+#define VHOST_VDMABUF_QUEUE_SIZE 128
+#define QEMU_UUID_SIZE_BYTES 16
+
+static bool have_event = false;
+
+typedef struct VHostVdmabufPCI VHostVdmabufPCI;
+
+typedef struct VDMABUFDMABuf {
+    QemuDmaBuf buf;
+    QemuUUID dmabuf_id;
+    QTAILQ_ENTRY(VDMABUFDMABuf) next;
+} VDMABUFDMABuf;
+
+typedef struct VDMABUFDisplay {
+    QemuConsole *con;
+    DisplaySurface *surface;
+    struct {
+        QTAILQ_HEAD(, VDMABUFDMABuf) bufs;
+        VDMABUFDMABuf *guest_fb;
+    } dmabuf;
+} VDMABUFDisplay;
+
+typedef struct {
+    VirtIODevice parent;
+
+    struct vhost_dev vhost_dev;
+    struct vhost_virtqueue vhost_vqs[2];
+
+    VirtQueue *send_vq;
+    VirtQueue *recv_vq;
+    VDMABUFDisplay *dpy;
+    int vhostfd;
+} VHostVdmabuf;
+
+struct VHostVdmabufPCI {
+    VirtIOPCIProxy parent_obj;
+    VHostVdmabuf vdev;
+};
+
+typedef struct VDMABUFBlob {
+    uint32_t width;
+    uint32_t height;
+    uint32_t stride;
+    uint32_t format;
+    uint64_t modifier;
+} VDMABUFBlob;
+
+static int vhost_vdmabuf_start(VirtIODevice *vdev)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+    BusState *bs = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *bc = VIRTIO_BUS_GET_CLASS(bs);
+    int ret, i;
+
+    if (!bc->set_guest_notifiers) {
+        error_report("No support for guest notifiers");
+        return -ENOSYS;
+    }
+
+    ret = vhost_dev_enable_notifiers(&vdmabuf->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Cannot enable host notifiers: %d", -ret);
+        return ret;
+    }
+
+    ret = bc->set_guest_notifiers(bs->parent, vdmabuf->vhost_dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Cannot set guest notifier: %d", -ret);
+        return ret;
+    }
+
+    vdmabuf->vhost_dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&vdmabuf->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Cannot start vhost: %d", -ret);
+        return ret;
+    }
+
+    for (i = 0; i < vdmabuf->vhost_dev.nvqs; i++) {
+        vhost_virtqueue_mask(&vdmabuf->vhost_dev, vdev, i, false);
+    }
+
+    return 0;
+}
+
+static void vhost_vdmabuf_stop(VirtIODevice *vdev)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+    BusState *bs = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *bc = VIRTIO_BUS_GET_CLASS(bs);
+
+    if (!bc->set_guest_notifiers) {
+        return;
+    }
+
+    vhost_dev_stop(&vdmabuf->vhost_dev, vdev);
+    vhost_dev_disable_notifiers(&vdmabuf->vhost_dev, vdev);
+}
+
+static int vhost_vdmabuf_set_running(VirtIODevice *vdev, int start)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+    const VhostOps *vhost_ops = vdmabuf->vhost_dev.vhost_ops;
+    int ret;
+
+    if (!vhost_ops->vhost_vdmabuf_set_running) {
+        return -ENOSYS;
+    }
+
+    ret = vhost_ops->vhost_vdmabuf_set_running(&vdmabuf->vhost_dev, start);
+    if (ret < 0) {
+        return -errno;
+    }
+
+    return 0;
+}
+
+static void vhost_vdmabuf_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+    int ret = 0;
+
+    if (!vdev->vm_running) {
+        should_start = false;
+    }
+
+    if (vdmabuf->vhost_dev.started == should_start) {
+        return;
+    }
+
+    if (should_start) {
+        ret = vhost_vdmabuf_start(vdev);
+        if (ret < 0) {
+            error_report("Cannot start vhost vdmabuf: %d", -ret);
+	    return;
+	}
+
+        ret = vhost_vdmabuf_set_running(vdev, 1);
+        if (ret < 0) {
+            vhost_vdmabuf_stop(vdev);
+            error_report("vhost vdmabuf set running failed: %d", ret);
+            return;
+        }
+    } else {
+        ret = vhost_vdmabuf_set_running(vdev, 0);
+        if (ret < 0) {
+            error_report("vhost vdmabuf set running failed: %d", ret);
+            return;
+        }
+
+        vhost_vdmabuf_stop(vdev);
+    }
+}
+
+static int vhost_vdmabuf_pre_save(void *opaque)
+{
+    return 0;
+}
+
+static int vhost_vdmabuf_post_load(void *opaque, int version_id)
+{
+    return 0;
+}
+
+static const VMStateDescription vmstate_virtio_vhost_vdmabuf = {
+    .name = "virtio-vhost_vdmabuf",
+    .minimum_version_id = 0,
+    .version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_VIRTIO_DEVICE,
+        VMSTATE_END_OF_LIST()
+    },
+    .pre_save = vhost_vdmabuf_pre_save,
+    .post_load = vhost_vdmabuf_post_load,
+};
+
+static void vhost_vdmabuf_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    return;
+}
+
+static void vhost_vdmabuf_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                              bool mask)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+
+    vhost_virtqueue_mask(&vdmabuf->vhost_dev, vdev, idx, mask);
+}
+
+static bool vhost_vdmabuf_guest_notifier_pending(VirtIODevice *vdev,
+                                                 int idx)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(vdev);
+
+    return vhost_virtqueue_pending(&vdmabuf->vhost_dev, idx);
+}
+
+static void vhost_vdmabuf_device_unrealize(DeviceState *dev)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(dev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+    vhost_vdmabuf_set_status(vdev, 0);
+    vhost_dev_cleanup(&vdmabuf->vhost_dev);
+
+    virtio_delete_queue(vdmabuf->send_vq);
+    virtio_delete_queue(vdmabuf->recv_vq);
+    virtio_cleanup(vdev);
+}
+
+static VDMABUFDMABuf *vdmabuf_display_get_dmabuf(VHostVdmabuf *vdmabuf)
+{
+    VDMABUFDisplay *dpy = vdmabuf->dpy;
+    VDMABUFDMABuf *dmabuf;
+    VDMABUFBlob *dmabuf_blob;
+    QemuUUID uuid;
+    struct virtio_vdmabuf_import msg;
+    struct virtio_vdmabuf_e_hdr *ev_hdr;
+    int fd = vdmabuf->vhostfd;
+    char data[256] = {0};
+    long ret = 0;
+
+    ret = read(fd, data, sizeof *ev_hdr + sizeof *dmabuf_blob);
+    if (ret <= 0) {
+        error_report("Cannot read event: %ld", -ret);
+        return NULL;
+    }
+
+    ev_hdr = (struct virtio_vdmabuf_e_hdr *)data;
+    memcpy(&uuid, &ev_hdr->buf_id, QEMU_UUID_SIZE_BYTES);
+    dmabuf_blob = (VDMABUFBlob *)(data + sizeof *ev_hdr);
+
+    QTAILQ_FOREACH(dmabuf, &dpy->dmabuf.bufs, next) {
+        if (qemu_uuid_is_equal(&uuid, &dmabuf->dmabuf_id)) {
+            QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
+            QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
+            return dmabuf;
+        }
+    }
+
+    memcpy(&msg.buf_id, &uuid, QEMU_UUID_SIZE_BYTES);
+    ret = ioctl(fd, VIRTIO_VDMABUF_IOCTL_IMPORT, &msg);
+    if (ret) {
+        error_report("Cannot import dmabuf: %ld", -ret);
+	return NULL;
+    }
+
+    dmabuf = g_new0(VDMABUFDMABuf, 1);
+    memcpy(&dmabuf->dmabuf_id, &uuid, QEMU_UUID_SIZE_BYTES);
+    dmabuf->buf.fd = msg.fd;
+
+    dmabuf->buf.width = dmabuf_blob->width;
+    dmabuf->buf.height = dmabuf_blob->height;
+    dmabuf->buf.stride = dmabuf_blob->stride;
+    dmabuf->buf.fourcc = dmabuf_blob->format;
+    dmabuf->buf.modifier = dmabuf_blob->modifier;
+
+    QTAILQ_INSERT_HEAD(&dpy->dmabuf.bufs, dmabuf, next);
+    return dmabuf;
+}
+
+static void vdmabuf_display_free_one_dmabuf(VHostVdmabuf *vdmabuf,
+					    VDMABUFDisplay *dpy,
+                                            VDMABUFDMABuf *dmabuf)
+{
+    struct virtio_vdmabuf_import msg;
+    int fd = vdmabuf->vhostfd;
+
+    QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
+    dpy_gl_release_dmabuf(dpy->con, &dmabuf->buf);
+
+    memcpy(&msg.buf_id, &dmabuf->dmabuf_id, QEMU_UUID_SIZE_BYTES);
+    if (ioctl(fd, VIRTIO_VDMABUF_IOCTL_RELEASE, &msg))
+        error_report("Error releasing dmabuf");
+
+    close(dmabuf->buf.fd);
+    g_free(dmabuf);
+}
+
+static void vdmabuf_display_free_dmabufs(VHostVdmabuf *vdmabuf)
+{
+    VDMABUFDisplay *dpy = vdmabuf->dpy;
+    VDMABUFDMABuf *dmabuf, *tmp;
+    uint32_t keep = 2;
+
+    QTAILQ_FOREACH_SAFE(dmabuf, &dpy->dmabuf.bufs, next, tmp) {
+        if (keep > 0) {
+            keep--;
+            continue;
+        }
+
+        assert(dmabuf != dpy->dmabuf.guest_fb);
+        vdmabuf_display_free_one_dmabuf(vdmabuf, dpy, dmabuf);
+    }
+}
+
+static void vdmabuf_display_dmabuf_update(void *opaque)
+{
+    VHostVdmabuf *vdmabuf = opaque;
+    VDMABUFDisplay *dpy = vdmabuf->dpy;
+    VDMABUFDMABuf *guest_fb;
+    bool free_bufs = false;
+
+    if (!have_event)
+        return;
+
+    guest_fb = vdmabuf_display_get_dmabuf(vdmabuf);
+    if (guest_fb == NULL) {
+        return;
+    }
+
+    if (dpy->dmabuf.guest_fb != guest_fb) {
+        dpy->dmabuf.guest_fb = guest_fb;
+        qemu_console_resize(dpy->con,
+                            guest_fb->buf.width, guest_fb->buf.height);
+        dpy_gl_scanout_dmabuf(dpy->con, &guest_fb->buf);
+        free_bufs = true;
+    }
+
+    dpy_gl_update(dpy->con, 0, 0, guest_fb->buf.width, guest_fb->buf.height);
+
+    if (free_bufs) {
+        vdmabuf_display_free_dmabufs(vdmabuf);
+    }
+
+    have_event = false;
+}
+
+static void vdmabuf_event_handler(void *opaque)
+{
+    VHostVdmabuf *vdmabuf = opaque;
+    VDMABUFDisplay *dpy = vdmabuf->dpy;
+
+    have_event = true;
+    graphic_hw_dpy_refresh(dpy->con);
+}
+
+static const GraphicHwOps vdmabuf_display_dmabuf_ops = {
+    .gfx_update = vdmabuf_display_dmabuf_update,
+};
+
+static int vdmabuf_display_dmabuf_init(VHostVdmabuf *vdmabuf, Error **errp)
+{
+    if (!display_opengl) {
+        error_setg(errp, "vhost-vdmabuf: opengl not available");
+        return -1;
+    }
+
+    vdmabuf->dpy = g_new0(VDMABUFDisplay, 1);
+    vdmabuf->dpy->con = graphic_console_init(NULL, 0,
+                                             &vdmabuf_display_dmabuf_ops,
+                                             vdmabuf);
+    return 0;
+}
+
+
+static void vhost_vdmabuf_device_realize(DeviceState *dev, Error **errp)
+{
+    VHostVdmabuf *vdmabuf = VHOST_VDMABUF(dev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    int vhostfd;
+    int ret;
+
+    vhostfd = open("/dev/vhost-vdmabuf", O_RDWR);
+    if (vhostfd < 0) {
+        error_setg_errno(errp, errno,
+                         "vhost-vdmabuf: failed to open vhost device");
+        return;
+    }
+
+    virtio_init(vdev, "vhost-vdmabuf", VIRTIO_ID_VDMABUF, 0);
+    vdmabuf->send_vq = virtio_add_queue(vdev, VHOST_VDMABUF_QUEUE_SIZE,
+                                        vhost_vdmabuf_handle_output);
+    vdmabuf->recv_vq = virtio_add_queue(vdev, VHOST_VDMABUF_QUEUE_SIZE,
+                                        vhost_vdmabuf_handle_output);
+
+    vdmabuf->vhost_dev.nvqs = ARRAY_SIZE(vdmabuf->vhost_vqs);
+    vdmabuf->vhost_dev.vqs = vdmabuf->vhost_vqs;
+    
+    ret = vhost_dev_init(&vdmabuf->vhost_dev, (void *)(uintptr_t)vhostfd,
+                         VHOST_BACKEND_TYPE_KERNEL, 0);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost-vdmabuf: vhost_dev_init failed");
+        goto err_virtio;
+    }
+
+    vdmabuf->vhostfd = vhostfd;
+    qemu_set_fd_handler(vhostfd, vdmabuf_event_handler, NULL, vdmabuf);
+
+    ret = vdmabuf_display_dmabuf_init(vdmabuf, errp);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost-vdmabuf: dmabuf_init failed");
+        goto err_virtio;
+    }
+
+    return;
+
+err_virtio:
+    vhost_vdmabuf_device_unrealize(dev);
+    if (vhostfd >= 0) {
+        close(vhostfd);
+    }
+}
+
+static uint64_t vhost_vdmabuf_get_features(VirtIODevice *vdev,
+                                           uint64_t req_features,
+                                           Error **errp)
+{
+    return req_features;
+}
+
+static void vhost_vdmabuf_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_virtio_vhost_vdmabuf;
+    vdc->realize = vhost_vdmabuf_device_realize;
+    vdc->unrealize = vhost_vdmabuf_device_unrealize;
+    vdc->get_features = vhost_vdmabuf_get_features;
+    vdc->set_status = vhost_vdmabuf_set_status;
+
+    vdc->guest_notifier_mask = vhost_vdmabuf_guest_notifier_mask;
+    vdc->guest_notifier_pending = vhost_vdmabuf_guest_notifier_pending;
+}
+
+static const TypeInfo vhost_vdmabuf_info = {
+    .name = TYPE_VHOST_VDMABUF,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VHostVdmabuf),
+    .class_init = vhost_vdmabuf_class_init,
+};
+
+static void vhost_vdmabuf_register_types(void)
+{
+    type_register_static(&vhost_vdmabuf_info);
+}
+
+static void vhost_vdmabuf_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VHostVdmabufPCI *dev = VHOST_VDMABUF_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+}
+
+static void vhost_vdmabuf_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *pc = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    pc->realize = vhost_vdmabuf_pci_realize;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VDMABUF;
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+}
+
+static void vhost_vdmabuf_pci_instance_init(Object *obj)
+{
+    VHostVdmabufPCI *dev = VHOST_VDMABUF_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VHOST_VDMABUF);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_vdmabuf_pci_info = {
+    .base_name     = TYPE_VHOST_VDMABUF_PCI,
+    .generic_name  = "vhost-vdmabuf-pci",
+    .instance_size = sizeof(VHostVdmabufPCI),
+    .instance_init = vhost_vdmabuf_pci_instance_init,
+    .class_init    = vhost_vdmabuf_pci_class_init,
+};
+
+static void virtio_pci_vhost_register(void)
+{
+    virtio_pci_types_register(&vhost_vdmabuf_pci_info);
+}
+
+type_init(virtio_pci_vhost_register)
+type_init(vhost_vdmabuf_register_types)
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 1bc231480f..fe4dd2443c 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -89,6 +89,7 @@  extern bool pci_available;
 #define PCI_DEVICE_ID_VIRTIO_PMEM        0x1013
 #define PCI_DEVICE_ID_VIRTIO_IOMMU       0x1014
 #define PCI_DEVICE_ID_VIRTIO_MEM         0x1015
+#define PCI_DEVICE_ID_VIRTIO_VDMABUF     0x1016
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
 #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h
index 8a6f8e2a7a..f00ab76e70 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -89,6 +89,7 @@  typedef bool (*vhost_backend_can_merge_op)(struct vhost_dev *dev,
 typedef int (*vhost_vsock_set_guest_cid_op)(struct vhost_dev *dev,
                                             uint64_t guest_cid);
 typedef int (*vhost_vsock_set_running_op)(struct vhost_dev *dev, int start);
+typedef int (*vhost_vdmabuf_set_running_op)(struct vhost_dev *dev, int start);
 typedef void (*vhost_set_iotlb_callback_op)(struct vhost_dev *dev,
                                            int enabled);
 typedef int (*vhost_send_device_iotlb_msg_op)(struct vhost_dev *dev,
@@ -157,6 +158,7 @@  typedef struct VhostOps {
     vhost_backend_can_merge_op vhost_backend_can_merge;
     vhost_vsock_set_guest_cid_op vhost_vsock_set_guest_cid;
     vhost_vsock_set_running_op vhost_vsock_set_running;
+    vhost_vdmabuf_set_running_op vhost_vdmabuf_set_running;
     vhost_set_iotlb_callback_op vhost_set_iotlb_callback;
     vhost_send_device_iotlb_msg_op vhost_send_device_iotlb_msg;
     vhost_get_config_op vhost_get_config;
diff --git a/include/hw/virtio/vhost-vdmabuf.h b/include/hw/virtio/vhost-vdmabuf.h
new file mode 100644
index 0000000000..aef99cbae2
--- /dev/null
+++ b/include/hw/virtio/vhost-vdmabuf.h
@@ -0,0 +1,76 @@ 
+// SPDX-License-Identifier: (MIT OR GPL-2.0)
+
+/*
+ * Copyright © 2021 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _UAPI_LINUX_VIRTIO_VDMABUF_H
+#define _UAPI_LINUX_VIRTIO_VDMABUF_H
+
+typedef struct {
+	__u64 id;
+	/* 8B long Random number */
+	int rng_key[2];
+} virtio_vdmabuf_buf_id_t;
+
+struct virtio_vdmabuf_e_hdr {
+	/* buf_id of new buf */
+	virtio_vdmabuf_buf_id_t buf_id;
+	/* size of private data */
+	int size;
+};
+
+struct virtio_vdmabuf_e_data {
+	struct virtio_vdmabuf_e_hdr hdr;
+	/* ptr to private data */
+	void *data;
+};
+
+#define VIRTIO_VDMABUF_IOCTL_IMPORT \
+_IOC(_IOC_NONE, 'G', 2, sizeof(struct virtio_vdmabuf_import))
+#define VIRTIO_VDMABUF_IOCTL_RELEASE \
+_IOC(_IOC_NONE, 'G', 3, sizeof(struct virtio_vdmabuf_import))
+struct virtio_vdmabuf_import {
+	/* IN parameters */
+	/* vdmabuf id to be imported */
+	virtio_vdmabuf_buf_id_t buf_id;
+	/* flags */
+	int flags;
+	/* OUT parameters */
+	/* exported dma buf fd */
+	int fd;
+};
+
+#define VIRTIO_VDMABUF_IOCTL_EXPORT \
+_IOC(_IOC_NONE, 'G', 4, sizeof(struct virtio_vdmabuf_export))
+struct virtio_vdmabuf_export {
+	/* IN parameters */
+	/* DMA buf fd to be exported */
+	int fd;
+	/* exported dma buf id */
+	virtio_vdmabuf_buf_id_t buf_id;
+	int sz_priv;
+	char *priv;
+};
+
+#endif
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
index bc1c0621f5..6c8c19fb6b 100644
--- a/include/standard-headers/linux/virtio_ids.h
+++ b/include/standard-headers/linux/virtio_ids.h
@@ -54,5 +54,6 @@ 
 #define VIRTIO_ID_FS			26 /* virtio filesystem */
 #define VIRTIO_ID_PMEM			27 /* virtio pmem */
 #define VIRTIO_ID_MAC80211_HWSIM	29 /* virtio mac80211-hwsim */
+#define VIRTIO_ID_VDMABUF		37 /* virtio vdmabuf */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
diff --git a/include/ui/console.h b/include/ui/console.h
index d30e972d0b..892b7ff03f 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -400,6 +400,7 @@  void graphic_console_close(QemuConsole *con);
 
 void graphic_hw_update(QemuConsole *con);
 void graphic_hw_update_done(QemuConsole *con);
+void graphic_hw_dpy_refresh(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h
index c998860d7b..d53faa59e9 100644
--- a/linux-headers/linux/vhost.h
+++ b/linux-headers/linux/vhost.h
@@ -150,4 +150,7 @@ 
 /* Get the valid iova range */
 #define VHOST_VDPA_GET_IOVA_RANGE	_IOR(VHOST_VIRTIO, 0x78, \
 					     struct vhost_vdpa_iova_range)
+/* VHOST_VDMABUF specific defines */
+#define VHOST_VDMABUF_SET_RUNNING	_IOW(VHOST_VIRTIO, 0x79, int)
+
 #endif
diff --git a/meson.build b/meson.build
index 2d8b433ff0..1847abf9a4 100644
--- a/meson.build
+++ b/meson.build
@@ -2417,6 +2417,7 @@  summary_info += {'vhost-net support': config_host.has_key('CONFIG_VHOST_NET')}
 summary_info += {'vhost-crypto support': config_host.has_key('CONFIG_VHOST_CRYPTO')}
 summary_info += {'vhost-scsi support': config_host.has_key('CONFIG_VHOST_SCSI')}
 summary_info += {'vhost-vsock support': config_host.has_key('CONFIG_VHOST_VSOCK')}
+summary_info += {'vhost-vdmabuf support': config_host.has_key('CONFIG_VHOST_VDMABUF')}
 summary_info += {'vhost-user support': config_host.has_key('CONFIG_VHOST_USER')}
 summary_info += {'vhost-user-blk server support': have_vhost_user_blk_server}
 summary_info += {'vhost-user-fs support': config_host.has_key('CONFIG_VHOST_USER_FS')}
diff --git a/ui/console.c b/ui/console.c
index c5d11bc701..8a80e97195 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -284,6 +284,13 @@  void graphic_hw_update(QemuConsole *con)
     }
 }
 
+void graphic_hw_dpy_refresh(QemuConsole *con)
+{
+    DisplayState *ds = con ? con->ds : active_console->ds;
+
+    dpy_refresh(ds);
+}
+
 void graphic_hw_gl_block(QemuConsole *con, bool block)
 {
     assert(con != NULL);