* [RFC PATCH] virtio: Add driver for virtio gpu
@ 2026-05-23 5:50 Daniel Palmer
2026-05-23 9:31 ` Simon Glass
2026-05-26 6:10 ` Kuan-Wei Chiu
0 siblings, 2 replies; 4+ messages in thread
From: Daniel Palmer @ 2026-05-23 5:50 UTC (permalink / raw)
To: bmeng.cn, sjg, visitorckw; +Cc: u-boot, Daniel Palmer
Add a basic driver for virtio gpu. This allows for a video on
qemu virt machines.
Signed-off-by: Daniel Palmer <daniel@thingy.jp>
---
Since the m68k virtio stuff is now in next I thought I'd send this.
This patch is based on next.
This is a very simple driver for virtio gpu that works just enough
to create a framebuffer that u-boot can use.
I've been playing with this on m68k and its shown that some of the
framebuffer code has some endian issues.
I think this is useful for testing the framebuffer code on other
arches like arm, riscv and so on.
Open to comments, ideas etc.
drivers/virtio/Kconfig | 19 ++
drivers/virtio/Makefile | 1 +
drivers/virtio/virtio-uclass.c | 1 +
drivers/virtio/virtio_gpu.c | 284 ++++++++++++++++++++
drivers/virtio/virtio_gpu.h | 461 +++++++++++++++++++++++++++++++++
include/virtio.h | 10 +-
6 files changed, 772 insertions(+), 4 deletions(-)
create mode 100644 drivers/virtio/virtio_gpu.c
create mode 100644 drivers/virtio/virtio_gpu.h
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 512ac376f185..d554346a2772 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -77,4 +77,23 @@ config VIRTIO_RNG
help
This is the virtual random number generator driver. It can be used
with QEMU based targets.
+
+config VIRTIO_GPU
+ bool "virtio gpu driver"
+ depends on VIDEO
+ depends on VIRTIO
+ help
+ This is the virtual GPU driver. It can be used
+ with QEMU based targets.
+
+if VIRTIO_GPU
+config VIRTIO_DEFAULT_WIDTH
+ int "default width"
+ default 1024
+
+config VIRTIO_DEFAULT_HEIGHT
+ int "default height"
+ default 768
+endif
+
endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 4c63a6c69043..c830fb6e6049 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o
+obj-$(CONFIG_VIRTIO_GPU) += virtio_gpu.o
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index c36e9e9b3a77..f040907e3a84 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -30,6 +30,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = {
[VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME,
[VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME,
[VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME,
+ [VIRTIO_ID_GPU] = VIRTIO_GPU_DRV_NAME,
};
int virtio_get_config(struct udevice *vdev, unsigned int offset,
diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
new file mode 100644
index 000000000000..cd4dbc6857aa
--- /dev/null
+++ b/drivers/virtio/virtio_gpu.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * virtio GPU driver
+ * 2025 Daniel Palmer <daniel@thingy.jp>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <video.h>
+#include <virtio_types.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+
+#include "virtio_gpu.h"
+
+#define VQ_CONTROL 0
+#define VQ_CURSOR 1
+#define NUM_VQS 2
+#define FRAMEBUFFER_RESOURCE_ID 1
+
+struct virtio_gpu_priv {
+ struct virtqueue *vqs[NUM_VQS];
+};
+
+static int virtio_gpu_cmd(struct virtqueue *vq,
+ void *req, size_t req_size,
+ void *resp, size_t resp_size)
+{
+ struct virtio_sg resp_sg = { resp, resp_size };
+ struct virtio_sg req_sg = { req, req_size };
+ struct virtio_sg *sgs[] = { &req_sg, &resp_sg };
+ struct virtio_gpu_ctrl_hdr *resp_hdr = resp;
+ int ret;
+
+ ret = virtqueue_add(vq, sgs, 1, 1);
+ if (ret)
+ return ret;
+
+ virtqueue_kick(vq);
+
+ while (!virtqueue_get_buf(vq, NULL))
+ ;
+
+ /* Some basic error handling */
+ switch (le32_to_cpu(resp_hdr->type)) {
+ case VIRTIO_GPU_RESP_ERR_UNSPEC:
+ case VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID:
+ case VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID:
+ case VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID:
+ case VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER:
+ return -EINVAL;
+ case VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY:
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int virtio_gpu_get_display_info(struct virtqueue *vq,
+ struct virtio_gpu_resp_display_info *info)
+{
+ struct virtio_gpu_ctrl_hdr req = {
+ .type = cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO),
+ };
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), info, sizeof(*info));
+}
+
+static int virtio_gpu_resource_create_2d(struct virtqueue *vq,
+ u32 resource_id,
+ u32 format,
+ u32 width,
+ u32 height)
+{
+ struct virtio_gpu_resource_create_2d req = {
+ .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D),
+ .resource_id = cpu_to_le32(resource_id),
+ .format = cpu_to_le32(format),
+ .width = cpu_to_le32(width),
+ .height = cpu_to_le32(height),
+ };
+ struct virtio_gpu_ctrl_hdr resp;
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+struct virtio_gpu_attach_backing_hdr_ent {
+ struct virtio_gpu_resource_attach_backing hdr;
+ struct virtio_gpu_mem_entry entry;
+};
+
+static int virtio_gpu_resource_attach_backing(struct virtqueue *vq,
+ u32 resource_id,
+ u64 addr,
+ u32 length)
+{
+ struct virtio_gpu_attach_backing_hdr_ent req = {
+ .hdr = {
+ .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING),
+ .resource_id = cpu_to_le32(resource_id),
+ .nr_entries = cpu_to_le32(1),
+ },
+ .entry = {
+ .addr = cpu_to_le64(addr),
+ .length = cpu_to_le32(length),
+ },
+ };
+ struct virtio_gpu_ctrl_hdr resp;
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_set_scanout(struct virtqueue *vq,
+ u32 resource_id,
+ u32 width, u32 height)
+{
+ struct virtio_gpu_set_scanout req = {
+ .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_SET_SCANOUT),
+ .resource_id = cpu_to_le32(resource_id),
+ .r = {
+ .width = cpu_to_le32(width),
+ .height = cpu_to_le32(height),
+ },
+ };
+ struct virtio_gpu_ctrl_hdr resp;
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_set_transfer_to_host_2d(struct virtqueue *vq,
+ u32 resource_id,
+ u32 width,
+ u32 height)
+{
+ struct virtio_gpu_transfer_to_host_2d req = {
+ .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D),
+ .resource_id = cpu_to_le32(resource_id),
+ .r = {
+ .width = cpu_to_le32(width),
+ .height = cpu_to_le32(height),
+ },
+ };
+ struct virtio_gpu_ctrl_hdr resp;
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_resource_flush(struct virtqueue *vq,
+ u32 resource_id,
+ u32 width,
+ u32 height)
+{
+ struct virtio_gpu_resource_flush req = {
+ .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_FLUSH),
+ .resource_id = cpu_to_le32(resource_id),
+ .r = {
+ .width = cpu_to_le32(width),
+ .height = cpu_to_le32(height),
+ },
+ };
+ struct virtio_gpu_ctrl_hdr resp;
+
+ return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
+}
+
+static int virtio_gpu_flush(struct udevice *dev)
+{
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct virtio_gpu_priv *priv = dev_get_priv(dev);
+ struct virtqueue *vq = priv->vqs[VQ_CONTROL];
+ int ret;
+
+ ret = virtio_gpu_set_transfer_to_host_2d(vq,
+ FRAMEBUFFER_RESOURCE_ID,
+ uc_priv->xsize,
+ uc_priv->ysize);
+ if (ret)
+ return ret;
+
+ ret = virtio_gpu_resource_flush(vq,
+ FRAMEBUFFER_RESOURCE_ID,
+ uc_priv->xsize,
+ uc_priv->ysize);
+
+ return ret;
+}
+
+static int virtio_gpu_probe(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct virtio_gpu_priv *priv = dev_get_priv(dev);
+ struct virtio_gpu_resp_display_info display_info;
+ struct virtqueue *vq;
+ u32 width, height;
+ int ret;
+ int i;
+
+ width = CONFIG_VIRTIO_DEFAULT_WIDTH;
+ height = CONFIG_VIRTIO_DEFAULT_HEIGHT;
+
+ ret = virtio_find_vqs(dev, NUM_VQS, priv->vqs);
+ if (ret)
+ return ret;
+
+ vq = priv->vqs[VQ_CONTROL];
+
+ ret = virtio_gpu_get_display_info(vq,
+ &display_info);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) {
+ u32 h = le32_to_cpu(display_info.pmodes[i].r.height);
+ u32 w = le32_to_cpu(display_info.pmodes[i].r.width);
+ u32 e = le32_to_cpu(display_info.pmodes[i].enabled);
+
+ if (!e)
+ continue;
+
+ /* For now just use the first enabled one */
+ width = w;
+ height = h;
+ break;
+ }
+
+ /* Just use 32 bpp rgba for now */
+ uc_priv->xsize = width;
+ uc_priv->ysize = height;
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->format = VIDEO_RGBA8888;
+
+ ret = virtio_gpu_resource_create_2d(vq,
+ FRAMEBUFFER_RESOURCE_ID,
+ VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM,
+ uc_priv->xsize,
+ uc_priv->ysize);
+ if (ret)
+ return ret;
+
+ /* virtio GPU apparently doesn't care about alignment */
+ plat->size = (width * height) * 4;
+ plat->base = (ulong)malloc(plat->size);
+ if (!plat->base)
+ return -ENOMEM;
+
+ ret = virtio_gpu_resource_attach_backing(vq,
+ FRAMEBUFFER_RESOURCE_ID,
+ plat->base,
+ round_up(plat->size, 4096));
+ if (ret)
+ goto err;
+
+ ret = virtio_gpu_set_scanout(vq,
+ FRAMEBUFFER_RESOURCE_ID,
+ uc_priv->xsize,
+ uc_priv->ysize);
+ if (ret)
+ goto err;
+
+ /* Do an initial flush to activate the output */
+ ret = virtio_gpu_flush(dev);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ free((void *)plat->base);
+ return ret;
+}
+
+static const struct video_ops virtio_gpu_ops = {
+ .video_sync = virtio_gpu_flush,
+};
+
+U_BOOT_DRIVER(virtio_gpu) = {
+ .name = VIRTIO_GPU_DRV_NAME,
+ .id = UCLASS_VIDEO,
+ .ops = &virtio_gpu_ops,
+ .probe = virtio_gpu_probe,
+ .flags = DM_FLAG_ACTIVE_DMA,
+ .priv_auto = sizeof(struct virtio_gpu_priv),
+};
diff --git a/drivers/virtio/virtio_gpu.h b/drivers/virtio/virtio_gpu.h
new file mode 100644
index 000000000000..6732c7218ca2
--- /dev/null
+++ b/drivers/virtio/virtio_gpu.h
@@ -0,0 +1,461 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ * Dave Airlie <airlied@redhat.com>
+ * Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This header is BSD licensed so anyone can use the definitions
+ * to implement compatible drivers/servers:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+
+#include <linux/types.h>
+
+/*
+ * VIRTIO_GPU_CMD_CTX_*
+ * VIRTIO_GPU_CMD_*_3D
+ */
+#define VIRTIO_GPU_F_VIRGL 0
+
+/*
+ * VIRTIO_GPU_CMD_GET_EDID
+ */
+#define VIRTIO_GPU_F_EDID 1
+/*
+ * VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID
+ */
+#define VIRTIO_GPU_F_RESOURCE_UUID 2
+
+/*
+ * VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB
+ */
+#define VIRTIO_GPU_F_RESOURCE_BLOB 3
+/*
+ * VIRTIO_GPU_CMD_CREATE_CONTEXT with
+ * context_init and multiple timelines
+ */
+#define VIRTIO_GPU_F_CONTEXT_INIT 4
+
+enum virtio_gpu_ctrl_type {
+ VIRTIO_GPU_UNDEFINED = 0,
+
+ /* 2d commands */
+ VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+ VIRTIO_GPU_CMD_RESOURCE_UNREF,
+ VIRTIO_GPU_CMD_SET_SCANOUT,
+ VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+ VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+ VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+ VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+ VIRTIO_GPU_CMD_GET_CAPSET,
+ VIRTIO_GPU_CMD_GET_EDID,
+ VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
+ VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,
+
+ /* 3d commands */
+ VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+ VIRTIO_GPU_CMD_CTX_DESTROY,
+ VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+ VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+ VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+ VIRTIO_GPU_CMD_SUBMIT_3D,
+ VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
+ VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
+
+ /* cursor commands */
+ VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+ VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+ /* success responses */
+ VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+ VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET,
+ VIRTIO_GPU_RESP_OK_EDID,
+ VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
+ VIRTIO_GPU_RESP_OK_MAP_INFO,
+
+ /* error responses */
+ VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+ VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+ VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+enum virtio_gpu_shm_id {
+ VIRTIO_GPU_SHM_ID_UNDEFINED = 0,
+ /*
+ * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB
+ * VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB
+ */
+ VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+/*
+ * If the following flag is set, then ring_idx contains the index
+ * of the command ring that needs to used when creating the fence
+ */
+#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1)
+
+struct virtio_gpu_ctrl_hdr {
+ __le32 type;
+ __le32 flags;
+ __le64 fence_id;
+ __le32 ctx_id;
+ __u8 ring_idx;
+ __u8 padding[3];
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos {
+ __le32 scanout_id;
+ __le32 x;
+ __le32 y;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+struct virtio_gpu_update_cursor {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_cursor_pos pos; /* update & move */
+ __le32 resource_id; /* update only */
+ __le32 hot_x; /* update only */
+ __le32 hot_y; /* update only */
+ __le32 padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+struct virtio_gpu_rect {
+ __le32 x;
+ __le32 y;
+ __le32 width;
+ __le32 height;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+struct virtio_gpu_resource_create_2d {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 format;
+ __le32 width;
+ __le32 height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ __le32 scanout_id;
+ __le32 resource_id;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+struct virtio_gpu_transfer_to_host_2d {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ __le64 offset;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+struct virtio_gpu_mem_entry {
+ __le64 addr;
+ __le32 length;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_display_one {
+ struct virtio_gpu_rect r;
+ __le32 enabled;
+ __le32 flags;
+ } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+/* data passed in the control vq, 3d related */
+
+struct virtio_gpu_box {
+ __le32 x, y, z;
+ __le32 w, h, d;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
+struct virtio_gpu_transfer_host_3d {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_box box;
+ __le64 offset;
+ __le32 resource_id;
+ __le32 level;
+ __le32 stride;
+ __le32 layer_stride;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
+#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
+struct virtio_gpu_resource_create_3d {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 target;
+ __le32 format;
+ __le32 bind;
+ __le32 width;
+ __le32 height;
+ __le32 depth;
+ __le32 array_size;
+ __le32 last_level;
+ __le32 nr_samples;
+ __le32 flags;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_CTX_CREATE */
+#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff
+struct virtio_gpu_ctx_create {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 nlen;
+ __le32 context_init;
+ char debug_name[64];
+};
+
+/* VIRTIO_GPU_CMD_CTX_DESTROY */
+struct virtio_gpu_ctx_destroy {
+ struct virtio_gpu_ctrl_hdr hdr;
+};
+
+/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
+struct virtio_gpu_ctx_resource {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_SUBMIT_3D */
+struct virtio_gpu_cmd_submit {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 size;
+ __le32 padding;
+};
+
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+#define VIRTIO_GPU_CAPSET_VIRGL2 2
+#define VIRTIO_GPU_CAPSET_GFXSTREAM_VULKAN 3
+#define VIRTIO_GPU_CAPSET_VENUS 4
+#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
+#define VIRTIO_GPU_CAPSET_DRM 6
+
+/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
+struct virtio_gpu_get_capset_info {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 capset_index;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
+struct virtio_gpu_resp_capset_info {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 capset_id;
+ __le32 capset_max_version;
+ __le32 capset_max_size;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_CMD_GET_CAPSET */
+struct virtio_gpu_get_capset {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 capset_id;
+ __le32 capset_version;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET */
+struct virtio_gpu_resp_capset {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __u8 capset_data[];
+};
+
+/* VIRTIO_GPU_CMD_GET_EDID */
+struct virtio_gpu_cmd_get_edid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 scanout;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_EDID */
+struct virtio_gpu_resp_edid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 size;
+ __le32 padding;
+ __u8 edid[1024];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config {
+ __le32 events_read;
+ __le32 events_clear;
+ __le32 num_scanouts;
+ __le32 num_capsets;
+};
+
+/* simple formats for fbcon/X use */
+enum virtio_gpu_formats {
+ VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
+ VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
+ VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
+ VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
+
+ VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
+ VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
+
+ VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
+ VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+struct virtio_gpu_resource_assign_uuid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */
+struct virtio_gpu_resp_resource_uuid {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __u8 uuid[16];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
+struct virtio_gpu_resource_create_blob {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001
+#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002
+#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003
+
+#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001
+#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002
+#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
+ /* zero is invalid blob mem */
+ __le32 blob_mem;
+ __le32 blob_flags;
+ __le32 nr_entries;
+ __le64 blob_id;
+ __le64 size;
+ /*
+ * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow
+ */
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */
+struct virtio_gpu_set_scanout_blob {
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ __le32 scanout_id;
+ __le32 resource_id;
+ __le32 width;
+ __le32 height;
+ __le32 format;
+ __le32 padding;
+ __le32 strides[4];
+ __le32 offsets[4];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB */
+struct virtio_gpu_resource_map_blob {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+ __le64 offset;
+};
+
+/* VIRTIO_GPU_RESP_OK_MAP_INFO */
+#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f
+#define VIRTIO_GPU_MAP_CACHE_NONE 0x00
+#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01
+#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02
+#define VIRTIO_GPU_MAP_CACHE_WC 0x03
+struct virtio_gpu_resp_map_info {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __u32 map_info;
+ __u32 padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB */
+struct virtio_gpu_resource_unmap_blob {
+ struct virtio_gpu_ctrl_hdr hdr;
+ __le32 resource_id;
+ __le32 padding;
+};
+
+#endif
diff --git a/include/virtio.h b/include/virtio.h
index 3edf023463d7..f53158e355b1 100644
--- a/include/virtio.h
+++ b/include/virtio.h
@@ -28,14 +28,16 @@
#define VIRTIO_VENDOR_QEMU 0x554d4551
-#define VIRTIO_ID_NET 1 /* virtio net */
-#define VIRTIO_ID_BLOCK 2 /* virtio block */
-#define VIRTIO_ID_RNG 4 /* virtio rng */
-#define VIRTIO_ID_MAX_NUM 5
+#define VIRTIO_ID_NET 1 /* virtio net */
+#define VIRTIO_ID_BLOCK 2 /* virtio block */
+#define VIRTIO_ID_RNG 4 /* virtio rng */
+#define VIRTIO_ID_GPU 16 /* virtio gpu */
+#define VIRTIO_ID_MAX_NUM 17
#define VIRTIO_NET_DRV_NAME "virtio-net"
#define VIRTIO_BLK_DRV_NAME "virtio-blk"
#define VIRTIO_RNG_DRV_NAME "virtio-rng"
+#define VIRTIO_GPU_DRV_NAME "virtio-gpu"
/* Status byte for guest to report progress, and synchronize features */
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [RFC PATCH] virtio: Add driver for virtio gpu
2026-05-23 5:50 [RFC PATCH] virtio: Add driver for virtio gpu Daniel Palmer
@ 2026-05-23 9:31 ` Simon Glass
2026-05-26 6:10 ` Kuan-Wei Chiu
1 sibling, 0 replies; 4+ messages in thread
From: Simon Glass @ 2026-05-23 9:31 UTC (permalink / raw)
To: daniel; +Cc: bmeng.cn, sjg, visitorckw, u-boot
Hi Daniel,
On 2026-05-23T05:50:00, Daniel Palmer <daniel@thingy.jp> wrote:
> virtio: Add driver for virtio gpu
>
> Add a basic driver for virtio gpu. This allows for a video on
> qemu virt machines.
>
> Signed-off-by: Daniel Palmer <daniel@thingy.jp>
>
> drivers/virtio/Kconfig | 19 ++
> drivers/virtio/Makefile | 1 +
> drivers/virtio/virtio-uclass.c | 1 +
> drivers/virtio/virtio_gpu.c | 284 +++++++++++++++++++++++++
> drivers/virtio/virtio_gpu.h | 461 +++++++++++++++++++++++++++++++++++++++++
> include/virtio.h | 10 +-
> 6 files changed, 772 insertions(+), 4 deletions(-)
Thanks for doing this!
> diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
> @@ -0,0 +1,284 @@
> +U_BOOT_DRIVER(virtio_gpu) = {
> + .name = VIRTIO_GPU_DRV_NAME,
> + .id = UCLASS_VIDEO,
> + .ops = &virtio_gpu_ops,
> + .probe = virtio_gpu_probe,
> + .flags = DM_FLAG_ACTIVE_DMA,
> + .priv_auto = sizeof(struct virtio_gpu_priv),
> +};
Two things are missing here per doc/develop/driver-model/virtio.rst
- a bind() that calls virtio_driver_features_init() for feature negotiation
- a '.remove = virtio_reset' so the device is reset before jumping to
the OS; without it the host may keep scanning out of a buffer U-Boot
has freed.
> diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
> @@ -0,0 +1,284 @@
> + /* virtio GPU apparently doesn't care about alignment */
> + plat->size = (width * height) * 4;
> + plat->base = (ulong)malloc(plat->size);
> + if (!plat->base)
> + return -ENOMEM;
> +
> + ret = virtio_gpu_resource_attach_backing(vq,
> + FRAMEBUFFER_RESOURCE_ID,
> + plat->base,
> + round_up(plat->size, 4096));
The length advertised to the host is round_up(plat->size, 4096) but
only plat->size bytes are allocated, so the host may read past the
end. Allocate the rounded-up size or pass plat->size
More fundamentally, video drivers declare plat->size (and plat->align
if needed) in bind(), and video_reserve() places the framebuffer in
the reserved region below the U-Boot relocation address - see
drivers/video/bochs.c for the standard pattern. So you should not need
the malloc() in probe() ?
> diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
> @@ -77,4 +77,23 @@ config VIRTIO_RNG
> +if VIRTIO_GPU
> +config VIRTIO_DEFAULT_WIDTH
> + int "default width"
> + default 1024
> +
> +config VIRTIO_DEFAULT_HEIGHT
> + int "default height"
> + default 768
> +endif
These sit in the VIRTIO namespace but are GPU-specific - please rename
to VIRTIO_GPU_DEFAULT_WIDTH / VIRTIO_GPU_DEFAULT_HEIGHT
The prompts also do not say what they configure; something like
'Default framebuffer width' would be clearer. BTW, are these ever
used?
> diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
> @@ -0,0 +1,284 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * virtio GPU driver
> + * 2025 Daniel Palmer <daniel@thingy.jp>
> + */
> +
> +#include <dm.h>
> +#include <malloc.h>
> +#include <video.h>
> +#include <virtio_types.h>
> +#include <virtio.h>
> +#include <virtio_ring.h>
Please add #define LOG_CATEGORY UCLASS_VIRTIO at the top - also good
to use log_msg_ret() / log_debug() on the error paths. Several
goto-err paths currently swallow the error silently.
> diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
> @@ -0,0 +1,284 @@
> + while (!virtqueue_get_buf(vq, NULL))
> + ;
> +
> + /* Some basic error handling */
> + switch (le32_to_cpu(resp_hdr->type)) {
> + case VIRTIO_GPU_RESP_ERR_UNSPEC:
> + case VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID:
> + case VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID:
> + case VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID:
> + case VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER:
> + return -EINVAL;
> + case VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY:
> + return -ENOMEM;
> + }
> +
> + return 0;
This returns success for any response not in the listed error codes,
so a future spec error (or garbage) is silently treated as OK. Please
invert the check — require resp_hdr->type to be one of
VIRTIO_GPU_RESP_OK_* and return -EIO otherwise.
> diff --git a/drivers/virtio/virtio_gpu.c b/drivers/virtio/virtio_gpu.c
> @@ -0,0 +1,284 @@
> + virtio: Add driver for virtio gpu
> +
> + Add a basic driver for virtio gpu. This allows for a video on
> + qemu virt machines.
> +
> + Signed-off-by: Daniel Palmer <daniel@thingy.jp>
The commit message is thin. Please mention the motivation (no current
display driver works on QEMU virt for arm64/riscv?), what is and isn't
supported (2D only, single scanout, no cursor, no EDID, no feature
negotiation) and how the user enables it. Also 'allows for a video'
reads oddly - perhaps 'enables video output on QEMU virt machines'.
Regards,
Simon
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFC PATCH] virtio: Add driver for virtio gpu
2026-05-23 5:50 [RFC PATCH] virtio: Add driver for virtio gpu Daniel Palmer
2026-05-23 9:31 ` Simon Glass
@ 2026-05-26 6:10 ` Kuan-Wei Chiu
2026-06-01 14:59 ` Simon Glass
1 sibling, 1 reply; 4+ messages in thread
From: Kuan-Wei Chiu @ 2026-05-26 6:10 UTC (permalink / raw)
To: Daniel Palmer; +Cc: bmeng.cn, sjg, u-boot
Hi Daniel,
On Sat, May 23, 2026 at 02:50:00PM +0900, Daniel Palmer wrote:
> Add a basic driver for virtio gpu. This allows for a video on
> qemu virt machines.
Cool! Thanks for doing this.
I was also planning to look into adding support for some other virtio
drivers, but I've been traveling recently and haven't had the time to
finish them up.
Video drivers aren't really my area of expertise, so my feedback is a
bit limited. I just have one minor comment below:
>
> Signed-off-by: Daniel Palmer <daniel@thingy.jp>
> ---
>
> Since the m68k virtio stuff is now in next I thought I'd send this.
> This patch is based on next.
>
> This is a very simple driver for virtio gpu that works just enough
> to create a framebuffer that u-boot can use.
>
> I've been playing with this on m68k and its shown that some of the
> framebuffer code has some endian issues.
>
> I think this is useful for testing the framebuffer code on other
> arches like arm, riscv and so on.
>
> Open to comments, ideas etc.
>
> +static int virtio_gpu_resource_create_2d(struct virtqueue *vq,
> + u32 resource_id,
> + u32 format,
> + u32 width,
> + u32 height)
> +{
> + struct virtio_gpu_resource_create_2d req = {
> + .hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D),
> + .resource_id = cpu_to_le32(resource_id),
> + .format = cpu_to_le32(format),
> + .width = cpu_to_le32(width),
> + .height = cpu_to_le32(height),
> + };
> + struct virtio_gpu_ctrl_hdr resp;
> +
> + return virtio_gpu_cmd(vq, &req, sizeof(req), &resp, sizeof(resp));
IIUC, req and resp here are used as dma buffers. I'm not sure if it's
safe to allocate them on the stack. Are there alignment requirements
for them?
Regards,
Kuan-Wei
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFC PATCH] virtio: Add driver for virtio gpu
2026-05-26 6:10 ` Kuan-Wei Chiu
@ 2026-06-01 14:59 ` Simon Glass
0 siblings, 0 replies; 4+ messages in thread
From: Simon Glass @ 2026-06-01 14:59 UTC (permalink / raw)
To: Kuan-Wei Chiu; +Cc: Daniel Palmer, bmeng.cn, u-boot
Hi Kuan-Wei,
On Tue, 26 May 2026 at 08:10, Kuan-Wei Chiu <visitorckw@gmail.com> wrote:
>
> Hi Daniel,
>
> On Sat, May 23, 2026 at 02:50:00PM +0900, Daniel Palmer wrote:
> > Add a basic driver for virtio gpu. This allows for a video on
> > qemu virt machines.
>
> Cool! Thanks for doing this.
>
> I was also planning to look into adding support for some other virtio
> drivers, but I've been traveling recently and haven't had the time to
> finish them up.
That's great! Let's coordinate a bit - I have virtio-scsi and virtiofs
locally - I just send a precursor series with a sandbox emulator too.
[..]
Regards,
Simon
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-06-01 14:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-23 5:50 [RFC PATCH] virtio: Add driver for virtio gpu Daniel Palmer
2026-05-23 9:31 ` Simon Glass
2026-05-26 6:10 ` Kuan-Wei Chiu
2026-06-01 14:59 ` Simon Glass
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.