feat: add VirtGPU ioctl bridge and PCI info patches for libdrm

P1: Replaces the old per-ioctl C handlers with a unified dispatch through\nredox_drm_simple_ioctl(), adds VirtGPU NR mappings (MAP, EXECBUFFER,\nGETPARAM, RESOURCE_CREATE, GET_CAPS, etc.), and special handlers for\nEXECBUFFER (inline command buffer) and GET_CAPS (variable response).

P2: Adds __redox__ blocks to drmParsePciBusInfo, drmParsePciDeviceInfo,\nand drmGetDevice2 using the DRM scheme GET_PCI_INFO ioctl to populate\nPCI device identification without /sys access.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-15 07:23:57 +01:00
parent 9a0c912399
commit 6a0659ee04
3 changed files with 461 additions and 0 deletions
@@ -0,0 +1,278 @@
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -91,6 +91,7 @@
#include "xf86drm_redox.h"
#include "libdrm_macros.h"
#include "drm_fourcc.h"
+#include "virtgpu_drm.h"
#include "util_math.h"
@@ -813,6 +814,50 @@
return REDOX_DRM_IOCTL_MODE_DESTROY_DUMB;
case 0xAF:
return REDOX_DRM_IOCTL_MODE_RMFB;
+ /* VirtGPU ioctls (NR 0x41-0x4B) */
+ case 0x41:
+ return REDOX_DRM_IOCTL_VIRTGPU_MAP;
+ case 0x42:
+ return REDOX_DRM_IOCTL_VIRTGPU_EXECBUFFER;
+ case 0x43:
+ return REDOX_DRM_IOCTL_VIRTGPU_GETPARAM;
+ case 0x44:
+ return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE;
+ case 0x45:
+ return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_INFO;
+ case 0x46:
+ return REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST;
+ case 0x47:
+ return REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST;
+ case 0x48:
+ return REDOX_DRM_IOCTL_VIRTGPU_WAIT;
+ case 0x49:
+ return REDOX_DRM_IOCTL_VIRTGPU_GET_CAPS;
+ case 0x4A:
+ return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB;
+ case 0x4B:
+ return REDOX_DRM_IOCTL_VIRTGPU_CONTEXT_INIT;
+ /* Additional standard DRM ioctls */
+ case 0x00:
+ return REDOX_DRM_IOCTL_VERSION;
+ case 0xA0:
+ return REDOX_DRM_IOCTL_MODE_GETRESOURCES;
+ case 0xA1:
+ return REDOX_DRM_IOCTL_MODE_GETCRTC;
+ case 0xA2:
+ return REDOX_DRM_IOCTL_MODE_SETCRTC;
+ case 0xA3:
+ return REDOX_DRM_IOCTL_MODE_GETCONNECTOR;
+ case 0xA4:
+ return REDOX_DRM_IOCTL_MODE_PAGE_FLIP;
+ case 0xA8:
+ return REDOX_DRM_IOCTL_MODE_CREATE_DUMB;
+ case 0xAC:
+ return REDOX_DRM_IOCTL_MODE_ADDFB;
+ case 0x2B:
+ return REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD;
+ case 0x2C:
+ return REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE;
default:
return 0;
}
@@ -908,7 +953,19 @@
static size_t redox_drm_expected_response_size(unsigned long linux_nr, size_t arg_size)
{
switch (linux_nr) {
+ case 0x00: /* VERSION */
case 0x0C:
+ case 0x2B: /* PRIME_HANDLE_TO_FD */
+ case 0x2C: /* PRIME_FD_TO_HANDLE */
+ case 0x41: /* VIRTGPU_MAP */
+ case 0x43: /* VIRTGPU_GETPARAM */
+ case 0x44: /* VIRTGPU_RESOURCE_CREATE */
+ case 0x45: /* VIRTGPU_RESOURCE_INFO */
+ case 0xA0: /* MODE_GETRESOURCES */
+ case 0xA1: /* MODE_GETCRTC */
+ case 0xA3: /* MODE_GETCONNECTOR */
+ case 0xA8: /* MODE_CREATE_DUMB */
+ case 0xAC: /* MODE_ADDFB */
case 0xA6:
case 0xB3:
return arg_size;
@@ -927,6 +984,41 @@
if (request_code == 0) {
errno = ENOTTY;
return -1;
+ }
+
+ if (linux_nr == 0x42) { /* VIRTGPU_EXECBUFFER */
+ struct drm_virtgpu_execbuffer *eb = arg;
+ size_t total = arg_size + eb->size;
+ uint8_t *buf = drmMalloc((int)total);
+ int ret;
+
+ if (!buf)
+ return -1;
+
+ memcpy(buf, arg, arg_size);
+ if (eb->size > 0 && eb->command)
+ memcpy(buf + arg_size, (void *)(uintptr_t)eb->command, eb->size);
+
+ ret = redox_drm_exchange(fd, request_code, buf, total, NULL, 0, NULL);
+ drmFree(buf);
+ return ret;
+ }
+
+ if (linux_nr == 0x49) { /* VIRTGPU_GET_CAPS */
+ struct drm_virtgpu_get_caps *gc = arg;
+ void *resp;
+ size_t resp_size;
+ int ret;
+
+ ret = redox_drm_exchange_alloc(fd, request_code, arg, arg_size, &resp, &resp_size);
+ if (ret == 0 && resp && resp_size > 0) {
+ size_t copy = resp_size < gc->size ? resp_size : gc->size;
+
+ memcpy((void *)(uintptr_t)gc->addr, resp, copy);
+ drmFree(resp);
+ }
+
+ return ret;
}
if (redox_drm_exchange(fd, request_code,
--- a/xf86drm_redox.h
+++ b/xf86drm_redox.h
@@ -28,6 +28,17 @@
#define REDOX_DRM_IOCTL_GEM_CLOSE (REDOX_DRM_IOCTL_BASE + 27)
#define REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD (REDOX_DRM_IOCTL_BASE + 29)
#define REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE (REDOX_DRM_IOCTL_BASE + 30)
+#define REDOX_DRM_IOCTL_VIRTGPU_MAP (REDOX_DRM_IOCTL_BASE + 31)
+#define REDOX_DRM_IOCTL_VIRTGPU_EXECBUFFER (REDOX_DRM_IOCTL_BASE + 32)
+#define REDOX_DRM_IOCTL_VIRTGPU_GETPARAM (REDOX_DRM_IOCTL_BASE + 33)
+#define REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE (REDOX_DRM_IOCTL_BASE + 34)
+#define REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_INFO (REDOX_DRM_IOCTL_BASE + 35)
+#define REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST (REDOX_DRM_IOCTL_BASE + 36)
+#define REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST (REDOX_DRM_IOCTL_BASE + 37)
+#define REDOX_DRM_IOCTL_VIRTGPU_WAIT (REDOX_DRM_IOCTL_BASE + 38)
+#define REDOX_DRM_IOCTL_VIRTGPU_GET_CAPS (REDOX_DRM_IOCTL_BASE + 39)
+#define REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB (REDOX_DRM_IOCTL_BASE + 40)
+#define REDOX_DRM_IOCTL_VIRTGPU_CONTEXT_INIT (REDOX_DRM_IOCTL_BASE + 41)
struct redox_drm_resources_wire {
uint32_t connector_count;
--- /dev/null
+++ b/virtgpu_drm.h
@@ -0,0 +1,132 @@
+#ifndef _VIRTGPU_DRM_H_
+#define _VIRTGPU_DRM_H_
+
+#include <stdint.h>
+
+#define DRM_VIRTGPU_MAP 0x41
+#define DRM_VIRTGPU_EXECBUFFER 0x42
+#define DRM_VIRTGPU_GETPARAM 0x43
+#define DRM_VIRTGPU_RESOURCE_CREATE 0x44
+#define DRM_VIRTGPU_RESOURCE_INFO 0x45
+#define DRM_VIRTGPU_TRANSFER_FROM_HOST 0x46
+#define DRM_VIRTGPU_TRANSFER_TO_HOST 0x47
+#define DRM_VIRTGPU_WAIT 0x48
+#define DRM_VIRTGPU_GET_CAPS 0x49
+#define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x4A
+#define DRM_VIRTGPU_CONTEXT_INIT 0x4B
+
+#define drm_virtgpu_resource_create drm_virtgpu_resource_create_3d
+#define drm_virtgpu_3d_transfer_to_host drm_virtgpu_transfer_to_host
+#define drm_virtgpu_3d_transfer_from_host drm_virtgpu_transfer_from_host
+#define drm_virtgpu_3d_wait drm_virtgpu_wait_3d
+#define ctx_set_params_ptr ctx_set_params
+#define resource_id res_handle
+
+struct drm_virtgpu_3d_box {
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ uint32_t w;
+ uint32_t h;
+ uint32_t d;
+};
+
+struct drm_virtgpu_execbuffer {
+ uint32_t flags;
+ uint32_t size;
+ uint64_t command;
+ uint64_t bo_handles;
+ uint32_t num_bo_handles;
+ int32_t fence_fd;
+ uint32_t ring_idx;
+ uint32_t syncobj_stride;
+ uint32_t num_in_syncobjs;
+ uint32_t num_out_syncobjs;
+ uint64_t in_syncobjs;
+ uint64_t out_syncobjs;
+};
+
+struct drm_virtgpu_getparam {
+ uint64_t param;
+ uint64_t value;
+};
+
+struct drm_virtgpu_resource_create_3d {
+ uint32_t target;
+ uint32_t format;
+ uint32_t bind;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+ uint32_t array_size;
+ uint32_t last_level;
+ uint32_t nr_samples;
+ uint32_t flags;
+ uint32_t bo_handle;
+ uint32_t res_handle;
+ uint32_t size;
+ uint32_t stride;
+};
+
+struct drm_virtgpu_resource_info {
+ uint32_t bo_handle;
+ uint32_t res_handle;
+ uint32_t size;
+ uint32_t blob_mem;
+};
+
+struct drm_virtgpu_transfer_to_host {
+ uint32_t bo_handle;
+ struct drm_virtgpu_3d_box box;
+ uint32_t level;
+ uint32_t offset;
+ uint32_t stride;
+ uint32_t layer_stride;
+};
+
+struct drm_virtgpu_transfer_from_host {
+ uint32_t bo_handle;
+ struct drm_virtgpu_3d_box box;
+ uint32_t level;
+ uint32_t offset;
+ uint32_t stride;
+ uint32_t layer_stride;
+};
+
+struct drm_virtgpu_wait_3d {
+ uint32_t handle;
+ uint32_t flags;
+};
+
+struct drm_virtgpu_get_caps {
+ uint32_t cap_set_id;
+ uint32_t cap_set_ver;
+ uint64_t addr;
+ uint32_t size;
+ uint32_t pad;
+};
+
+struct drm_virtgpu_resource_create_blob {
+ uint32_t blob_mem;
+ uint32_t blob_flags;
+ uint32_t bo_handle;
+ uint32_t res_handle;
+ uint64_t size;
+ uint32_t pad;
+ uint32_t cmd_size;
+ uint64_t cmd;
+ uint64_t blob_id;
+};
+
+struct drm_virtgpu_context_set_param {
+ uint64_t param;
+ uint64_t value;
+};
+
+struct drm_virtgpu_context_init {
+ uint32_t num_params;
+ uint32_t pad;
+ uint64_t ctx_set_params;
+};
+
+#endif
@@ -0,0 +1,30 @@
diff --git a/local/recipes/libs/libdrm/source/xf86drm.c b/local/recipes/libs/libdrm/source/xf86drm.c
index 0379aafd7e..2d3fcd6d3b 100644
--- a/local/recipes/libs/libdrm/source/xf86drm.c
+++ b/local/recipes/libs/libdrm/source/xf86drm.c
@@ -1653,6 +1653,10 @@ static size_t redox_drm_expected_response_size(unsigned long linux_nr, size_t ar
case 0xA9:
case 0xAA:
case 0xAC:
+ case 0xB2:
+ case 0xB4:
+ case 0xBD:
+ case 0xBE:
case 0xB8:
case 0xB9:
case 0xB3:
@@ -4482,7 +4486,13 @@ drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
return -errno;
}
- *prime_fd = response.fd;
+ char path[64];
+ snprintf(path, sizeof(path), "card0/dmabuf/%d", response.fd);
+ int real_fd = openat(fd, path, O_RDWR | O_CLOEXEC);
+ if (real_fd < 0) {
+ return -errno;
+ }
+ *prime_fd = real_fd;
return 0;
#else
struct drm_prime_handle args;
@@ -0,0 +1,153 @@
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -115,7 +115,7 @@
#define DRM_MAJOR 226 /* Linux */
#endif
-#if defined(__OpenBSD__) || defined(__DragonFly__)
+#if defined(__OpenBSD__) || defined(__DragonFly__) || defined(__redox__)
struct drm_pciinfo {
uint16_t domain;
uint8_t bus;
@@ -858,6 +858,9 @@
return REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD;
case 0x2C:
return REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE;
+ /* DRM_IOCTL_GET_PCIINFO — PCI device information for driver discovery */
+ case 0x15:
+ return REDOX_DRM_IOCTL_GET_PCI_INFO;
default:
return 0;
}
@@ -4201,6 +4204,21 @@
return 0;
#elif defined(__FreeBSD__)
return get_sysctl_pci_bus_info(maj, min, info);
+#elif defined(__redox__)
+ int rfd = open("/scheme/drm/card0", O_RDONLY);
+ if (rfd < 0)
+ return -errno;
+ uint8_t buf[22];
+ size_t rsize = 0;
+ int ret = redox_drm_exchange(rfd, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, buf, sizeof(buf), &rsize);
+ close(rfd);
+ if (ret != 0 || rsize < 17)
+ return -EIO;
+ info->domain = buf[10] | (buf[11] << 8) | (buf[12] << 16) | (buf[13] << 24);
+ info->bus = buf[14];
+ info->dev = buf[15];
+ info->func = buf[16];
+ return 0;
#else
#warning "Missing implementation of drmParsePciBusInfo"
return -EINVAL;
@@ -4410,6 +4428,23 @@
device->revision_id = results[0].pc_revid;
return 0;
+#elif defined(__redox__)
+ int rfd2 = open("/scheme/drm/card0", O_RDONLY);
+ if (rfd2 < 0)
+ return -errno;
+ uint8_t dbuf[22];
+ size_t drsize = 0;
+ int dret = redox_drm_exchange(rfd2, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, dbuf, sizeof(dbuf), &drsize);
+ close(rfd2);
+ if (dret != 0 || drsize < 9)
+ return -EIO;
+ device->vendor_id = dbuf[0] | (dbuf[1] << 8);
+ device->device_id = dbuf[2] | (dbuf[3] << 8);
+ device->subvendor_id = dbuf[4] | (dbuf[5] << 8);
+ device->subdevice_id = dbuf[6] | (dbuf[7] << 8);
+ if (drsize >= 9)
+ device->revision_id = dbuf[8];
+ return 0;
#else
#warning "Missing implementation of drmParsePciDeviceInfo"
return -EINVAL;
@@ -5162,6 +5197,66 @@
*/
drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
{
+#if defined(__redox__)
+ uint8_t pbuf[22];
+ size_t prsize = 0;
+ int pret;
+ uint16_t pvendor_id, pdevice_id, psubvendor_id, psubdevice_id, pdomain;
+ uint8_t prevision_id, pbus, pdev, pfunc;
+ const char *pnode;
+ int max_node_length, i;
+ size_t extra, psize;
+ drmDevicePtr devp;
+ char *pptr;
+
+ pret = redox_drm_exchange(fd, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0,
+ pbuf, sizeof(pbuf), &prsize);
+ if (pret != 0 || prsize < 17)
+ return -EIO;
+
+ pvendor_id = pbuf[0] | (pbuf[1] << 8);
+ pdevice_id = pbuf[2] | (pbuf[3] << 8);
+ psubvendor_id = pbuf[4] | (pbuf[5] << 8);
+ psubdevice_id = pbuf[6] | (pbuf[7] << 8);
+ prevision_id = pbuf[8];
+ pdomain = pbuf[10] | (pbuf[11] << 8) | (pbuf[12] << 16) | (pbuf[13] << 24);
+ pbus = pbuf[14];
+ pdev = pbuf[15];
+ pfunc = pbuf[16];
+
+ pnode = "/scheme/drm/card0";
+ max_node_length = 64;
+ extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
+ psize = sizeof(drmDevice) + extra + sizeof(drmPciBusInfo) + sizeof(drmPciDeviceInfo);
+ devp = calloc(1, psize);
+ if (!devp)
+ return -ENOMEM;
+
+ devp->bustype = DRM_BUS_PCI;
+ devp->available_nodes = 1 << DRM_NODE_PRIMARY;
+ pptr = (char *)devp + sizeof(drmDevice);
+ devp->nodes = (char **)pptr;
+ pptr += DRM_NODE_MAX * sizeof(void *);
+ for (i = 0; i < DRM_NODE_MAX; i++) { devp->nodes[i] = pptr; pptr += max_node_length; }
+ snprintf(devp->nodes[DRM_NODE_PRIMARY], max_node_length, "%s", pnode);
+
+ devp->businfo.pci = (drmPciBusInfoPtr)pptr;
+ pptr += sizeof(drmPciBusInfo);
+ devp->businfo.pci->domain = pdomain;
+ devp->businfo.pci->bus = pbus;
+ devp->businfo.pci->dev = pdev;
+ devp->businfo.pci->func = pfunc;
+
+ devp->deviceinfo.pci = (drmPciDeviceInfoPtr)pptr;
+ devp->deviceinfo.pci->vendor_id = pvendor_id;
+ devp->deviceinfo.pci->device_id = pdevice_id;
+ devp->deviceinfo.pci->subvendor_id = psubvendor_id;
+ devp->deviceinfo.pci->subdevice_id = psubdevice_id;
+ devp->deviceinfo.pci->revision_id = prevision_id;
+
+ *device = devp;
+ return 0;
+#else
struct stat sbuf;
if (fd == -1)
@@ -5174,6 +5269,7 @@
return -EINVAL;
return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
+#endif
}
/**
--- a/xf86drm_redox.h
+++ b/xf86drm_redox.h
@@ -40,6 +40,8 @@
#define REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB (REDOX_DRM_IOCTL_BASE + 40)
#define REDOX_DRM_IOCTL_VIRTGPU_CONTEXT_INIT (REDOX_DRM_IOCTL_BASE + 41)
+#define REDOX_DRM_IOCTL_GET_PCI_INFO (REDOX_DRM_IOCTL_BASE + 0x60)
+
struct redox_drm_resources_wire {
uint32_t connector_count;
uint32_t crtc_count;