* [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads
@ 2026-09-17 10:25 Honglei Huang
2026-09-17 10:25 ` [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Honglei Huang @ 2026-09-17 10:25 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel
Hello,
This series adds virtio-gpu userptr support for ROCm native compute
contexts. The guest kernel pins an existing userspace mapping with
FOLL_LONGTERM and exposes it to the host as ordinary CREATE_BLOB
backing entries, avoiding a second shmem allocation and memcpy.
USE_USERPTR and USERPTR_RDONLY are guest-only DRM ioctl selectors.
They are not added to virtio_gpu.h; the device does not need a new
wire flag.
Patches overview:
1. Add VIRTIO_GPU_CAPSET_ROCM capability for compute workloads
2. Extend DRM UAPI with guest-only userptr flags and userptr field
3. Implement core userptr functionality with page management
4. Wire blob ioctl creation to userptr objects
Tests:
- Full OPENCL CTS tests passed on ROCm 5.7.0 in V2000 platform.
- Near 70% percentage of OPENCL CTS tests passed on ROCm 7.0 W7900 platform.
- most HIP catch tests passed on ROCm 7.0 W7900 platform.
- Some AI applications enabled on ROCm 7.0 W7900 platform.
- latest ROCm 7.14 and ROCm 10 testing is ongoing.
V6 changes:
- Rebase onto drm-misc-next
- Keep USE_USERPTR / USERPTR_RDONLY as guest-only DRM flags; drop the
virtio wire-header patch (5 patches down to 4)
- Fix userptr lifetime, DMA mapping, memlock accounting, alignment
checks, and PRIME SG export
- Updated corresponding cover letter and commit messages
V5 changes:
- Add VIRTIO_GPU_BLOB_FLAG_USERPTR_RDONLY definition to patch 2
- Dropped unused VIRTIO_GPU_F_RESOURCE_USERPTR feature bit in patch 2
- Included VIRTIO_GPU_BLOB_FLAG_USERPTR_RDONLY in VIRTGPU_BLOB_FLAG_USE_MASK in patch 5
- Add check for userptr feature in patch 5 before creating userptr blob resource
- Updated corresponding cover letter and commit messages
V4 changes:
- Renamed VIRTIO_GPU_CAPSET_HSAKMT to VIRTIO_GPU_CAPSET_ROCM
- Remove userptr feature probing cause it can reuse the guest
blob resource code path, reduce patch count from 6 to 5
- Updated corresponding commit messages
- Consolidated userptr feature detection in final patch
- Update corresponding cover letter content
V3 changes:
- Split into focused patches for easier review
- Removed complex interval tree userptr management
- Simplified resource creation without deduplication
- Added VIRTGPU_PARAM_RESOURCE_USERPTR for feature detection
- Improved UAPI documentation and error handling
- Enhanced code quality with proper cleanup paths
- Removed MMU notifier dependencies for simplicity
- Fixed resource lifecycle management issues
V2: - Split add HSAKMT context and blob userptr resource to two patches.
- Remove MMU notifier related patches, cause use not moveable user space
memory with MMU notifier is not a good idea.
- Remove HSAKMT context check when create context, let all the context
support the userptr feature.
- Remove MMU notifier related content in cover letter.
- Add more comments for patch 6 in cover letter.
Previous version:
https://lore.kernel.org/dri-devel/20260116083808.325180-1-honglei1.huang@amd.com/
Honglei Huang (4):
drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
drm/virtgpu api: add blob userptr resource
drm/virtio: implement userptr support for zero-copy memory access
drm/virtio: wire blob ioctl creation to userptr objects
drivers/gpu/drm/virtio/Makefile | 3 +-
drivers/gpu/drm/virtio/virtgpu_drv.h | 36 +++
drivers/gpu/drm/virtio/virtgpu_ioctl.c | 20 +-
drivers/gpu/drm/virtio/virtgpu_object.c | 10 +
drivers/gpu/drm/virtio/virtgpu_userptr.c | 323 +++++++++++++++++++++++
include/uapi/drm/virtgpu_drm.h | 10 +
include/uapi/linux/virtio_gpu.h | 1 +
7 files changed, 400 insertions(+), 3 deletions(-)
create mode 100644 drivers/gpu/drm/virtio/virtgpu_userptr.c
base-commit: 766bfba0f3bae329f99b42dcabc3ef11fa368f0b
--
2.34.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
2026-09-17 10:25 [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads Honglei Huang
@ 2026-09-17 10:25 ` Honglei Huang
2026-09-17 10:33 ` sashiko-bot
2026-09-17 10:25 ` [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource Honglei Huang
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Honglei Huang @ 2026-09-17 10:25 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel
Add a new GPU capability set VIRTIO_GPU_CAPSET_ROCM to support
ROCm compute workloads in virtualized environments.
ROCm (Radeon Open Compute) is AMD's open-source software platform
for GPU compute and HPC workloads.
Signed-off-by: Honglei Huang <honghuan@amd.com>
---
include/uapi/linux/virtio_gpu.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h
index 4f530d9005..3d4dfadc9d 100644
--- a/include/uapi/linux/virtio_gpu.h
+++ b/include/uapi/linux/virtio_gpu.h
@@ -321,6 +321,7 @@ struct virtio_gpu_cmd_submit {
#define VIRTIO_GPU_CAPSET_VENUS 4
#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
#define VIRTIO_GPU_CAPSET_DRM 6
+#define VIRTIO_GPU_CAPSET_ROCM 8
/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
struct virtio_gpu_get_capset_info {
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource
2026-09-17 10:25 [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads Honglei Huang
2026-09-17 10:25 ` [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
@ 2026-09-17 10:25 ` Honglei Huang
2026-09-17 10:34 ` sashiko-bot
2026-09-17 10:25 ` [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access Honglei Huang
2026-09-17 10:25 ` [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang
3 siblings, 1 reply; 13+ messages in thread
From: Honglei Huang @ 2026-09-17 10:25 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel
From: Honglei Huang <Honglei1.Huang@amd.com>
Add DRM ioctl flags and a userptr address field so userspace can
request a blob backed by an existing process mapping.
UAPI changes:
- Add guest-only VIRTGPU_BLOB_FLAG_USE_USERPTR and
VIRTGPU_BLOB_FLAG_USERPTR_RDONLY flags
- Add a userptr field to drm_virtgpu_resource_create_blob
These flags select guest pin behavior in the ioctl. They are not
part of the virtio CREATE_BLOB wire ABI.
Signed-off-by: Honglei Huang <Honglei1.Huang@amd.com>
---
include/uapi/drm/virtgpu_drm.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h
index 95587e12ae..6171b4e230 100644
--- a/include/uapi/drm/virtgpu_drm.h
+++ b/include/uapi/drm/virtgpu_drm.h
@@ -186,6 +186,9 @@ struct drm_virtgpu_resource_create_blob {
#define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001
#define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002
#define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
+/* Guest-only flags */
+#define VIRTGPU_BLOB_FLAG_USE_USERPTR 0x0008
+#define VIRTGPU_BLOB_FLAG_USERPTR_RDONLY 0x0010
/* zero is invalid blob_mem */
__u32 blob_mem;
__u32 blob_flags;
@@ -205,6 +208,13 @@ struct drm_virtgpu_resource_create_blob {
#define DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING 0x0001
__u32 blob_hints;
__u32 pad2;
+
+ /*
+ * userptr: guest userspace memory address for VIRTGPU_BLOB_FLAG_USE_USERPTR.
+ * Must be 0 if VIRTGPU_BLOB_FLAG_USE_USERPTR is not set.
+ * The driver will pin the user pages and allow the host to access them.
+ */
+ __u64 userptr;
};
#define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access
2026-09-17 10:25 [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads Honglei Huang
2026-09-17 10:25 ` [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
2026-09-17 10:25 ` [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource Honglei Huang
@ 2026-09-17 10:25 ` Honglei Huang
2026-09-17 10:38 ` sashiko-bot
2026-09-17 10:25 ` [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang
3 siblings, 1 reply; 13+ messages in thread
From: Honglei Huang @ 2026-09-17 10:25 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel
From: Honglei Huang <Honglei1.Huang@amd.com>
Add userptr blob objects so the guest kernel can pin an existing
userspace mapping and advertise it as CREATE_BLOB backing entries.
- New virtio_gpu_object_userptr type for userptr resources
- Pin pages with pin_user_pages_fast() and FOLL_LONGTERM
- Charge FOLL_LONGTERM pins against RLIMIT_MEMLOCK
- DMA-map the scatterlist and pass DMA addresses when the virtio
DMA API is required
- Keep pages pinned until RESOURCE_UNREF is queued; drop them from
cleanup_object() on the unref response or on create failure
- Reject unaligned or overflowing userptr ranges at create time
- Return a fresh SG table from PRIME export
Signed-off-by: Honglei Huang <Honglei1.Huang@amd.com>
---
drivers/gpu/drm/virtio/Makefile | 3 +-
drivers/gpu/drm/virtio/virtgpu_drv.h | 36 +++
drivers/gpu/drm/virtio/virtgpu_object.c | 10 +
drivers/gpu/drm/virtio/virtgpu_userptr.c | 323 +++++++++++++++++++++++
4 files changed, 371 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/virtio/virtgpu_userptr.c
diff --git a/drivers/gpu/drm/virtio/Makefile b/drivers/gpu/drm/virtio/Makefile
index d2e1788a82..fe7332a621 100644
--- a/drivers/gpu/drm/virtio/Makefile
+++ b/drivers/gpu/drm/virtio/Makefile
@@ -6,6 +6,7 @@
virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_gem.o virtgpu_vram.o \
virtgpu_display.o virtgpu_vq.o \
virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \
- virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o virtgpu_submit.o
+ virtgpu_ioctl.o virtgpu_prime.o virtgpu_trace_points.o virtgpu_submit.o \
+ virtgpu_userptr.o
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 9df4c71173..42869b7d57 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -105,6 +105,7 @@ struct virtio_gpu_object_params {
uint32_t blob_flags;
uint64_t blob_id;
uint32_t blob_hints;
+ uint64_t userptr;
};
struct virtio_gpu_object {
@@ -138,12 +139,41 @@ struct virtio_gpu_object_vram {
struct drm_mm_node vram_node;
};
+struct virtio_gpu_object_userptr;
+
+struct virtio_gpu_object_userptr_ops {
+ int (*get_pages)(struct virtio_gpu_object_userptr *userptr);
+ void (*put_pages)(struct virtio_gpu_object_userptr *userptr);
+};
+
+struct virtio_gpu_object_userptr {
+ struct virtio_gpu_object base;
+ const struct virtio_gpu_object_userptr_ops *ops;
+ /* Protects pages and sgt. */
+ struct mutex lock;
+
+ uint64_t start;
+ uint32_t npages;
+ uint32_t bo_handle;
+ uint32_t flags;
+
+ struct virtio_gpu_device *vgdev;
+ struct drm_file *file;
+ struct page **pages;
+ struct sg_table *sgt;
+ bool dma_mapped;
+ struct mm_struct *mm;
+};
+
#define to_virtio_gpu_shmem(virtio_gpu_object) \
container_of((virtio_gpu_object), struct virtio_gpu_object_shmem, base)
#define to_virtio_gpu_vram(virtio_gpu_object) \
container_of((virtio_gpu_object), struct virtio_gpu_object_vram, base)
+#define to_virtio_gpu_userptr(virtio_gpu_object) \
+ container_of((virtio_gpu_object), struct virtio_gpu_object_userptr, base)
+
struct virtio_gpu_object_array {
struct ww_acquire_ctx ticket;
struct list_head next;
@@ -562,4 +592,10 @@ void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram);
int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
+/* virtgpu_userptr.c */
+int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev,
+ struct drm_file *file,
+ struct virtio_gpu_object_params *params,
+ struct virtio_gpu_object **bo_ptr);
+bool virtio_gpu_is_userptr(struct virtio_gpu_object *bo);
#endif
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index 49899485be..5c40f5a034 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -91,6 +91,16 @@ void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo)
drm_gem_free_mmap_offset(&vram->base.base.base);
drm_gem_object_release(&vram->base.base.base);
kfree(vram);
+ } else if (virtio_gpu_is_userptr(bo)) {
+ struct virtio_gpu_object_userptr *userptr =
+ to_virtio_gpu_userptr(bo);
+
+ mutex_lock(&userptr->lock);
+ userptr->ops->put_pages(userptr);
+ mutex_unlock(&userptr->lock);
+ mutex_destroy(&userptr->lock);
+ drm_gem_object_release(&userptr->base.base.base);
+ kfree(userptr);
} else {
drm_gem_object_release(&bo->base.base);
kfree(bo);
diff --git a/drivers/gpu/drm/virtio/virtgpu_userptr.c b/drivers/gpu/drm/virtio/virtgpu_userptr.c
new file mode 100644
index 0000000000..7879735e63
--- /dev/null
+++ b/drivers/gpu/drm/virtio/virtgpu_userptr.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/dma-mapping.h>
+#include <linux/limits.h>
+#include <linux/mm.h>
+#include <linux/overflow.h>
+#include <linux/pid.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/signal.h>
+#include <linux/vmalloc.h>
+
+#include "virtgpu_drv.h"
+#include <drm/drm_gem.h>
+#include <drm/drm_prime.h>
+
+static struct sg_table *
+virtio_gpu_userptr_get_sg_table(struct drm_gem_object *obj);
+
+static void virtio_gpu_userptr_free(struct drm_gem_object *obj)
+{
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_device *vgdev = obj->dev->dev_private;
+
+ /*
+ * Keep pages pinned until RESOURCE_UNREF completes. The response
+ * callback calls virtio_gpu_cleanup_object(), which drops them.
+ */
+ if (bo->created) {
+ virtio_gpu_remove_from_restore_list(bo);
+ virtio_gpu_cmd_unref_resource(vgdev, bo, false);
+ virtio_gpu_notify(vgdev);
+ return;
+ }
+
+ virtio_gpu_cleanup_object(bo);
+}
+
+static const struct drm_gem_object_funcs virtio_gpu_userptr_funcs = {
+ .open = virtio_gpu_gem_object_open,
+ .close = virtio_gpu_gem_object_close,
+ .free = virtio_gpu_userptr_free,
+ .export = virtgpu_gem_prime_export,
+ .get_sg_table = virtio_gpu_userptr_get_sg_table,
+};
+
+bool virtio_gpu_is_userptr(struct virtio_gpu_object *bo)
+{
+ return bo->base.base.funcs == &virtio_gpu_userptr_funcs;
+}
+
+static int
+virtio_gpu_userptr_get_pages(struct virtio_gpu_object_userptr *userptr)
+{
+ unsigned int flag = FOLL_LONGTERM;
+ unsigned int num_pages, pinned = 0;
+ int ret = 0;
+
+ if (userptr->pages)
+ return 0;
+
+ userptr->pages = kvmalloc_array(userptr->npages, sizeof(struct page *),
+ GFP_KERNEL);
+ if (!userptr->pages)
+ return -ENOMEM;
+
+ if (!(userptr->flags & VIRTGPU_BLOB_FLAG_USERPTR_RDONLY))
+ flag |= FOLL_WRITE;
+
+ do {
+ num_pages = userptr->npages - pinned;
+
+ ret = pin_user_pages_fast(userptr->start + pinned * PAGE_SIZE,
+ num_pages, flag,
+ userptr->pages + pinned);
+
+ if (ret < 0) {
+ if (pinned)
+ unpin_user_pages(userptr->pages, pinned);
+ kvfree(userptr->pages);
+ return ret;
+ }
+
+ pinned += ret;
+
+ } while (pinned < userptr->npages);
+
+ return 0;
+}
+
+static void
+virtio_gpu_userptr_unaccount(struct virtio_gpu_object_userptr *userptr)
+{
+ if (!userptr->mm)
+ return;
+
+ atomic64_sub(userptr->npages, &userptr->mm->pinned_vm);
+ mmdrop(userptr->mm);
+ userptr->mm = NULL;
+}
+
+static void
+virtio_gpu_userptr_put_pages(struct virtio_gpu_object_userptr *userptr)
+{
+ struct drm_device *dev = userptr->base.base.base.dev;
+
+ if (userptr->sgt) {
+ if (userptr->dma_mapped)
+ dma_unmap_sgtable(drm_dev_dma_dev(dev), userptr->sgt,
+ DMA_BIDIRECTIONAL, 0);
+ userptr->dma_mapped = false;
+ sg_free_table(userptr->sgt);
+ kfree(userptr->sgt);
+ userptr->sgt = NULL;
+ }
+
+ if (userptr->pages) {
+ unpin_user_pages(userptr->pages, userptr->npages);
+ kvfree(userptr->pages);
+ userptr->pages = NULL;
+ }
+
+ virtio_gpu_userptr_unaccount(userptr);
+}
+
+static int
+virtio_gpu_userptr_get_entries(struct virtio_gpu_device *vgdev,
+ struct virtio_gpu_object_userptr *userptr,
+ struct virtio_gpu_mem_entry **ents,
+ unsigned int *nents)
+{
+ bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
+ struct scatterlist *sg;
+ unsigned int count;
+ int si;
+
+ count = use_dma_api ? userptr->sgt->nents : userptr->sgt->orig_nents;
+ if (!count)
+ return -EINVAL;
+
+ *ents = kvmalloc_array(count, sizeof(**ents), GFP_KERNEL);
+ if (!*ents)
+ return -ENOMEM;
+
+ if (use_dma_api) {
+ for_each_sgtable_dma_sg(userptr->sgt, sg, si) {
+ (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg));
+ (*ents)[si].length = cpu_to_le32(sg_dma_len(sg));
+ (*ents)[si].padding = 0;
+ }
+ } else {
+ for_each_sgtable_sg(userptr->sgt, sg, si) {
+ (*ents)[si].addr = cpu_to_le64(sg_phys(sg));
+ (*ents)[si].length = cpu_to_le32(sg->length);
+ (*ents)[si].padding = 0;
+ }
+ }
+
+ *nents = count;
+ return 0;
+}
+
+static struct sg_table *
+virtio_gpu_userptr_get_sg_table(struct drm_gem_object *obj)
+{
+ struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
+ struct virtio_gpu_object_userptr *userptr = to_virtio_gpu_userptr(bo);
+ int ret;
+
+ mutex_lock(&userptr->lock);
+ if (!userptr->pages) {
+ ret = userptr->ops->get_pages(userptr);
+ if (ret) {
+ mutex_unlock(&userptr->lock);
+ return ERR_PTR(ret);
+ }
+ }
+ mutex_unlock(&userptr->lock);
+
+ /* PRIME takes ownership of the returned table. */
+ return drm_prime_pages_to_sg(obj->dev, userptr->pages, userptr->npages);
+}
+
+static int
+virtio_gpu_userptr_init(struct drm_device *dev, struct drm_file *file,
+ struct virtio_gpu_object_userptr *userptr,
+ struct virtio_gpu_object_params *params,
+ const struct virtio_gpu_object_userptr_ops *ops)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ userptr->start = params->userptr;
+ userptr->npages = params->size >> PAGE_SHIFT;
+ userptr->flags = params->blob_flags;
+
+ mutex_init(&userptr->lock);
+ userptr->vgdev = dev->dev_private;
+ userptr->file = file;
+ userptr->ops = ops;
+
+ /*
+ * Allocate the resource id before GEM init so a failure here can
+ * unwind with a plain kfree and does not need a special id=0 guard
+ * in the shared resource_id_put helper.
+ */
+ ret = virtio_gpu_resource_id_get(userptr->vgdev,
+ &userptr->base.hw_res_handle);
+ if (ret) {
+ mutex_destroy(&userptr->lock);
+ return ret;
+ }
+
+ obj = &userptr->base.base.base;
+ obj->funcs = &virtio_gpu_userptr_funcs;
+
+ drm_gem_private_object_init(dev, obj, params->size);
+ INIT_LIST_HEAD(&userptr->base.restore_node);
+
+ return 0;
+}
+
+static const struct virtio_gpu_object_userptr_ops virtio_gpu_userptr_ops = {
+ .get_pages = virtio_gpu_userptr_get_pages,
+ .put_pages = virtio_gpu_userptr_put_pages,
+};
+
+int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev,
+ struct drm_file *file,
+ struct virtio_gpu_object_params *params,
+ struct virtio_gpu_object **bo_ptr)
+{
+ struct virtio_gpu_object_userptr *userptr;
+ struct virtio_gpu_mem_entry *ents = NULL;
+ struct sg_table *sgt;
+ struct mm_struct *mm;
+ unsigned long lock_limit;
+ unsigned long start;
+ unsigned long end;
+ s64 new_pinned;
+ unsigned int nents;
+ int ret;
+
+ *bo_ptr = NULL;
+
+ if (!params->size || !IS_ALIGNED(params->size, PAGE_SIZE) ||
+ params->userptr != (unsigned long)params->userptr)
+ return -EINVAL;
+
+ start = params->userptr;
+ if (!IS_ALIGNED(start, PAGE_SIZE) ||
+ check_add_overflow(start, (unsigned long)params->size, &end))
+ return -EINVAL;
+
+ if (!can_do_mlock())
+ return -EPERM;
+
+ if (params->size >> PAGE_SHIFT > INT_MAX)
+ return -E2BIG;
+
+ if (!access_ok((void __user *)start, params->size))
+ return -EFAULT;
+
+ userptr = kzalloc_obj(*userptr);
+ if (!userptr)
+ return -ENOMEM;
+
+ ret = virtio_gpu_userptr_init(vgdev->ddev, file, userptr, params,
+ &virtio_gpu_userptr_ops);
+ if (ret) {
+ kfree(userptr);
+ return ret;
+ }
+
+ mm = current->mm;
+ mmgrab(mm);
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ new_pinned = atomic64_add_return(userptr->npages, &mm->pinned_vm);
+ if (new_pinned < 0 ||
+ (new_pinned > lock_limit && !capable(CAP_IPC_LOCK))) {
+ atomic64_sub(userptr->npages, &mm->pinned_vm);
+ mmdrop(mm);
+ ret = new_pinned < 0 ? -EOVERFLOW : -ENOMEM;
+ goto err_cleanup;
+ }
+ userptr->mm = mm;
+
+ mutex_lock(&userptr->lock);
+ ret = userptr->ops->get_pages(userptr);
+ mutex_unlock(&userptr->lock);
+ if (ret)
+ goto err_cleanup;
+
+ sgt = drm_prime_pages_to_sg(vgdev->ddev, userptr->pages,
+ userptr->npages);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto err_cleanup;
+ }
+
+ ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt,
+ DMA_BIDIRECTIONAL, 0);
+ if (ret) {
+ sg_free_table(sgt);
+ kfree(sgt);
+ goto err_cleanup;
+ }
+
+ userptr->sgt = sgt;
+ userptr->dma_mapped = true;
+
+ ret = virtio_gpu_userptr_get_entries(vgdev, userptr, &ents, &nents);
+ if (ret)
+ goto err_cleanup;
+
+ virtio_gpu_cmd_resource_create_blob(vgdev, &userptr->base, params, ents,
+ nents);
+
+ *bo_ptr = &userptr->base;
+ return 0;
+
+err_cleanup:
+ virtio_gpu_cleanup_object(&userptr->base);
+ return ret;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects
2026-09-17 10:25 [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads Honglei Huang
` (2 preceding siblings ...)
2026-09-17 10:25 ` [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access Honglei Huang
@ 2026-09-17 10:25 ` Honglei Huang
2026-09-17 10:38 ` sashiko-bot
3 siblings, 1 reply; 13+ messages in thread
From: Honglei Huang @ 2026-09-17 10:25 UTC (permalink / raw)
To: Dmitry Osipenko, Akihiko Odaki, David Airlie, Gerd Hoffmann
Cc: Gurchetan Singh, Chia-I Wu, Ray Huang, dri-devel, virtualization,
linux-kernel
From: Honglei Huang <Honglei1.Huang@amd.com>
Integrate userptr into the blob resource creation ioctl.
- Include VIRTGPU_BLOB_FLAG_USE_USERPTR and
VIRTGPU_BLOB_FLAG_USERPTR_RDONLY in VIRTGPU_BLOB_FLAG_USE_MASK
- Require userptr if and only if USE_USERPTR is set
- Pass the userspace address into the internal create params
- Call virtio_gpu_userptr_create() for userptr blob requests
Signed-off-by: Honglei Huang <Honglei1.Huang@amd.com>
---
drivers/gpu/drm/virtio/virtgpu_ioctl.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index 3d8e4ccdb7..616d248b3d 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -36,7 +36,9 @@
#define VIRTGPU_BLOB_FLAG_USE_MASK (VIRTGPU_BLOB_FLAG_USE_MAPPABLE | \
VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \
- VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE)
+ VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE | \
+ VIRTGPU_BLOB_FLAG_USE_USERPTR | \
+ VIRTGPU_BLOB_FLAG_USERPTR_RDONLY)
/* Must be called with &virtio_gpu_fpriv.struct_mutex held. */
static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev,
@@ -458,6 +460,17 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
return -EINVAL;
}
+ if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_USERPTR) {
+ if (!rc_blob->userptr)
+ return -EINVAL;
+ } else {
+ if (rc_blob->userptr)
+ return -EINVAL;
+
+ if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USERPTR_RDONLY)
+ return -EINVAL;
+ }
+
switch (rc_blob->blob_mem) {
case VIRTGPU_BLOB_MEM_GUEST:
*guest_blob = true;
@@ -495,6 +508,7 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
params->blob = true;
params->blob_flags = rc_blob->blob_flags;
params->blob_hints = rc_blob->blob_hints;
+ params->userptr = rc_blob->userptr;
if (vgdev->has_blob_alignment &&
!IS_ALIGNED(params->size, vgdev->blob_alignment))
@@ -538,8 +552,10 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
vfpriv->ctx_id, NULL, NULL);
}
- if (guest_blob)
+ if (guest_blob && !params.userptr)
ret = virtio_gpu_object_create(vgdev, ¶ms, &bo, NULL);
+ else if (guest_blob && params.userptr)
+ ret = virtio_gpu_userptr_create(vgdev, file, ¶ms, &bo);
else if (!guest_blob && host3d_blob)
ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo);
else
--
2.34.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
2026-09-17 10:25 ` [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
@ 2026-09-17 10:33 ` sashiko-bot
2026-09-17 10:40 ` Huang, Honglei1
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-09-17 10:33 UTC (permalink / raw)
To: Honglei Huang
Cc: Michael S. Tsirkin, virtualization, Eugenio Perez, dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] uapi: VIRTIO_GPU_CAPSET_ROCM defines unstandardized capset ID 8
--
commit ddbf02d8a1557a4976371db4a94be88bc1f7052f
Author: Honglei Huang <honghuan@amd.com>
drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
This commit adds a new GPU capability set VIRTIO_GPU_CAPSET_ROCM to the virtio
gpu UAPI header to support ROCm compute workloads in virtualized environments.
> diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h
> index 4f530d90058c7..3d4dfadc9d789 100644
> --- a/include/uapi/linux/virtio_gpu.h
> +++ b/include/uapi/linux/virtio_gpu.h
> @@ -321,6 +321,7 @@ struct virtio_gpu_cmd_submit {
> #define VIRTIO_GPU_CAPSET_VENUS 4
> #define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
> #define VIRTIO_GPU_CAPSET_DRM 6
> +#define VIRTIO_GPU_CAPSET_ROCM 8
[Severity: Medium]
Does allocating this ID without specification standardization risk permanent ABI
collisions?
If the virtio standard later assigns ID 8 to another capability, this UAPI
addition could cause a conflict. Furthermore, skipping ID 7 leaves an
undocumented gap that might conflict with virtio standardization protocols.
Has ID 8 been allocated in the upstream virtio specification?
>
> /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
> struct virtio_gpu_get_capset_info {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource
2026-09-17 10:25 ` [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource Honglei Huang
@ 2026-09-17 10:34 ` sashiko-bot
2026-09-17 10:42 ` Huang, Honglei1
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-09-17 10:34 UTC (permalink / raw)
To: Honglei Huang
Cc: Michael S. Tsirkin, dri-devel, virtualization, Eugenio Perez
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] virtio-gpu: guest-only blob flags leaked to host breaking wire ABI
--
commit ce150cb1a68528e491d40b28c03376311a653c0c
Author: Honglei Huang <Honglei1.Huang@amd.com>
drm/virtgpu api: add blob userptr resource
This commit adds DRM ioctl flags and a userptr field to allow userspace
to request a blob backed by an existing process mapping. It introduces
guest-only flags VIRTGPU_BLOB_FLAG_USE_USERPTR and
VIRTGPU_BLOB_FLAG_USERPTR_RDONLY for guest pin behavior.
> diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h
> index 95587e12aed57..6171b4e2300b1 100644
> --- a/include/uapi/drm/virtgpu_drm.h
> +++ b/include/uapi/drm/virtgpu_drm.h
> @@ -186,6 +186,9 @@ struct drm_virtgpu_resource_create_blob {
> #define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001
> #define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002
> #define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
> +/* Guest-only flags */
> +#define VIRTGPU_BLOB_FLAG_USE_USERPTR 0x0008
> +#define VIRTGPU_BLOB_FLAG_USERPTR_RDONLY 0x0010
[Severity: High]
Do these guest-only flags leak to the host and break the virtio wire ABI?
When userspace calls the DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB ioctl,
verify_blob() assigns rc_blob->blob_flags directly to params->blob_flags.
This struct is passed to virtio_gpu_userptr_create(), which calls
virtio_gpu_cmd_resource_create_blob().
In virtio_gpu_cmd_resource_create_blob(), the flags are written directly to
the command without masking:
drivers/gpu/drm/virtio/virtgpu_vq.c:virtio_gpu_cmd_resource_create_blob() {
...
cmd_p->blob_flags = cpu_to_le32(params->blob_flags);
...
}
If these guest-only flags are not masked out before being sent to the host,
will strict hosts reject the command with an error, making the userptr
feature unusable?
I noticed this wire ABI violation appears to remain unfixed at the end of
the patch series (commit 357076bf581c).
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access
2026-09-17 10:25 ` [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access Honglei Huang
@ 2026-09-17 10:38 ` sashiko-bot
2026-09-17 10:43 ` Huang, Honglei1
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-09-17 10:38 UTC (permalink / raw)
To: Honglei Huang
Cc: virtualization, dri-devel, Eugenio Perez, Michael S. Tsirkin
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] drm/virtio: missing pointer clear in virtio_gpu_userptr_get_pages()
- [Critical] drm/virtio: unconditional dma_map_sgtable() causes data corruption
--
commit 6e836cf8f7dd384050e500d6dbf47a69c2767c26
Author: Honglei Huang <Honglei1.Huang@amd.com>
Subject: drm/virtio: implement userptr support for zero-copy memory access
This commit adds userptr blob objects so the guest kernel can pin an existing
userspace mapping and advertise it as CREATE_BLOB backing entries. It pins
pages using pin_user_pages_fast() and maps the scatterlist for the device.
> diff --git a/drivers/gpu/drm/virtio/virtgpu_userptr.c b/drivers/gpu/drm/virtio/virtgpu_userptr.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/gpu/drm/virtio/virtgpu_userptr.c
> @@ -0,0 +1,323 @@
[ ... ]
> +static int
> +virtio_gpu_userptr_get_pages(struct virtio_gpu_object_userptr *userptr)
> +{
[ ... ]
> + ret = pin_user_pages_fast(userptr->start + pinned * PAGE_SIZE,
> + num_pages, flag,
> + userptr->pages + pinned);
> +
> + if (ret < 0) {
> + if (pinned)
> + unpin_user_pages(userptr->pages, pinned);
> + kvfree(userptr->pages);
> + return ret;
> + }
[Severity: Critical]
Does this error path leave a dangling pointer? The userptr->pages array is
freed here but not set to NULL.
If pin_user_pages_fast() fails, this bubbles up to virtio_gpu_userptr_create()
which jumps to err_cleanup and calls virtio_gpu_cleanup_object(). That
function ultimately invokes virtio_gpu_userptr_put_pages():
if (userptr->pages) {
unpin_user_pages(userptr->pages, userptr->npages);
kvfree(userptr->pages);
userptr->pages = NULL;
}
Because userptr->pages wasn't cleared, won't this result in a use-after-free
and double-free when the cleanup function executes?
[ ... ]
> +static int
> +virtio_gpu_userptr_get_entries(struct virtio_gpu_device *vgdev,
> + struct virtio_gpu_object_userptr *userptr,
> + struct virtio_gpu_mem_entry **ents,
> + unsigned int *nents)
> +{
> + bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
[ ... ]
> + if (use_dma_api) {
> + for_each_sgtable_dma_sg(userptr->sgt, sg, si) {
> + (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg));
> + (*ents)[si].length = cpu_to_le32(sg_dma_len(sg));
> + (*ents)[si].padding = 0;
> + }
> + } else {
> + for_each_sgtable_sg(userptr->sgt, sg, si) {
> + (*ents)[si].addr = cpu_to_le64(sg_phys(sg));
> + (*ents)[si].length = cpu_to_le32(sg->length);
> + (*ents)[si].padding = 0;
> + }
> + }
[ ... ]
> +int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev,
> + struct drm_file *file,
> + struct virtio_gpu_object_params *params,
> + struct virtio_gpu_object **bo_ptr)
> +{
[ ... ]
> + sgt = drm_prime_pages_to_sg(vgdev->ddev, userptr->pages,
> + userptr->npages);
> + if (IS_ERR(sgt)) {
> + ret = PTR_ERR(sgt);
> + goto err_cleanup;
> + }
> +
> + ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt,
> + DMA_BIDIRECTIONAL, 0);
[Severity: Critical]
Can this unconditional DMA mapping cause silent data corruption?
If the system uses SWIOTLB bounce buffers and the device is configured to
bypass the DMA API, the dma_map_sgtable() call will allocate a bounce buffer.
Later in virtio_gpu_userptr_get_entries(), the code branches based on
virtio_gpu_use_dma_api(), and if false it ignores the DMA address and passes
the raw physical address (sg_phys) to the device.
Since the raw physical address is passed to the device when DMA is bypassed,
the device will write directly to the original physical memory. However,
during cleanup, dma_unmap_sgtable() with DMA_BIDIRECTIONAL will copy the
unmodified bounce buffer back over the original memory. Will this overwrite
and destroy the data written by the device?
> + if (ret) {
> + sg_free_table(sgt);
> + kfree(sgt);
> + goto err_cleanup;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects
2026-09-17 10:25 ` [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang
@ 2026-09-17 10:38 ` sashiko-bot
2026-09-17 10:43 ` Huang, Honglei1
0 siblings, 1 reply; 13+ messages in thread
From: sashiko-bot @ 2026-09-17 10:38 UTC (permalink / raw)
To: Honglei Huang
Cc: Michael S. Tsirkin, virtualization, Eugenio Perez, dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] drm/virtio: double-free and UAF in virtio_gpu_userptr_get_pages error path
- [High] drm/virtio: read-only userptr memory mapped as DMA_BIDIRECTIONAL
- [Medium] drm/virtio: silent fallback to VRAM if userptr is combined with HOST3D
--
commit 357076bf581ca76e53fbe71d8c16da04e304d01c
Author: Honglei Huang <Honglei1.Huang@amd.com>
drm/virtio: wire blob ioctl creation to userptr objects
Integrate userptr into the blob resource creation ioctl.
> diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
[ ... ]
> @@ -458,6 +460,17 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
> return -EINVAL;
> }
>
> + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_USERPTR) {
> + if (!rc_blob->userptr)
> + return -EINVAL;
> + } else {
> + if (rc_blob->userptr)
> + return -EINVAL;
> +
> + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USERPTR_RDONLY)
> + return -EINVAL;
> + }
> +
[Severity: Medium]
Will this silently fall back to VRAM if the user requests a userptr blob but
sets the memory type to VIRTGPU_BLOB_MEM_HOST3D?
If guest_blob is false and host3d_blob is true, the userptr flag is validated
here but it doesn't ensure a guest memory type was requested.
This could allow the execution to fall through into:
virtio_gpu_resource_create_blob_ioctl() {
...
else if (!guest_blob && host3d_blob)
ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo);
...
}
which would silently ignore params.userptr and allocate standard VRAM instead
of returning -EINVAL.
> switch (rc_blob->blob_mem) {
> case VIRTGPU_BLOB_MEM_GUEST:
[ ... ]
> @@ -538,8 +552,10 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
> vfpriv->ctx_id, NULL, NULL);
> }
>
> - if (guest_blob)
> + if (guest_blob && !params.userptr)
> ret = virtio_gpu_object_create(vgdev, ¶ms, &bo, NULL);
> + else if (guest_blob && params.userptr)
> + ret = virtio_gpu_userptr_create(vgdev, file, ¶ms, &bo);
[Severity: Critical]
Does the error path in virtio_gpu_userptr_get_pages() lead to a use-after-free
and double-free when this is called?
If virtio_gpu_userptr_get_pages() enters the error path, it frees the pages
array but leaves a dangling pointer:
virtio_gpu_userptr_get_pages() {
...
if (pinned)
unpin_user_pages(userptr->pages, pinned);
kvfree(userptr->pages);
return ret;
}
The error returned to virtio_gpu_userptr_create() triggers a jump to
err_cleanup and calls virtio_gpu_cleanup_object(), which eventually calls
virtio_gpu_userptr_put_pages():
virtio_gpu_userptr_put_pages() {
if (userptr->pages) {
unpin_user_pages(userptr->pages, userptr->npages);
kvfree(userptr->pages);
userptr->pages = NULL;
}
}
Because the pointer is not NULL, this would unpin and free the already freed
array, potentially corrupting page refcounts and memory.
[Severity: High]
Can a read-only userptr be overwritten by the host device?
When VIRTGPU_BLOB_FLAG_USERPTR_RDONLY is specified, the userptr memory is
pinned without FOLL_WRITE, allowing read-only memory to be pinned. However,
the DMA mapping in virtio_gpu_userptr_create() appears to be hardcoded to
bidirectional:
virtio_gpu_userptr_create() {
...
ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt,
DMA_BIDIRECTIONAL, 0);
...
}
Because it is mapped bidirectionally, the IOMMU allows device writes to these
physical pages. Can unprivileged userspace submit command buffers that
instruct the host device to write into the blob, overwriting the read-only
guest memory? Should this use DMA_TO_DEVICE when USERPTR_RDONLY is set?
> + else if (!guest_blob && host3d_blob)
> + ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo);
> else
> return -EINVAL;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
2026-09-17 10:33 ` sashiko-bot
@ 2026-09-17 10:40 ` Huang, Honglei1
0 siblings, 0 replies; 13+ messages in thread
From: Huang, Honglei1 @ 2026-09-17 10:40 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: Michael S. Tsirkin, virtualization@lists.linux.dev, Eugenio Perez,
dri-devel@lists.freedesktop.org
AMD General
Capset ID 7 is already used by VIRCL in the virgl/virtio-gpu stack
So ROCm use ID 8, and we have created a pr in spec to reserve the ID8
-----Original Message-----
From: sashiko-bot@kernel.org <sashiko-bot@kernel.org>
Sent: Thursday, September 17, 2026 6:34 PM
To: Huang, Honglei1 <Honglei1.Huang@amd.com>
Cc: Michael S. Tsirkin <mst@redhat.com>; virtualization@lists.linux.dev; Eugenio Perez <eperezma@redhat.com>; dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] uapi: VIRTIO_GPU_CAPSET_ROCM defines unstandardized capset ID 8
--
commit ddbf02d8a1557a4976371db4a94be88bc1f7052f
Author: Honglei Huang <honghuan@amd.com>
drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability
This commit adds a new GPU capability set VIRTIO_GPU_CAPSET_ROCM to the virtio gpu UAPI header to support ROCm compute workloads in virtualized environments.
> diff --git a/include/uapi/linux/virtio_gpu.h
> b/include/uapi/linux/virtio_gpu.h index 4f530d90058c7..3d4dfadc9d789
> 100644
> --- a/include/uapi/linux/virtio_gpu.h
> +++ b/include/uapi/linux/virtio_gpu.h
> @@ -321,6 +321,7 @@ struct virtio_gpu_cmd_submit { #define
> VIRTIO_GPU_CAPSET_VENUS 4 #define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
> #define VIRTIO_GPU_CAPSET_DRM 6
> +#define VIRTIO_GPU_CAPSET_ROCM 8
[Severity: Medium]
Does allocating this ID without specification standardization risk permanent ABI collisions?
If the virtio standard later assigns ID 8 to another capability, this UAPI addition could cause a conflict. Furthermore, skipping ID 7 leaves an undocumented gap that might conflict with virtio standardization protocols.
Has ID 8 been allocated in the upstream virtio specification?
>
> /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
> struct virtio_gpu_get_capset_info {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource
2026-09-17 10:34 ` sashiko-bot
@ 2026-09-17 10:42 ` Huang, Honglei1
0 siblings, 0 replies; 13+ messages in thread
From: Huang, Honglei1 @ 2026-09-17 10:42 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: Michael S. Tsirkin, dri-devel@lists.freedesktop.org,
virtualization@lists.linux.dev, Eugenio Perez
AMD General
This part need some input from maintainer, these flags do not seem to have effect on the QEMU side.
-----Original Message-----
From: sashiko-bot@kernel.org <sashiko-bot@kernel.org>
Sent: Thursday, September 17, 2026 6:35 PM
To: Huang, Honglei1 <Honglei1.Huang@amd.com>
Cc: Michael S. Tsirkin <mst@redhat.com>; dri-devel@lists.freedesktop.org; virtualization@lists.linux.dev; Eugenio Perez <eperezma@redhat.com>
Subject: Re: [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] virtio-gpu: guest-only blob flags leaked to host breaking wire ABI
--
commit ce150cb1a68528e491d40b28c03376311a653c0c
Author: Honglei Huang <Honglei1.Huang@amd.com>
drm/virtgpu api: add blob userptr resource
This commit adds DRM ioctl flags and a userptr field to allow userspace to request a blob backed by an existing process mapping. It introduces guest-only flags VIRTGPU_BLOB_FLAG_USE_USERPTR and VIRTGPU_BLOB_FLAG_USERPTR_RDONLY for guest pin behavior.
> diff --git a/include/uapi/drm/virtgpu_drm.h
> b/include/uapi/drm/virtgpu_drm.h index 95587e12aed57..6171b4e2300b1
> 100644
> --- a/include/uapi/drm/virtgpu_drm.h
> +++ b/include/uapi/drm/virtgpu_drm.h
> @@ -186,6 +186,9 @@ struct drm_virtgpu_resource_create_blob {
> #define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001
> #define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002
> #define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
> +/* Guest-only flags */
> +#define VIRTGPU_BLOB_FLAG_USE_USERPTR 0x0008
> +#define VIRTGPU_BLOB_FLAG_USERPTR_RDONLY 0x0010
[Severity: High]
Do these guest-only flags leak to the host and break the virtio wire ABI?
When userspace calls the DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB ioctl,
verify_blob() assigns rc_blob->blob_flags directly to params->blob_flags.
This struct is passed to virtio_gpu_userptr_create(), which calls virtio_gpu_cmd_resource_create_blob().
In virtio_gpu_cmd_resource_create_blob(), the flags are written directly to the command without masking:
drivers/gpu/drm/virtio/virtgpu_vq.c:virtio_gpu_cmd_resource_create_blob() {
...
cmd_p->blob_flags = cpu_to_le32(params->blob_flags);
...
}
If these guest-only flags are not masked out before being sent to the host, will strict hosts reject the command with an error, making the userptr feature unusable?
I noticed this wire ABI violation appears to remain unfixed at the end of the patch series (commit 357076bf581c).
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=2
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access
2026-09-17 10:38 ` sashiko-bot
@ 2026-09-17 10:43 ` Huang, Honglei1
0 siblings, 0 replies; 13+ messages in thread
From: Huang, Honglei1 @ 2026-09-17 10:43 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: virtualization@lists.linux.dev, dri-devel@lists.freedesktop.org,
Eugenio Perez, Michael S. Tsirkin
AMD General
Will fix it and waiting for maintainer's suggestions
-----Original Message-----
From: sashiko-bot@kernel.org <sashiko-bot@kernel.org>
Sent: Thursday, September 17, 2026 6:38 PM
To: Huang, Honglei1 <Honglei1.Huang@amd.com>
Cc: virtualization@lists.linux.dev; dri-devel@lists.freedesktop.org; Eugenio Perez <eperezma@redhat.com>; Michael S. Tsirkin <mst@redhat.com>
Subject: Re: [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] drm/virtio: missing pointer clear in virtio_gpu_userptr_get_pages()
- [Critical] drm/virtio: unconditional dma_map_sgtable() causes data corruption
--
commit 6e836cf8f7dd384050e500d6dbf47a69c2767c26
Author: Honglei Huang <Honglei1.Huang@amd.com>
Subject: drm/virtio: implement userptr support for zero-copy memory access
This commit adds userptr blob objects so the guest kernel can pin an existing userspace mapping and advertise it as CREATE_BLOB backing entries. It pins pages using pin_user_pages_fast() and maps the scatterlist for the device.
> diff --git a/drivers/gpu/drm/virtio/virtgpu_userptr.c
> b/drivers/gpu/drm/virtio/virtgpu_userptr.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/gpu/drm/virtio/virtgpu_userptr.c
> @@ -0,0 +1,323 @@
[ ... ]
> +static int
> +virtio_gpu_userptr_get_pages(struct virtio_gpu_object_userptr
> +*userptr) {
[ ... ]
> + ret = pin_user_pages_fast(userptr->start + pinned * PAGE_SIZE,
> + num_pages, flag,
> + userptr->pages + pinned);
> +
> + if (ret < 0) {
> + if (pinned)
> + unpin_user_pages(userptr->pages, pinned);
> + kvfree(userptr->pages);
> + return ret;
> + }
[Severity: Critical]
Does this error path leave a dangling pointer? The userptr->pages array is freed here but not set to NULL.
If pin_user_pages_fast() fails, this bubbles up to virtio_gpu_userptr_create() which jumps to err_cleanup and calls virtio_gpu_cleanup_object(). That function ultimately invokes virtio_gpu_userptr_put_pages():
if (userptr->pages) {
unpin_user_pages(userptr->pages, userptr->npages);
kvfree(userptr->pages);
userptr->pages = NULL;
}
Because userptr->pages wasn't cleared, won't this result in a use-after-free and double-free when the cleanup function executes?
[ ... ]
> +static int
> +virtio_gpu_userptr_get_entries(struct virtio_gpu_device *vgdev,
> + struct virtio_gpu_object_userptr *userptr,
> + struct virtio_gpu_mem_entry **ents,
> + unsigned int *nents)
> +{
> + bool use_dma_api = virtio_gpu_use_dma_api(vgdev->vdev);
[ ... ]
> + if (use_dma_api) {
> + for_each_sgtable_dma_sg(userptr->sgt, sg, si) {
> + (*ents)[si].addr = cpu_to_le64(sg_dma_address(sg));
> + (*ents)[si].length = cpu_to_le32(sg_dma_len(sg));
> + (*ents)[si].padding = 0;
> + }
> + } else {
> + for_each_sgtable_sg(userptr->sgt, sg, si) {
> + (*ents)[si].addr = cpu_to_le64(sg_phys(sg));
> + (*ents)[si].length = cpu_to_le32(sg->length);
> + (*ents)[si].padding = 0;
> + }
> + }
[ ... ]
> +int virtio_gpu_userptr_create(struct virtio_gpu_device *vgdev,
> + struct drm_file *file,
> + struct virtio_gpu_object_params *params,
> + struct virtio_gpu_object **bo_ptr) {
[ ... ]
> + sgt = drm_prime_pages_to_sg(vgdev->ddev, userptr->pages,
> + userptr->npages);
> + if (IS_ERR(sgt)) {
> + ret = PTR_ERR(sgt);
> + goto err_cleanup;
> + }
> +
> + ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt,
> + DMA_BIDIRECTIONAL, 0);
[Severity: Critical]
Can this unconditional DMA mapping cause silent data corruption?
If the system uses SWIOTLB bounce buffers and the device is configured to bypass the DMA API, the dma_map_sgtable() call will allocate a bounce buffer.
Later in virtio_gpu_userptr_get_entries(), the code branches based on virtio_gpu_use_dma_api(), and if false it ignores the DMA address and passes the raw physical address (sg_phys) to the device.
Since the raw physical address is passed to the device when DMA is bypassed, the device will write directly to the original physical memory. However, during cleanup, dma_unmap_sgtable() with DMA_BIDIRECTIONAL will copy the unmodified bounce buffer back over the original memory. Will this overwrite and destroy the data written by the device?
> + if (ret) {
> + sg_free_table(sgt);
> + kfree(sgt);
> + goto err_cleanup;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects
2026-09-17 10:38 ` sashiko-bot
@ 2026-09-17 10:43 ` Huang, Honglei1
0 siblings, 0 replies; 13+ messages in thread
From: Huang, Honglei1 @ 2026-09-17 10:43 UTC (permalink / raw)
To: sashiko-reviews@lists.linux.dev
Cc: Michael S. Tsirkin, virtualization@lists.linux.dev, Eugenio Perez,
dri-devel@lists.freedesktop.org
AMD General
Will fix it and waiting for maintainer's suggestions
-----Original Message-----
From: sashiko-bot@kernel.org <sashiko-bot@kernel.org>
Sent: Thursday, September 17, 2026 6:38 PM
To: Huang, Honglei1 <Honglei1.Huang@amd.com>
Cc: Michael S. Tsirkin <mst@redhat.com>; virtualization@lists.linux.dev; Eugenio Perez <eperezma@redhat.com>; dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] drm/virtio: double-free and UAF in virtio_gpu_userptr_get_pages error path
- [High] drm/virtio: read-only userptr memory mapped as DMA_BIDIRECTIONAL
- [Medium] drm/virtio: silent fallback to VRAM if userptr is combined with HOST3D
--
commit 357076bf581ca76e53fbe71d8c16da04e304d01c
Author: Honglei Huang <Honglei1.Huang@amd.com>
drm/virtio: wire blob ioctl creation to userptr objects
Integrate userptr into the blob resource creation ioctl.
> diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
[ ... ]
> @@ -458,6 +460,17 @@ static int verify_blob(struct virtio_gpu_device *vgdev,
> return -EINVAL;
> }
>
> + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USE_USERPTR) {
> + if (!rc_blob->userptr)
> + return -EINVAL;
> + } else {
> + if (rc_blob->userptr)
> + return -EINVAL;
> +
> + if (rc_blob->blob_flags & VIRTGPU_BLOB_FLAG_USERPTR_RDONLY)
> + return -EINVAL;
> + }
> +
[Severity: Medium]
Will this silently fall back to VRAM if the user requests a userptr blob but sets the memory type to VIRTGPU_BLOB_MEM_HOST3D?
If guest_blob is false and host3d_blob is true, the userptr flag is validated here but it doesn't ensure a guest memory type was requested.
This could allow the execution to fall through into:
virtio_gpu_resource_create_blob_ioctl() {
...
else if (!guest_blob && host3d_blob)
ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo);
...
}
which would silently ignore params.userptr and allocate standard VRAM instead of returning -EINVAL.
> switch (rc_blob->blob_mem) {
> case VIRTGPU_BLOB_MEM_GUEST:
[ ... ]
> @@ -538,8 +552,10 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
> vfpriv->ctx_id, NULL, NULL);
> }
>
> - if (guest_blob)
> + if (guest_blob && !params.userptr)
> ret = virtio_gpu_object_create(vgdev, ¶ms, &bo, NULL);
> + else if (guest_blob && params.userptr)
> + ret = virtio_gpu_userptr_create(vgdev, file, ¶ms, &bo);
[Severity: Critical]
Does the error path in virtio_gpu_userptr_get_pages() lead to a use-after-free and double-free when this is called?
If virtio_gpu_userptr_get_pages() enters the error path, it frees the pages array but leaves a dangling pointer:
virtio_gpu_userptr_get_pages() {
...
if (pinned)
unpin_user_pages(userptr->pages, pinned);
kvfree(userptr->pages);
return ret;
}
The error returned to virtio_gpu_userptr_create() triggers a jump to err_cleanup and calls virtio_gpu_cleanup_object(), which eventually calls
virtio_gpu_userptr_put_pages():
virtio_gpu_userptr_put_pages() {
if (userptr->pages) {
unpin_user_pages(userptr->pages, userptr->npages);
kvfree(userptr->pages);
userptr->pages = NULL;
}
}
Because the pointer is not NULL, this would unpin and free the already freed array, potentially corrupting page refcounts and memory.
[Severity: High]
Can a read-only userptr be overwritten by the host device?
When VIRTGPU_BLOB_FLAG_USERPTR_RDONLY is specified, the userptr memory is pinned without FOLL_WRITE, allowing read-only memory to be pinned. However, the DMA mapping in virtio_gpu_userptr_create() appears to be hardcoded to
bidirectional:
virtio_gpu_userptr_create() {
...
ret = dma_map_sgtable(drm_dev_dma_dev(vgdev->ddev), sgt,
DMA_BIDIRECTIONAL, 0);
...
}
Because it is mapped bidirectionally, the IOMMU allows device writes to these physical pages. Can unprivileged userspace submit command buffers that instruct the host device to write into the blob, overwriting the read-only guest memory? Should this use DMA_TO_DEVICE when USERPTR_RDONLY is set?
> + else if (!guest_blob && host3d_blob)
> + ret = virtio_gpu_vram_create(vgdev, ¶ms, &bo);
> else
> return -EINVAL;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260917102540.1312102-1-honghuan@amd.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-09-17 10:43 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 10:25 [PATCH v6 0/4] virtio-gpu: Add userptr support for compute workloads Honglei Huang
2026-09-17 10:25 ` [PATCH v6 1/4] drm/virtio-gpu: Add VIRTIO_GPU_CAPSET_ROCM capability Honglei Huang
2026-09-17 10:33 ` sashiko-bot
2026-09-17 10:40 ` Huang, Honglei1
2026-09-17 10:25 ` [PATCH v6 2/4] drm/virtgpu api: add blob userptr resource Honglei Huang
2026-09-17 10:34 ` sashiko-bot
2026-09-17 10:42 ` Huang, Honglei1
2026-09-17 10:25 ` [PATCH v6 3/4] drm/virtio: implement userptr support for zero-copy memory access Honglei Huang
2026-09-17 10:38 ` sashiko-bot
2026-09-17 10:43 ` Huang, Honglei1
2026-09-17 10:25 ` [PATCH v6 4/4] drm/virtio: wire blob ioctl creation to userptr objects Honglei Huang
2026-09-17 10:38 ` sashiko-bot
2026-09-17 10:43 ` Huang, Honglei1
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.