R4: virtio-gpu driver (virgl, scanout, cursor), guest verification pending #7

Merged
toasterson merged 22 commits from r4-virtio-gpu into main 2026-10-05 16:46:17 +00:00
Owner

Anima work item: WI-456 01a0e388-0729-7da2-9fac-747b889a2020

Stacked on #6 (r2-sync). Pins illumos-ddi r4-virtio be78455670 (illumos-ddi #6, stacked on its #5).

Status: code complete and verified in a QEMU guest (Hephaistos, QEMU 6.2, -device virtio-gpu-gl-pci -display egl-headless, virglrenderer 0.9.1 on the host's AMD GPU), including Mesa's virgl driver rendering through virtio_gpu to the screen. The guest runs found three bugs and the final review of their evidence a fourth, all fixed here and re-run on the device (see Fixes from the guest runs). This PR was first opened while the test host was down, with the verification marked pending; that original section is kept at the end under History.

What was built

  • Driver drivers/virtio-gpu (module virtio_gpu, PCI 1af4:1050), on illumos-ddi's ddi::private::virtio:
    • It negotiates VIRGL, EDID, RESOURCE_BLOB and CONTEXT_INIT when offered. The control queue carries every request and the cursor queue carries cursor updates.
    • Requests encode virtio_gpu_ctrl_hdr and complete in thread context on the framework's task queue, and waiters also poll. Fenced requests (SUBMIT_3D, the 3D transfers) take their fence id under the submission lock and signal R2 Fences in the device's per-context order.
    • It queries capsets (virgl, virgl2) with a cache, reads display info, and reads the EDID.
  • GEM objects are R1 SysMem bound for DMA against the device's node, and their cookies are the ATTACH_BACKING (or blob) memory entries:
    • 2D resources for dumb buffers and non-virgl mode, 3D resources, and guest-memory blobs (BLOB_MEM_GUEST, BLOB_MEM_HOST3D_GUEST).
    • A handle attaches the resource to the file's virgl context; removing the handle detaches it. Closing the file destroys the context.
    • Destroying an object waits for RESOURCE_UNREF before freeing its memory, and leaks the memory if the device never answers.
  • Ioctls follow Linux 6.12's checks and errnos: MAP; EXECBUFFER (32-, 40- and 64-byte layouts; FENCE_FD_IN/OUT through R2 sync files; in and out sync-object arrays including timelines and SYNCOBJ_RESET; rings with RING_IDX); GETPARAM (3D_FEATURES, CAPSET_QUERY_FIX=1, RESOURCE_BLOB, HOST_VISIBLE=0, CROSS_DEVICE=0, CONTEXT_INIT, SUPPORTED_CAPSET_IDs, EXPLICIT_DEBUG_NAME); RESOURCE_CREATE; RESOURCE_INFO; TRANSFER_FROM_HOST and TRANSFER_TO_HOST (also in the 36-byte layout); WAIT; GET_CAPS; RESOURCE_CREATE_BLOB; CONTEXT_INIT. The driver reports version 0.1.0, which Mesa's virgl winsys requires.
  • Display:
    • Each scanout gets a connector, encoder, CRTC, primary plane and cursor plane. EDID comes from the device, with a CVT mode and the standard modes as the fallback.
    • The primary plane uses SET_SCANOUT, with TRANSFER_TO_HOST_2D for dumb buffers and RESOURCE_FLUSH. The cursor uses the cursor queue.
    • DIRTYFB sends one transfer and flush of the damage's bounding box.
    • Page-flip events come from R3's software vblank, one per active CRTC.
    • The bus ID is pci:0000:BB:DD.F, which Xorg's modesetting driver matches.
  • Core hooks (small, host tests unchanged and passing): GemObject::handle_opened, handle_closed and release; Driver::file_close and Driver::dumb_object; KmsDriver::dirty_fb (the default is still ENOSYS); SyncCore::sync_file_fence made public; Plain for the virtgpu uAPI structures.
  • uAPI:
    • drm-uapi is regenerated with virtgpu_drm.h from Linux v6.12. The header is MIT-licensed; its source URL and SHA-256 are in tools/uapi/include/README. libdrm 2.4.109's copy lacks RESOURCE_CREATE_BLOB, CONTEXT_INIT, the later parameters and the sync-object arrays.
    • Grown structures have a command number per size under the illumos encoding. virtgpu_compat.rs declares the older layouts: EXECBUFFER at 32 bytes (libdrm 2.4.109) and 40 bytes (Mesa 21.3), and the 36-byte transfers.
    • tools/uapi/virtgpu_compat_layout.c checks those layouts against the original headers, and abi.rs pins every virtio-gpu ioctl number.
  • Packaging:
    • packaging/virtio-gpu.p5m delivers the module with a driver action (alias=pci1af4,1050, perms="* 0666 root sys", and a devlink for /dev/dri).
    • packaging/xorg.conf.d/20-virtio-gpu.conf configures modesetting with kmsdev /dev/dri/card0 and glamor.
    • devlink.tab gets the virtio_gpu line.
  • Tests:
    • tools/test/drm_r4_test.c covers the parameters, capsets and dumb buffers. With virgl, it also sends a minimal virgl command stream (surface, framebuffer, clear) through EXECBUFFER and checks the pixels read back with TRANSFER_FROM_HOST; chains fences across the three layouts; covers sync objects and a timeline wait that times out; imports a buffer into the render node's context with PRIME; creates blobs and runs CONTEXT_INIT; checks every refusal; and runs 2000 submissions in a row plus 8 threads at once.
    • tools/test/run-r4-test.sh links, checks symbols, runs add_drv, runs the test and modetest, checks that detach is refused while a file is open and while only a dma-buf is left, then unloads and checks that /etc and /devices are restored.
    • Host tests of the driver's pure logic: cargo test -p virtio_gpu --no-default-features.
  • CI runs the driver's host tests, and builds and links the module with -N misc/virtio -N fs/specfs.

Decisions

  • The driver is a crate in this workspace. The core is linked statically, as in rdrmnull, with -N misc/virtio -N fs/specfs.
  • Completions run in thread context: the wrapper's task queue, plus waiters that poll. So Driver::fence_priority is None, and no driver lock has an interrupt priority.
  • The GEM references that requests hold are dropped through the interrupt-safe (deferred) path. RESOURCE_UNREF is therefore never awaited on the completing thread.
  • Mesa: oi-userland hephaistos/virgl-gallium (d69854c287) was built on oibuild in /ws/toasty with -j2, and published as x11/library/mesa@21.3.9-2025.0.0.90 with COMPONENT_REVISION=90 so that it outranks the installed 21.3.9. No packages were installed on oibuild and env-prep was not run. The worktree-local repo was created with pkgrepo create. The guest run showed that revision 90 crashes in virgl_disk_cache_create (it reads a GNU build ID that illumos' link-editor does not emit), so the oibuild worktree gained patches/09-virgl-disk-cache-build-id.patch (commit 4aa9a85809, uses disk_cache_get_function_identifier, which falls back to the library's mtime) and was republished as revision 91 (mesa-virgl-r4-91.p5p, SHA-256 1fb443ad…). Revision 91 was published from the worktree's local branch r4/xorg-glamor at 4aa9a85809, which is d69854c287 plus five xorg-server test commits (the abandoned glamor build) plus the Mesa patch; only the patch touches Mesa. Nothing was pushed upstream. The crash itself was seen in the guest but its stack was not saved; the static evidence (the unpatched build_id_length(note) on a NULL note with the assert compiled out, and no note section in the built virtio_gpu_dri.so) is in logs/oibuild/mesa-virgl-r4/build-id-evidence.log.

Deviations

  • HOST_VISIBLE is 0 and BLOB_MEM_HOST3D blobs are refused with EINVAL: the gate framework has no shared-memory regions, as the work item expected.
  • CROSS_DEVICE is 0 (no resource UUIDs).
  • A non-zero POLL_RINGS_MASK is EINVAL, because the core has no per-file event queue outside KMS.
  • Blob framebuffers cannot be scanned out: SET_SCANOUT_BLOB is not implemented. With HOST_VISIBLE=0, Mesa does not use them.
  • The EXECBUFFER command stream is limited to 1 MiB (Mesa 21.3 sends at most 266,240 bytes).
  • After an EXECBUFFER is queued, adding its fence to the reservations, the out sync objects or a new sync file can still fail for lack of memory. The ioctl then reports an error for work that runs anyway. Linux reserves these first.
  • Contexts are named pid N, because the DDI has no process name.
  • CONTEXT_INIT is EINVAL without VIRTIO_GPU_F_CONTEXT_INIT, which QEMU 6.2 does not offer. On such a host only that path can be exercised.

Verification (counts and logs)

Done:

  • Host checks with --locked on the pinned illumos-ddi: check, clippy -D warnings (also with rdrmnull/panic-drill), fmt, rustdoc -D warnings. Tests: drm 109, drm-uapi 1, virtio_gpu 5, and the host tests caught a real bug in response checking. xtask uapi-check: 111 sizes, 497 offsets, 121 ioctl numbers identical to gcc 14.3.0 on illumos (tools/uapi/drm_layout.oibldofgate.out, which now includes the compat layouts). The kernel archives of virtio_gpu and rdrmnull build with nightly-2026-04-16. Log: logs/r4-host-checks-illumos-drm.log.
  • Link check on oibldofgate (illumos cda5b9a49f, the golden guest's kernel), with nothing loaded: virtio_gpu links with NEEDED misc/virtio, fs/specfs and all 127 of its undefined symbols are exported by the running kernel; rdrmnull has 106 of 106. Log: logs/oibldofgate/20260930-r4-kmod-link.log.
  • illumos-ddi kernel-check of the virtio crate against that kernel: 48/48 symbols from virtio. Log: logs/oibldofgate/20260930-r4-virtio-kernel-check.log.
  • IPS package: pkglint clean, published and received as a p5p. Log: logs/oibuild/20260930-r4-virtio-gpu-package.log; artifact artifacts/r4-virtio-gpu/package/.
  • Mesa: gmake install (1558 ninja steps, virtio_gpu_dri.so in the proto area) and gmake publish both exit 0. Logs: logs/oibuild/mesa-virgl-r4/; artifact artifacts/r4-virtio-gpu/mesa/mesa-virgl-r4.p5p.
  • drm_r4_test.c compiles with gcc -Wall -Wextra on illumos.
  • Two local review rounds (Anima rules, Opus). Round 1 found 4 blockers and 9 should-fix items; all were addressed, and the two illumos-ddi type rules are in its PR. Round 2 found no code defects and rejected only because the guest run is missing.

Guest runs on Hephaistos (2026-09-30; fresh overlays of the golden Hipster image, illumos cda5b9a49f, 2 vCPUs, 3 GiB, private user networking, bounded lifetime; ports 2360-2364; all overlays deleted afterwards, nothing left running). Logs are in the workspace under logs/hephaistos/illumos-drm/, screenshots under artifacts/r4-virtio-gpu/screens/, the results note is notes/r4-virtio-gpu-verification.md. No run panicked.

  • Host capabilities: QEMU 6.2 offers virtio-gpu-gl-pci, virtio-gpu-pci and egl-headless; libvirglrenderer 0.9.1; /dev/dri/renderD128 on the host. Log 20260930-r4-host-preflight.log.
  • Two guest-setup traps (not driver bugs): a virtio-gpu at an automatic PCI slot moves the disk and NIC (the golden image's network then fails), so the GPU sits at addr=0x10; and at illumos cda5b9a49f the virtio framework caches the BAR register number of the first modern device (illumos bug 18358, fixed upstream in 36d8c52c14), so virtio_init for the GPU failed with "Failed to map CAP 1 @ BAR4" behind the transitional vioblk. The runs attach the disk with disable-modern=on instead. Logs 20260930-r4-run2-driver.log, 20260930-r4-run2-bar-cache.log; documented in illumos-ddi #6 (docs/DESIGN.md).
  • Attach (dmesg): virtio_gpu0: virtio-gpu: 1 scanout(s), features 0x110000003 of 0x130000003 (virgl true, edid true, blob false, context_init false), 2 capset(s) 0x6, modern interface.
  • run-r4-test.sh: PASS, 74 checks, 0 failures (r4-run5, driver from c4318271eb, whose code is that of 7dda62f; the rebase only moved virgl_egl_test.c into its own commit; virtio_gpu.a SHA-256 c909e777…f7e6). Log 20260930-r4-run5-driver.log.
    • drm_r4_test 63/63, including the minimal virgl command stream (surface, framebuffer, clear) read back from the host renderer with TRANSFER_FROM_HOST, fences across the 32/40/64-byte EXECBUFFER layouts, binary and timeline sync objects, PRIME into another file's context, 2000 submissions in a row, and 8 threads creating, clearing, fencing, reading back and closing 800 textures at once.
    • Negative tests: unknown EXECBUFFER flags EINVAL; a timeline wait times out with ETIME after 100 ms; CONTEXT_INIT-only rings refused; unknown handles and sync objects, bad strides, oversized and unreadable streams refused.
    • modetest: the device's EDID (1024x768 at 75 Hz preferred, 12 more modes), mode set, page flips with vblank events at the mode's 75 Hz, cursor, atomic commit. Screendump during flips: 20260930-r4-run3-modetest-vsync-gpu0.png (SMPTE bars).
    • Unload with outstanding objects: modunload refused while a process holds a file, a dumb buffer and a dma-buf, and while only a dma-buf is left; the device works again afterwards; then it unloads, and /etc and /devices are as before. At detach: 19,543 requests, 7,224 fenced, 0 failed, 5 queue-full waits, 0 timeouts, 2,011 resources created, 0 left.
  • R0-R3 regression with rdrmnull in the same boot: run-r1-test: fail=0 (R0, R1 and R2 suites, 0 failures each) and run-r3-test: fail=0. Logs 20260930-r4-run5-regression-r1.log, 20260930-r4-run5-regression-r3.log.
  • Xorg modesetting: stock x11/server/xorg@1.19.7-2026.0.0.14 and x11/demo/mesa-demos@8.5.0 installed from the openindiana.org publisher into the overlay (20260930-r4-run5-x-install.log) with packaging/xorg.conf.d/20-virtio-gpu.conf: modesetting opens card0, reads the EDID, runs 1024x768 with damage through DIRTYFB (20260930-r4-run5-Xorg.1-stock.log, screenshot 20260930-r4-run5-xorg-stock-gpu0.png). OpenIndiana's Xorg is built without glamor ("No glamor support in the X Server", "AIGLX: Screen 0 is not DRI2 capable"), so glxinfo -B reports softpipe, not virgl (20260930-r4-run5-glxinfo-stock-xorg.log), and glxgears runs at about 180 FPS in software, shown on the virtio-gpu scanout (20260930-r4-run5-glxgears-softpipe.log, 20260930-r4-run5-glxgears-softpipe-gpu0.png). A glamor rebuild of Xorg on oibuild failed (xtrans 1.6 and gcc 14 errors; the last attempt's log is logs/oibuild/mesa-virgl-r4/xorg-glamor-publish.log, failing in Xtranssock.c on msghdr.msg_control) and was abandoned. The stock-Xorg screenshot 20260930-r4-run5-xorg-stock-gpu0.png is black (an empty root window); the scanout of X's damage is shown by the glxgears screenshot.
  • Mesa's virgl driver (rev 91): pkg install of the p5p in the guest is impossible (it depends on osnet 23293, the golden image has 23197), so its payload (tar SHA-256 be86a844…65b4, 104 files, each listed in 20260930-r4-run5-mesa-overlay.log; virtio_gpu_dri.so SHA-256 c300f510…) was extracted over the stock Mesa 21.3.9 in the overlay only, never the golden image. OpenIndiana's libdrm 2.4.109 only enumerates device nodes named display, so without help EGL fails with "DRI2: failed to find EGLDevice" (20260930-r4-run5-virgl-egl.log); the tests load tools/test/drm_devshim.c with LD_PRELOAD_64 to answer drmGetDevice2 for the device.
    • tools/test/virgl_egl_test.c (EGL on GBM, render node): GL_RENDERER: virgl, GL_VERSION: 3.1 Mesa 21.3.9, a cleared 256x256 FBO reads back exactly, 600 clear-and-read-back frames at about 1,300 per second, 0 failures (20260930-r4-run5-virgl-egl-shim.log).
    • tools/test/virgl_kms_gears.c (GBM scanout surface on card0, page flip per frame, waiting for each flip event): renderer virgl, 600 frames at 74.8 fps on the 75 Hz mode, 0 failures; QMP screendump of the virgl-rendered frame 20260930-r4-run5-virgl-kms-gears-gpu0.png. Afterwards modunload succeeded: 18,762 requests, 3,011 fenced, 0 failed, 8 resources created, 0 left (20260930-r4-run5-virgl-kms-gears.log).
    • Observed, not this driver: after SIGTERM, Xorg :1 stayed blocked in xf86CloseConsole (VT_ACTIVATE) holding card0, and needed SIGKILL before the unload.
  • Final run r4-run6 at 8e15c99b50 (after the final review round's fix below; virtio_gpu.a SHA-256 3f6d912c…3519, rdrmnull.a from the same commit), port 2365:
    • run-r4-test.sh: PASS, 74 checks, including its /dev/dri cleanup (20260930-r4-run6-driver.log). Detach: 19,522 requests, 7,224 fenced, 0 failed, 4 queue-full waits, 0 timeouts, 2,011 resources, 0 left.
    • The review's scenario on the device: a legacy cursor set on a CRTC that is off (cursor plane 22 on CRTC 23 with fb 29), the file closed, then modunload succeeds (20260930-r4-run6-cursor-close.log, program 20260930-r4-run6-cursor_close.c).
    • R0-R3: run-r1-test: fail=0, run-r3-test: fail=0 (20260930-r4-run6-regression-r1.log, -r3.log).
    • Mesa (stock x11/library/mesa and x11/library/libdrm from the publisher, rev 91 payload over it, 20260930-r4-run6-mesa-overlay.log): virgl_egl_test 0 failed with GL_RENDERER: virgl; virgl_kms_gears 600 page-flipped frames at 75.0 fps; screendump 20260930-r4-run6-virgl-kms-gears-gpu0.png; clean modunload afterwards (20260930-r4-run6-virgl.log). Xorg was not rerun.
    • Guest consoles for all runs: logs/hephaistos/illumos-drm/r4-console/.
  • Host checks at the final head 55d8e6011d: check, clippy -D warnings (also with rdrmnull/panic-drill), fmt, rustdoc, tests (drm 111, drm-uapi 1, virtio_gpu 5), uapi-check 0 differences. Log logs/20260930-r4-host-checks-final-illumos-drm.log.

Fixes from the guest runs

  • a1d0785 kms (core): a CRTC turned off by a close or RMFB now takes its other planes with it. modetest -C left a legacy cursor framebuffer (owned by no file) on the dark CRTC, so detach was refused with no file open. New host test close_turns_off_the_cursor_of_the_crtc_it_turns_off fails without the fix.
  • 7dda62f virtio_gpu: the driver no longer keeps a KArc<FenceDomain>; it takes the domain from the device's sync core per submission. Holding it meant the core's "fences or sync objects remain" check refused every unload.
  • 4ad90da, and the rate check in a1d0785, run-r4-test.sh: the page-flip rate is compared with the mode's refresh rate (QEMU's EDID prefers 75 Hz), and the script removes virtio_gpu's /dev/dri links at the end so later suites start clean.
  • 8e15c99 kms (core), from the final review round: a file's close also turns off the legacy cursors it set. add_fb takes an FbOwner (File or Cursor), and the internal cursor framebuffer records the file whose CURSOR call made it. Without this, a cursor set on a CRTC that is off (or left by SETCRTC turning the CRTC off) outlived its master and kept virtio_gpu's detach refused. Linux leaves such cursors on; the README explains the difference. New host test close_turns_off_the_legacy_cursors_the_file_set, which fails without the change; verified on the device in r4-run6.
  • 72256f3 tools/test: virgl_egl_test.c, virgl_kms_gears.c, drm_devshim.c. 7dd280a, 03f8109, 55d8e60 README; d02a5bc the Xorg snippet documents the no-glamor case.

Local review rounds

  • Round 1 (code): reject, 4 blockers and 9 should-fix items, all addressed.
  • Round 2 (code): no code defects; reject only because the guest run was missing.
  • Round 3 (runtime evidence, after the runs above): approve, no blockers. Should-fix items: the cursor-on-a-dark-CRTC case (fixed in 8e15c99, re-run in r4-run6); two claims without logs (the rev-90 crash, now backed by static evidence and marked as such; the Xorg glamor failure, log added); and the Mesa branch name (corrected above). Notes: the driver package p5p in the workspace was built from an earlier commit (72397ee39e; only pkglint and publishing were claimed, and it should be rebuilt from the merged head before any publication); the run3 SMPTE screenshot predates the fixes (r4-run6's virgl screendump is at the final head).

Open issues

  • GLX with virgl under X: needs an OpenIndiana Xorg built with glamor (DRI2/DRI3 in modesetting).
  • libdrm (gfx-drm) device enumeration: match minors of node type ddi_display:drm instead of the node name display (and fix the PCI path parsing); until then Mesa needs drm_devshim.c for virtio-gpu. Workspace note notes/mesa-component.md, libdrm item 6.
  • illumos bug 18358 in the guest's kernel (fixed upstream after cda5b9a49f): a second modern virtio device fails; the runs use a transitional disk.
  • The Mesa build-ID patch (oi-userland hephaistos/virgl-gallium branch, local) and a Mesa package whose dependencies match the installed osnet.
  • SET_SCANOUT_BLOB, host-visible blobs (they need shared-memory regions in the gate's virtio framework), resource UUIDs, and polled-ring fence events.
  • Pre-reserving EXECBUFFER's fence slots, chains and fd before queueing.
  • Moving the illumos-ddi pin to main once the stacked branches merge.

History

The first version of this PR (head 298fec2438) was opened while Hephaistos was down. Its verification section read:

Pending, all on a QEMU guest (Hephaistos, -device virtio-gpu-gl-pci, -display egl-headless or gtk,gl=on under Xvfb):

  • The host's QEMU capabilities (virtio-gpu-gl, egl-headless, virglrenderer).
  • The attach lines in dmesg.
  • run-r4-test.sh, including the threaded part and the negative tests: unknown EXECBUFFER flags return EINVAL, the fence wait times out, and detach is refused while objects are outstanding.
  • modetest: mode set, vsync, cursor, atomic.
  • The Xorg modesetting log, glxinfo -B showing virgl, the glxgears frame rate, and a QMP screendump of gpu0.
  • The R0–R3 regression suites with rdrmnull.

The guest bundle is staged in artifacts/r4-virtio-gpu/guest-bundle/ (virtio_gpu.a SHA-256 1dd62fc6…dfa8, built at 298fec2438). Commands:

bin/ssh-illumos hephaistos 'cd ~/illumos-drm-test/20260928 && qemu-img create -f qcow2 -F qcow2 -b $PWD/golden.qcow2 r4-run1.qcow2 && bin/start-guest-gpu.sh r4-run1 $PWD/r4-run1.qcow2 2360 3h gl egl'
tar -C artifacts/r4-virtio-gpu/guest-bundle -cf - . | artifacts/illumos-drm-hephaistos/guest-ssh 2360 'mkdir -p /root/r4 && tar -xf - -C /root/r4'
artifacts/illumos-drm-hephaistos/guest-ssh 2360 'cd /root/r4 && KEEP=1 ./run-r4-test.sh'
Anima work item: WI-456 `01a0e388-0729-7da2-9fac-747b889a2020` Stacked on #6 (`r2-sync`). Pins illumos-ddi `r4-virtio` `be78455670` (illumos-ddi #6, stacked on its #5). **Status: code complete and verified in a QEMU guest** (Hephaistos, QEMU 6.2, `-device virtio-gpu-gl-pci -display egl-headless`, virglrenderer 0.9.1 on the host's AMD GPU), including Mesa's virgl driver rendering through `virtio_gpu` to the screen. The guest runs found three bugs and the final review of their evidence a fourth, all fixed here and re-run on the device (see *Fixes from the guest runs*). This PR was first opened while the test host was down, with the verification marked pending; that original section is kept at the end under *History*. ## What was built - **Driver `drivers/virtio-gpu`** (module `virtio_gpu`, PCI `1af4:1050`), on illumos-ddi's `ddi::private::virtio`: - It negotiates `VIRGL`, `EDID`, `RESOURCE_BLOB` and `CONTEXT_INIT` when offered. The control queue carries every request and the cursor queue carries cursor updates. - Requests encode `virtio_gpu_ctrl_hdr` and complete in thread context on the framework's task queue, and waiters also poll. Fenced requests (`SUBMIT_3D`, the 3D transfers) take their fence id under the submission lock and signal R2 `Fence`s in the device's per-context order. - It queries capsets (virgl, virgl2) with a cache, reads display info, and reads the EDID. - **GEM objects** are R1 `SysMem` bound for DMA against the device's node, and their cookies are the `ATTACH_BACKING` (or blob) memory entries: - 2D resources for dumb buffers and non-virgl mode, 3D resources, and guest-memory blobs (`BLOB_MEM_GUEST`, `BLOB_MEM_HOST3D_GUEST`). - A handle attaches the resource to the file's virgl context; removing the handle detaches it. Closing the file destroys the context. - Destroying an object waits for `RESOURCE_UNREF` before freeing its memory, and leaks the memory if the device never answers. - **Ioctls** follow Linux 6.12's checks and errnos: `MAP`; `EXECBUFFER` (32-, 40- and 64-byte layouts; `FENCE_FD_IN`/`OUT` through R2 sync files; in and out sync-object arrays including timelines and `SYNCOBJ_RESET`; rings with `RING_IDX`); `GETPARAM` (`3D_FEATURES`, `CAPSET_QUERY_FIX`=1, `RESOURCE_BLOB`, `HOST_VISIBLE`=0, `CROSS_DEVICE`=0, `CONTEXT_INIT`, `SUPPORTED_CAPSET_IDs`, `EXPLICIT_DEBUG_NAME`); `RESOURCE_CREATE`; `RESOURCE_INFO`; `TRANSFER_FROM_HOST` and `TRANSFER_TO_HOST` (also in the 36-byte layout); `WAIT`; `GET_CAPS`; `RESOURCE_CREATE_BLOB`; `CONTEXT_INIT`. The driver reports version 0.1.0, which Mesa's virgl winsys requires. - **Display:** - Each scanout gets a connector, encoder, CRTC, primary plane and cursor plane. EDID comes from the device, with a CVT mode and the standard modes as the fallback. - The primary plane uses `SET_SCANOUT`, with `TRANSFER_TO_HOST_2D` for dumb buffers and `RESOURCE_FLUSH`. The cursor uses the cursor queue. - `DIRTYFB` sends one transfer and flush of the damage's bounding box. - Page-flip events come from R3's software vblank, one per active CRTC. - The bus ID is `pci:0000:BB:DD.F`, which Xorg's modesetting driver matches. - **Core hooks** (small, host tests unchanged and passing): `GemObject::handle_opened`, `handle_closed` and `release`; `Driver::file_close` and `Driver::dumb_object`; `KmsDriver::dirty_fb` (the default is still `ENOSYS`); `SyncCore::sync_file_fence` made public; `Plain` for the virtgpu uAPI structures. - **uAPI:** - `drm-uapi` is regenerated with `virtgpu_drm.h` from Linux v6.12. The header is MIT-licensed; its source URL and SHA-256 are in `tools/uapi/include/README`. libdrm 2.4.109's copy lacks `RESOURCE_CREATE_BLOB`, `CONTEXT_INIT`, the later parameters and the sync-object arrays. - Grown structures have a command number per size under the illumos encoding. `virtgpu_compat.rs` declares the older layouts: `EXECBUFFER` at 32 bytes (libdrm 2.4.109) and 40 bytes (Mesa 21.3), and the 36-byte transfers. - `tools/uapi/virtgpu_compat_layout.c` checks those layouts against the original headers, and `abi.rs` pins every virtio-gpu ioctl number. - **Packaging:** - `packaging/virtio-gpu.p5m` delivers the module with a `driver` action (`alias=pci1af4,1050`, `perms="* 0666 root sys"`, and a `devlink` for `/dev/dri`). - `packaging/xorg.conf.d/20-virtio-gpu.conf` configures modesetting with `kmsdev` `/dev/dri/card0` and glamor. - `devlink.tab` gets the virtio_gpu line. - **Tests:** - `tools/test/drm_r4_test.c` covers the parameters, capsets and dumb buffers. With virgl, it also sends a minimal virgl command stream (surface, framebuffer, clear) through `EXECBUFFER` and checks the pixels read back with `TRANSFER_FROM_HOST`; chains fences across the three layouts; covers sync objects and a timeline wait that times out; imports a buffer into the render node's context with PRIME; creates blobs and runs `CONTEXT_INIT`; checks every refusal; and runs 2000 submissions in a row plus 8 threads at once. - `tools/test/run-r4-test.sh` links, checks symbols, runs `add_drv`, runs the test and modetest, checks that detach is refused while a file is open and while only a dma-buf is left, then unloads and checks that `/etc` and `/devices` are restored. - Host tests of the driver's pure logic: `cargo test -p virtio_gpu --no-default-features`. - **CI** runs the driver's host tests, and builds and links the module with `-N misc/virtio -N fs/specfs`. ## Decisions - The driver is a crate in this workspace. The core is linked statically, as in `rdrmnull`, with `-N misc/virtio -N fs/specfs`. - Completions run in thread context: the wrapper's task queue, plus waiters that poll. So `Driver::fence_priority` is `None`, and no driver lock has an interrupt priority. - The GEM references that requests hold are dropped through the interrupt-safe (deferred) path. `RESOURCE_UNREF` is therefore never awaited on the completing thread. - `Mesa`: oi-userland `hephaistos/virgl-gallium` (`d69854c287`) was built on oibuild in `/ws/toasty` with `-j2`, and published as `x11/library/mesa@21.3.9-2025.0.0.90` with `COMPONENT_REVISION=90` so that it outranks the installed 21.3.9. No packages were installed on oibuild and `env-prep` was not run. The worktree-local repo was created with `pkgrepo create`. The guest run showed that revision 90 crashes in `virgl_disk_cache_create` (it reads a GNU build ID that illumos' link-editor does not emit), so the oibuild worktree gained `patches/09-virgl-disk-cache-build-id.patch` (commit `4aa9a85809`, uses `disk_cache_get_function_identifier`, which falls back to the library's mtime) and was republished as revision 91 (`mesa-virgl-r4-91.p5p`, SHA-256 `1fb443ad…`). Revision 91 was published from the worktree's local branch `r4/xorg-glamor` at `4aa9a85809`, which is `d69854c287` plus five xorg-server test commits (the abandoned glamor build) plus the Mesa patch; only the patch touches Mesa. Nothing was pushed upstream. The crash itself was seen in the guest but its stack was not saved; the static evidence (the unpatched `build_id_length(note)` on a NULL note with the assert compiled out, and no note section in the built `virtio_gpu_dri.so`) is in `logs/oibuild/mesa-virgl-r4/build-id-evidence.log`. ## Deviations - `HOST_VISIBLE` is 0 and `BLOB_MEM_HOST3D` blobs are refused with `EINVAL`: the gate framework has no shared-memory regions, as the work item expected. - `CROSS_DEVICE` is 0 (no resource UUIDs). - A non-zero `POLL_RINGS_MASK` is `EINVAL`, because the core has no per-file event queue outside KMS. - Blob framebuffers cannot be scanned out: `SET_SCANOUT_BLOB` is not implemented. With `HOST_VISIBLE`=0, Mesa does not use them. - The `EXECBUFFER` command stream is limited to 1 MiB (Mesa 21.3 sends at most 266,240 bytes). - After an `EXECBUFFER` is queued, adding its fence to the reservations, the out sync objects or a new sync file can still fail for lack of memory. The ioctl then reports an error for work that runs anyway. Linux reserves these first. - Contexts are named `pid N`, because the DDI has no process name. - `CONTEXT_INIT` is `EINVAL` without `VIRTIO_GPU_F_CONTEXT_INIT`, which QEMU 6.2 does not offer. On such a host only that path can be exercised. ## Verification (counts and logs) Done: - Host checks with `--locked` on the pinned illumos-ddi: check, clippy `-D warnings` (also with `rdrmnull/panic-drill`), fmt, rustdoc `-D warnings`. Tests: `drm` 109, `drm-uapi` 1, `virtio_gpu` 5, and the host tests caught a real bug in response checking. `xtask uapi-check`: 111 sizes, 497 offsets, 121 ioctl numbers identical to gcc 14.3.0 on illumos (`tools/uapi/drm_layout.oibldofgate.out`, which now includes the compat layouts). The kernel archives of `virtio_gpu` and `rdrmnull` build with nightly-2026-04-16. Log: `logs/r4-host-checks-illumos-drm.log`. - Link check on oibldofgate (illumos `cda5b9a49f`, the golden guest's kernel), with nothing loaded: `virtio_gpu` links with `NEEDED misc/virtio, fs/specfs` and all 127 of its undefined symbols are exported by the running kernel; `rdrmnull` has 106 of 106. Log: `logs/oibldofgate/20260930-r4-kmod-link.log`. - illumos-ddi `kernel-check` of the virtio crate against that kernel: 48/48 symbols from `virtio`. Log: `logs/oibldofgate/20260930-r4-virtio-kernel-check.log`. - IPS package: `pkglint` clean, published and received as a p5p. Log: `logs/oibuild/20260930-r4-virtio-gpu-package.log`; artifact `artifacts/r4-virtio-gpu/package/`. - Mesa: `gmake install` (1558 ninja steps, `virtio_gpu_dri.so` in the proto area) and `gmake publish` both exit 0. Logs: `logs/oibuild/mesa-virgl-r4/`; artifact `artifacts/r4-virtio-gpu/mesa/mesa-virgl-r4.p5p`. - `drm_r4_test.c` compiles with `gcc -Wall -Wextra` on illumos. - Two local review rounds (Anima rules, Opus). Round 1 found 4 blockers and 9 should-fix items; all were addressed, and the two illumos-ddi type rules are in its PR. Round 2 found no code defects and rejected only because the guest run is missing. Guest runs on Hephaistos (2026-09-30; fresh overlays of the golden Hipster image, illumos `cda5b9a49f`, 2 vCPUs, 3 GiB, private user networking, bounded lifetime; ports 2360-2364; all overlays deleted afterwards, nothing left running). Logs are in the workspace under `logs/hephaistos/illumos-drm/`, screenshots under `artifacts/r4-virtio-gpu/screens/`, the results note is `notes/r4-virtio-gpu-verification.md`. No run panicked. - **Host capabilities**: QEMU 6.2 offers `virtio-gpu-gl-pci`, `virtio-gpu-pci` and `egl-headless`; libvirglrenderer 0.9.1; `/dev/dri/renderD128` on the host. Log `20260930-r4-host-preflight.log`. - **Two guest-setup traps** (not driver bugs): a virtio-gpu at an automatic PCI slot moves the disk and NIC (the golden image's network then fails), so the GPU sits at `addr=0x10`; and at illumos `cda5b9a49f` the virtio framework caches the BAR register number of the first modern device (illumos bug 18358, fixed upstream in `36d8c52c14`), so `virtio_init` for the GPU failed with "Failed to map CAP 1 @ BAR4" behind the transitional vioblk. The runs attach the disk with `disable-modern=on` instead. Logs `20260930-r4-run2-driver.log`, `20260930-r4-run2-bar-cache.log`; documented in illumos-ddi #6 (`docs/DESIGN.md`). - **Attach** (`dmesg`): `virtio_gpu0: virtio-gpu: 1 scanout(s), features 0x110000003 of 0x130000003 (virgl true, edid true, blob false, context_init false), 2 capset(s) 0x6, modern interface`. - **`run-r4-test.sh`: PASS, 74 checks, 0 failures** (r4-run5, driver from `c4318271eb`, whose code is that of `7dda62f`; the rebase only moved `virgl_egl_test.c` into its own commit; `virtio_gpu.a` SHA-256 `c909e777…f7e6`). Log `20260930-r4-run5-driver.log`. - `drm_r4_test` 63/63, including the minimal virgl command stream (surface, framebuffer, clear) read back from the host renderer with `TRANSFER_FROM_HOST`, fences across the 32/40/64-byte `EXECBUFFER` layouts, binary and timeline sync objects, PRIME into another file's context, 2000 submissions in a row, and 8 threads creating, clearing, fencing, reading back and closing 800 textures at once. - Negative tests: unknown `EXECBUFFER` flags `EINVAL`; a timeline wait times out with `ETIME` after 100 ms; `CONTEXT_INIT`-only rings refused; unknown handles and sync objects, bad strides, oversized and unreadable streams refused. - modetest: the device's EDID (1024x768 at 75 Hz preferred, 12 more modes), mode set, page flips with vblank events at the mode's 75 Hz, cursor, atomic commit. Screendump during flips: `20260930-r4-run3-modetest-vsync-gpu0.png` (SMPTE bars). - Unload with outstanding objects: `modunload` refused while a process holds a file, a dumb buffer and a dma-buf, and while only a dma-buf is left; the device works again afterwards; then it unloads, and `/etc` and `/devices` are as before. At detach: 19,543 requests, 7,224 fenced, 0 failed, 5 queue-full waits, 0 timeouts, 2,011 resources created, 0 left. - **R0-R3 regression** with `rdrmnull` in the same boot: `run-r1-test: fail=0` (R0, R1 and R2 suites, 0 failures each) and `run-r3-test: fail=0`. Logs `20260930-r4-run5-regression-r1.log`, `20260930-r4-run5-regression-r3.log`. - **Xorg modesetting**: stock `x11/server/xorg@1.19.7-2026.0.0.14` and `x11/demo/mesa-demos@8.5.0` installed from the openindiana.org publisher into the overlay (`20260930-r4-run5-x-install.log`) with `packaging/xorg.conf.d/20-virtio-gpu.conf`: modesetting opens card0, reads the EDID, runs 1024x768 with damage through `DIRTYFB` (`20260930-r4-run5-Xorg.1-stock.log`, screenshot `20260930-r4-run5-xorg-stock-gpu0.png`). OpenIndiana's Xorg is built without glamor ("No glamor support in the X Server", "AIGLX: Screen 0 is not DRI2 capable"), so `glxinfo -B` reports **softpipe**, not virgl (`20260930-r4-run5-glxinfo-stock-xorg.log`), and `glxgears` runs at about 180 FPS in software, shown on the virtio-gpu scanout (`20260930-r4-run5-glxgears-softpipe.log`, `20260930-r4-run5-glxgears-softpipe-gpu0.png`). A glamor rebuild of Xorg on oibuild failed (xtrans 1.6 and gcc 14 errors; the last attempt's log is `logs/oibuild/mesa-virgl-r4/xorg-glamor-publish.log`, failing in `Xtranssock.c` on `msghdr.msg_control`) and was abandoned. The stock-Xorg screenshot `20260930-r4-run5-xorg-stock-gpu0.png` is black (an empty root window); the scanout of X's damage is shown by the glxgears screenshot. - **Mesa's virgl driver** (rev 91): `pkg install` of the p5p in the guest is impossible (it depends on osnet 23293, the golden image has 23197), so its payload (tar SHA-256 `be86a844…65b4`, 104 files, each listed in `20260930-r4-run5-mesa-overlay.log`; `virtio_gpu_dri.so` SHA-256 `c300f510…`) was extracted over the stock Mesa 21.3.9 in the overlay only, never the golden image. OpenIndiana's libdrm 2.4.109 only enumerates device nodes named `display`, so without help EGL fails with "DRI2: failed to find EGLDevice" (`20260930-r4-run5-virgl-egl.log`); the tests load `tools/test/drm_devshim.c` with `LD_PRELOAD_64` to answer `drmGetDevice2` for the device. - `tools/test/virgl_egl_test.c` (EGL on GBM, render node): **`GL_RENDERER: virgl`**, `GL_VERSION: 3.1 Mesa 21.3.9`, a cleared 256x256 FBO reads back exactly, 600 clear-and-read-back frames at about 1,300 per second, 0 failures (`20260930-r4-run5-virgl-egl-shim.log`). - `tools/test/virgl_kms_gears.c` (GBM scanout surface on card0, page flip per frame, waiting for each flip event): renderer virgl, **600 frames at 74.8 fps on the 75 Hz mode**, 0 failures; QMP screendump of the virgl-rendered frame `20260930-r4-run5-virgl-kms-gears-gpu0.png`. Afterwards `modunload` succeeded: 18,762 requests, 3,011 fenced, 0 failed, 8 resources created, 0 left (`20260930-r4-run5-virgl-kms-gears.log`). - Observed, not this driver: after SIGTERM, Xorg :1 stayed blocked in `xf86CloseConsole` (`VT_ACTIVATE`) holding card0, and needed SIGKILL before the unload. - **Final run r4-run6 at `8e15c99b50`** (after the final review round's fix below; `virtio_gpu.a` SHA-256 `3f6d912c…3519`, `rdrmnull.a` from the same commit), port 2365: - `run-r4-test.sh`: PASS, 74 checks, including its `/dev/dri` cleanup (`20260930-r4-run6-driver.log`). Detach: 19,522 requests, 7,224 fenced, 0 failed, 4 queue-full waits, 0 timeouts, 2,011 resources, 0 left. - The review's scenario on the device: a legacy cursor set on a CRTC that is off (cursor plane 22 on CRTC 23 with fb 29), the file closed, then `modunload` succeeds (`20260930-r4-run6-cursor-close.log`, program `20260930-r4-run6-cursor_close.c`). - R0-R3: `run-r1-test: fail=0`, `run-r3-test: fail=0` (`20260930-r4-run6-regression-r1.log`, `-r3.log`). - Mesa (stock `x11/library/mesa` and `x11/library/libdrm` from the publisher, rev 91 payload over it, `20260930-r4-run6-mesa-overlay.log`): `virgl_egl_test` 0 failed with `GL_RENDERER: virgl`; `virgl_kms_gears` 600 page-flipped frames at 75.0 fps; screendump `20260930-r4-run6-virgl-kms-gears-gpu0.png`; clean `modunload` afterwards (`20260930-r4-run6-virgl.log`). Xorg was not rerun. - Guest consoles for all runs: `logs/hephaistos/illumos-drm/r4-console/`. - **Host checks at the final head** `55d8e6011d`: check, clippy `-D warnings` (also with `rdrmnull/panic-drill`), fmt, rustdoc, tests (`drm` 111, `drm-uapi` 1, `virtio_gpu` 5), `uapi-check` 0 differences. Log `logs/20260930-r4-host-checks-final-illumos-drm.log`. ### Fixes from the guest runs - `a1d0785` **kms (core)**: a CRTC turned off by a close or `RMFB` now takes its other planes with it. `modetest -C` left a legacy cursor framebuffer (owned by no file) on the dark CRTC, so detach was refused with no file open. New host test `close_turns_off_the_cursor_of_the_crtc_it_turns_off` fails without the fix. - `7dda62f` **virtio_gpu**: the driver no longer keeps a `KArc<FenceDomain>`; it takes the domain from the device's sync core per submission. Holding it meant the core's "fences or sync objects remain" check refused every unload. - `4ad90da`, and the rate check in `a1d0785`, **run-r4-test.sh**: the page-flip rate is compared with the mode's refresh rate (QEMU's EDID prefers 75 Hz), and the script removes `virtio_gpu`'s `/dev/dri` links at the end so later suites start clean. - `8e15c99` **kms (core), from the final review round**: a file's close also turns off the legacy cursors it set. `add_fb` takes an `FbOwner` (`File` or `Cursor`), and the internal cursor framebuffer records the file whose `CURSOR` call made it. Without this, a cursor set on a CRTC that is off (or left by `SETCRTC` turning the CRTC off) outlived its master and kept `virtio_gpu`'s detach refused. Linux leaves such cursors on; the README explains the difference. New host test `close_turns_off_the_legacy_cursors_the_file_set`, which fails without the change; verified on the device in r4-run6. - `72256f3` **tools/test**: `virgl_egl_test.c`, `virgl_kms_gears.c`, `drm_devshim.c`. `7dd280a`, `03f8109`, `55d8e60` README; `d02a5bc` the Xorg snippet documents the no-glamor case. ### Local review rounds - Round 1 (code): reject, 4 blockers and 9 should-fix items, all addressed. - Round 2 (code): no code defects; reject only because the guest run was missing. - Round 3 (runtime evidence, after the runs above): approve, no blockers. Should-fix items: the cursor-on-a-dark-CRTC case (fixed in `8e15c99`, re-run in r4-run6); two claims without logs (the rev-90 crash, now backed by static evidence and marked as such; the Xorg glamor failure, log added); and the Mesa branch name (corrected above). Notes: the driver package p5p in the workspace was built from an earlier commit (`72397ee39e`; only `pkglint` and publishing were claimed, and it should be rebuilt from the merged head before any publication); the run3 SMPTE screenshot predates the fixes (r4-run6's virgl screendump is at the final head). ## Open issues - GLX with virgl under X: needs an OpenIndiana Xorg built with glamor (DRI2/DRI3 in modesetting). - libdrm (gfx-drm) device enumeration: match minors of node type `ddi_display:drm` instead of the node name `display` (and fix the PCI path parsing); until then Mesa needs `drm_devshim.c` for virtio-gpu. Workspace note `notes/mesa-component.md`, libdrm item 6. - illumos bug 18358 in the guest's kernel (fixed upstream after `cda5b9a49f`): a second modern virtio device fails; the runs use a transitional disk. - The Mesa build-ID patch (oi-userland `hephaistos/virgl-gallium` branch, local) and a Mesa package whose dependencies match the installed osnet. - `SET_SCANOUT_BLOB`, host-visible blobs (they need shared-memory regions in the gate's virtio framework), resource UUIDs, and polled-ring fence events. - Pre-reserving `EXECBUFFER`'s fence slots, chains and fd before queueing. - Moving the illumos-ddi pin to `main` once the stacked branches merge. ## History The first version of this PR (head `298fec2438`) was opened while Hephaistos was down. Its verification section read: > Pending, all on a QEMU guest (Hephaistos, `-device virtio-gpu-gl-pci`, `-display egl-headless` or `gtk,gl=on` under Xvfb): > - The host's QEMU capabilities (`virtio-gpu-gl`, `egl-headless`, virglrenderer). > - The attach lines in `dmesg`. > - `run-r4-test.sh`, including the threaded part and the negative tests: unknown `EXECBUFFER` flags return `EINVAL`, the fence wait times out, and detach is refused while objects are outstanding. > - modetest: mode set, vsync, cursor, atomic. > - The Xorg modesetting log, `glxinfo -B` showing virgl, the `glxgears` frame rate, and a QMP `screendump` of `gpu0`. > - The R0–R3 regression suites with `rdrmnull`. > > The guest bundle is staged in `artifacts/r4-virtio-gpu/guest-bundle/` (`virtio_gpu.a` SHA-256 `1dd62fc6…dfa8`, built at `298fec2438`). Commands: > > ```sh > bin/ssh-illumos hephaistos 'cd ~/illumos-drm-test/20260928 && qemu-img create -f qcow2 -F qcow2 -b $PWD/golden.qcow2 r4-run1.qcow2 && bin/start-guest-gpu.sh r4-run1 $PWD/r4-run1.qcow2 2360 3h gl egl' > tar -C artifacts/r4-virtio-gpu/guest-bundle -cf - . | artifacts/illumos-drm-hephaistos/guest-ssh 2360 'mkdir -p /root/r4 && tar -xf - -C /root/r4' > artifacts/illumos-drm-hephaistos/guest-ssh 2360 'cd /root/r4 && KEEP=1 ./run-r4-test.sh' > ```
GemObject::handle_opened and handle_closed run around every handle's
creation and removal (Linux's gem open and close callbacks), outside the
GEM locks; GEM_OPEN and PRIME imports call the hook between their two
critical sections. GemObject::release runs when the object is destroyed,
in thread context, before its memory goes, so that a driver can tell the
device to stop using it. Driver::file_close runs after a file's handles
and sync objects are gone (Linux's postclose). KmsDriver::dirty_fb
receives DIRTYFB with the planes that show the framebuffer and the clip
rectangles; the default still answers ENOSYS. SyncCore::sync_file_fence
is public for submissions that take an in-fence.
libdrm 2.4.109's virtgpu_drm.h has no RESOURCE_CREATE_BLOB, CONTEXT_INIT,
the later VIRTGPU_PARAM values or the sync object arrays of EXECBUFFER.
generate.sh now takes include/uapi/drm/virtgpu_drm.h of Linux v6.12 (MIT
per its header; source and SHA-256 in tools/uapi/include/README) in its
place and regenerates the bindings.

Structures that grew have one command number per size, so the older
layouts userland still uses are declared by hand in virtgpu_compat.rs:
the 32-byte EXECBUFFER and 36-byte transfers of libdrm 2.4.109 and the
40-byte EXECBUFFER of Mesa 21.3's own copy. virtgpu_compat_layout.c prints
them from the original headers; with drm_layout.c, gcc 14.3.0 on
oibldofgate (illumos-cda5b9a49f) agrees with the Rust definitions on 111
sizes, 497 offsets and 121 ioctl numbers. abi.rs pins the virtio-gpu
command numbers too.
A driver whose objects need more than memory (a host resource for
virtio-gpu) makes the object of a dumb buffer in the new
Driver::dumb_object hook; the default still converts the memory with
From. The virtio-gpu argument structures are Plain, with their sizes
asserted.
A new crate, drivers/virtio-gpu (module virtio_gpu, PCI 1af4:1050), on
illumos-ddi's ddi::private::virtio: negotiates VIRGL, EDID,
RESOURCE_BLOB and CONTEXT_INIT, runs every request through the control
queue and the cursor through the cursor queue, and completes requests in
thread context. Fenced requests signal R2 fences in the device's fence
order; completions drop the GEM references they held through the
interrupt-safe path, so that RESOURCE_UNREF is never waited for on the
completing thread.

GEM objects are R1 system memory whose DMA cookies are the resources'
memory entries: 2D resources for dumb buffers and without virgl, 3D
resources, and guest-memory blobs. Handles attach resources to the
file's virgl context; destruction waits for RESOURCE_UNREF before the
memory goes.

The ioctls of Linux 6.12: MAP, EXECBUFFER (32-, 40- and 64-byte layouts,
fence descriptors, sync object arrays), GETPARAM, RESOURCE_CREATE,
RESOURCE_INFO, TRANSFER_FROM_HOST and TO_HOST (also 36-byte), WAIT,
GET_CAPS, RESOURCE_CREATE_BLOB, CONTEXT_INIT. Display: a connector,
encoder, CRTC, primary and cursor plane per scanout, EDID from the device,
SET_SCANOUT/TRANSFER_TO_HOST_2D/RESOURCE_FLUSH, DIRTYFB, the cursor queue
and software vblanks for page-flip events.
tools/test/drm_r4_test.c drives the device through the virtio-gpu
ioctls: parameters, capability sets, dumb buffers as 2D resources, and
with virgl a minimal command stream (surface, framebuffer, clear) whose
result is read back with TRANSFER_FROM_HOST, fence descriptors across the
three EXECBUFFER layouts, binary and timeline sync objects, a timeline
wait that times out, PRIME into the render node's context, guest-memory
blobs, CONTEXT_INIT, every refusal, 2000 submissions in a row and eight
threads at once. run-r4-test.sh links the module (-N misc/virtio
-N fs/specfs), checks its symbols, add_drv's it for pci1af4,1050, runs the
test and modetest, and checks that a detach is refused while a file or
only a dma-buf holds the device.

packaging/virtio-gpu.p5m delivers the module with its driver action
(alias, 0666 nodes, the /dev/dri devlink) and an Xorg snippet for the
modesetting driver with glamor; devlink.tab gains the virtio_gpu line.
- CONTEXT_INIT checks its parameters as Linux does (each once, a
  capability set the device has, at most 64 rings, no polled rings) in a
  pure function, and sets and creates the context under one hold of the
  context lock, so a concurrent second call gets EEXIST.
- An in-fence is skipped only when it is on the submission's own fence
  context; fences of other rings of the same file are waited for.
- DIRTYFB transfers and flushes the bounding box of the damage once.
- Blob framebuffers are refused for scanout (they would need
  SET_SCANOUT_BLOB).
- check() no longer takes a missing response (0) for the expected one
  when none is named; resource ids stop at the maximum instead of
  wrapping; more than 64 capability sets is logged; a fenced request
  dropped unsignalled is reported (the core refuses a detach while fences
  live, so it cannot happen).
- Host tests of the pure logic (cargo test -p virtio_gpu
  --no-default-features; the kernel feature brings the ddi panic handler
  and allocator) and CI steps that run them and build and link the
  module with -N misc/virtio -N fs/specfs.
CI: build virtio_gpu --locked; note on CONTEXT_INIT retries
Some checks failed
ci / check-hosted (pull_request) Failing after 3m19s
ci / kmod-illumos (pull_request) Successful in 5m54s
298fec2438
Found by the R4 run: modetest -C sets a legacy cursor, whose framebuffer
belongs to no file; closing the file turned the CRTC off but left the
cursor plane on it, holding the framebuffer, so virtio_gpu's detach was
refused with no file open. disable_fbs now turns off every plane of a
CRTC it turns off, as nothing on a dark CRTC can be shown. Host test.

run-r4-test.sh: the page-flip rate is checked against the mode's
refresh rate (QEMU's EDID prefers 1024x768 at 75 Hz).
Found by the R4 run: the driver kept a counted reference to the DRM
device's fence domain for its fenced requests, so the core's detach
check always found the domain in use ("fences or sync objects remain"
with every count at zero) and the module never unloaded. The driver now
keeps only its fence context number and the ioctls pass the domain in.

run-r4-test.sh: modetest prints the mode after the rates; compare in END.
devfsadm -C left them dangling, and the R1 regression script run next in
the same guest found /dev/dri changed.
virgl_egl_test: a surfaceless desktop GL context through EGL on a GBM
device on the render node; checks that the renderer is virgl, reads back
a cleared framebuffer object and times 600 frames.

virgl_kms_gears: renders with virgl to a GBM scanout surface on the
primary node and shows every frame with a page flip, waiting for the
flip event, then holds the last frame for a host screendump.

drm_devshim: an LD_PRELOAD_64 aid that answers libdrm's drmGetDevice2
family for the guest's virtio-gpu function. OpenIndiana's libdrm only
finds device nodes named "display" (VGA-class PCI functions), so Mesa's
loader and EGL find no device for virtio-gpu (PCI class 0x0380).
README: R4 verified in a QEMU guest; Mesa's virgl driver and its workarounds
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
7dd280a73d
20-virtio-gpu.conf: what happens on an Xorg without glamor
Some checks failed
ci / check-hosted (pull_request) Failing after 8m32s
ci / kmod-illumos (pull_request) Successful in 9m48s
d02a5bc4d0
Review of the R4 runs: a1d0785 only turned the cursor off with the CRTC
a close turns off. A legacy cursor set on a CRTC that is off (never
turned on, or turned off by SETCRTC, which keeps the cursor as Linux
does) still survived its master's close; its internal framebuffer
belongs to no file, so it stayed referenced and virtio_gpu's detach was
refused with no file open until another master hid the cursor.

add_fb now takes an FbOwner: File(id) as before, or Cursor(id) for the
internal framebuffer of a legacy CURSOR call, recorded as the
framebuffer's cursor_of. file_close also turns off the planes that show
the closing file's cursor framebuffers. This differs from Linux, which
leaves them on; README says why. Host test, which fails without the
change.
README: the final run
Some checks failed
ci / check-hosted (pull_request) Has been cancelled
ci / kmod-illumos (pull_request) Has been cancelled
03f81097e7
README: what the final run covered
Some checks failed
ci / check-hosted (pull_request) Failing after 10m2s
ci / kmod-illumos (pull_request) Successful in 5m7s
55d8e6011d
virtio_gpu: leave the module entry points out of host unit tests
All checks were successful
ci / check-hosted (pull_request) Successful in 3m53s
ci / kmod-illumos (pull_request) Successful in 21m1s
b6d2e449b6
A host test binary is an executable whose C runtime defines _init and
_fini (crti.o on Linux), so linking the module's _init/_fini/_info into
it fails with duplicate symbols on the Linux CI runner (macOS has no
such symbols, so the tests passed there). The module linkage is only
needed in the kernel module.
toasterson changed target branch from r2-sync to main 2026-10-05 16:39:15 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
illumos/illumos-drm!7
No description provided.