R0: drm-uapi crate and DRM core with card/render minors (WI-452) #1
Loading…
Reference in a new issue
No description provided.
Delete branch "r0-uapi-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Milestone R0 of the Rust DRM core (Anima WI-452): the uAPI crate, the DRM core library with card and render minors, per-file state and the core ioctls, a
Drivertrait and a null driver. It was built, loaded and tested with libdrm 2.4.109 on oibldofgate.What was built
crates/drm-uapi: the#[repr(C)]structures and constants ofdrm.h,drm_mode.handvirtgpu_drm.hfrom libdrm 2.4.109.tools/uapi/generate.sh, targetx86_64-pc-solaris2.11, illumos-gate system headers) from the release gfx-drm builds (same SHA-256), with gfx-drm's illumosdrm.hpatch vendored intools/uapi/patches.DRM_IOCTL_*numbers are generated from the same headers in the illumos_IOWRencoding (tools/uapi/gen_uapi.py), because bindgen cannot expand function-like macros.abi.rs, which pins 50 structures (drm_version,drm_get_cap,drm_set_client_cap,drm_gem_close,drm_prime_handle, alldrm_syncobj_*, the atomic and KMSdrm_mode_*, alldrm_virtgpu_*) and the 11 R0 command numbers to the gcc values.crates/drm: ano_stdcore on theddicrate.drm::Driversupplies the name, date, description, major/minor/patch, feature flags (MODESET,ATOMIC,RENDER), mode-setting properties forGET_CAP, and the bus ID.drm::Device<D>createscard<N>andrenderD<128+N>. Every open is a clone open: the clone id sits in bits 9-17, the bits illumos libdrm strips, which allows 511 files per device.DrmFileholds the authenticated flag, the master binding and the client capabilities.VERSION,GET_CAP,SET_CLIENT_CAP,GET_UNIQUE/SET_UNIQUE,SET_VERSION,GET_MAGIC/AUTH_MAGIC,GET_CLIENT,SET_MASTER/DROP_MASTER. They follow Linux's permission flags and semantics: per-master magic namespaces, render nodes without authentication, and a bus ID that stays empty until interface 1.1 is set.drv_priv(9F)runs on the ioctl path only when a permission needs it (SET_UNIQUE, andSET_MASTER/DROP_MASTERby a file that is not a former master of the same process), as Linux callscapable()lazily.GET_CAPreportsADDFB2_MODIFIERS,DUMB_PREFERRED_DEPTHandDUMB_PREFER_SHADOWas 0 until the ioctls they describe exist (R1/R3), whatever the driver'sModeConfig.get/get_mutwith an errno on the unreachable branches.ENOTTY. Commands are matched on their full 32-bit value, since illumos encodes only 8 bits of the size. Core commands from 32-bit callers (ddi_model_convert_from) fail withENOTSUP; other commands from them fail withENOTTY.examples/rdrmnull: the null driver. It registers one device (card0 and renderD128), declaresMODESET,ATOMICandRENDER, and has no hardware. It is the kernel module that is built and loaded, and it is a test module, not something to deploy.packaging/devlink.tabholds the/dev/drirule for packages.xtask: vendored from illumos-ddieb18ab93b7(build, link, deps, kernel-check), with a header comment that lists the changes.lint-manis not vendored (there is no-syscrate here).uapi-dumpanduapi-checkare new.tools/test/drm_r0_test.cis the libdrm test andtools/test/run-r0-test.shthe VM procedure. The two C programs are local test tools, not deliverables..forgejo/workflows/ci.ymlfollows illumos-ddi's setup (hosted check, clippy, fmt, doc, tests and uapi-check; native illumos build and link of rdrmnull). CI has not run yet.Deviations from the work item text
misc/drmkernel module.misc/drmis therefore deferred to R5. Until then, static linking costs nothing, since one Rust driver comes first.ddi_display:drm(DDI_NT_DISPLAY_DRM), not plainddi_display.misc_link'sdisplay()handler, which adds/dev/fbs/<minor>and/dev/fb<N>console framebuffer links. The VM already has/dev/fb0 -> fbs/text-0.ddi_display:drmis gfx-drm's convention. OpenIndiana'sdriver/graphics/drmshipsSUNW_drm_link, which created/dev/dri/card0and/dev/dri/renderD128from it, so no/etc/devlink.tabchange was needed on the VM.packaging/devlink.tab.SET_VERSIONis added because libdrm calls it on primary nodes.GET_CLIENT(index 0, as on current Linux) is an addition beyond the work item, so that the result of authentication can be observed.x11/library/libdrm) but nodrm.h,drm_mode.horvirtgpu_drm.h: they belong tosystem/header/header-drm, which is not installed, and I installed nothing. The C layout program was therefore compiled with gcc 14.3.0 on the VM against the patched libdrm 2.4.109 headers, copied to/root/illumos-drm-test/uapi/drm. That patched header is exactly what gfx-drm compiles the installedlibdrm.soagainst.illumos-ddi change
The dependency is pinned to illumos-ddi branch
drm-r0, reve019d5bd3c:mainplus the following. It is under review as illumos/illumos-ddi#1; once that merges, this repository pins illumos-ddimain.8463d9da92addsCharDevice::clone_opento the module glue. The driver returns a fresh minor, and the glue storesmakedevice(getmajor(dev), minor)throughdevp. The default callsopenand keeps the device number, so existing drivers are unaffected.f36d47958edocuments the 32-bitdev_tlimit for clone minors.e019d5bd3caddsclone_opento theCharDevicedescription indocs/DESIGN.md§5.2.Verification
Host: Mac, aarch64-apple-darwin, Rust 1.97.1. VM: oibldofgate, illumos-cda5b9a49f, OpenIndiana Hipster 2026.04, root, global zone.
cargo check --workspace --target x86_64-unknown-illumoslogs/oibldofgate/20260928-r0-local-checks.logcargo clippy --workspace --target x86_64-unknown-illumos -- -D warningscargo fmt --all -- --checkcargo docwith-D warningscargo test -p drm -p drm-uapi(host)cargo xtask build rdrmnull(nightly-2026-04-16, build-std)86823733d8f9…, identical on the VM (digestin the load-test log)cargo xtask uapi-check)20260928-r0-uapi-layout.logxtask kernel-check --verifyagainstmdb -k(ddi-sys at e019d5bd3c)ddi_ncpus_expectedpostdates this kernel. Same as upstream's 26 Sep result20260928-r0-kernel-check.logld -ztype=kmod, then each undefined symbol resolved with::whatiscrgetuidimport went away in1a0f6eb)20260928-r0-rdrmnull-load-test.logadd_drv -m '* 0666 root sys' rdrmnull, libdrm test as root and as nobody, 32-bit probedrm_r0_test hold /dev/dri/card0, thenmodunload -i <id>modunloadsucceeds, the next open reattachesrem_drv rdrmnullThe R0 structures have no kernel CTF counterpart; they are userland ABI, and the gcc comparison is their layout proof. The DDI layouts the module relies on are checked by kernel-check.
ls -l /dev/driwith the module loaded:What the libdrm test showed:
drmOpen("rdrmnull", NULL)opened card0 as master.drmGetDeviceNameFromFdmapped the clone minor0x200back to/dev/dri/card0.drmGetVersionreturned 1.0.0 "rdrmnull" "20260928".drmGetCap: TIMESTAMP_MONOTONIC 1; PRIME, SYNCOBJ, SYNCOBJ_TIMELINE, DUMB_BUFFER, ADDFB2_MODIFIERS and CRTC_IN_VBLANK_EVENT 0; CURSOR_WIDTH and CURSOR_HEIGHT 64; unknown capabilities EINVAL.drmSetClientCapaccepted and recorded all five capabilities with the Linux rules; bad values were EINVAL.drmSetInterfaceVersion(1.4)madedrmGetBusidreportpseudo:rdrmnull@0.drmSetBusidreturned EINVAL for a foreign ID and EBUSY once set.drmAuthMagicauthenticated it (checked withdrmGetClient); reusing the magic was EINVAL. The client's AuthMagic, SetMaster and DropMaster were EACCES.drmOpenRender(128), as root and as nobody, version and caps work; GET_MAGIC, SET_CLIENT_CAP, GET_UNIQUE and SET_MASTER are EACCES.drmGetClient. Meanwhile the root process dropped and retook master concurrently: 1878 retaken, 468 EBUSY. The number of authentications varies between runs with how often the master is held at the moment ofAUTH_MAGIC(1025 in the run at1a0f6eb).isattywas false.modunloadof rdrmnull failed with "Device busy"; it succeeded once the file was closed. rem_drv is not used for this check, because it removes the driver configuration even when the unload fails.VM left in its prior state:
/usr/kernel/drv./dev/driis removed again. It did not exist before, andSUNW_drm_link's remove rule does not matchcard0, sodevfsadm -Cleaves the links./etcdriver and devlink files have the same SHA-256 as before (20260928-r0-vm-state-before.logand-after.log)./root/illumos-drm-test(8.7 MB) remains;/root/illumos-ddi-testis untouched.All log paths are under
logs/oibldofgate/in the owner's workspace (not in this repository).Concurrency argument
All device state lives in one
DeviceStatebehind oneddi::Mutex. Each open, close and ioctl does its permission check and state change in one critical section; user copies happen outside it; table growth withKM_SLEEPis the only blocking operation under the lock. specfs guarantees oneclose(9E)per clone after the last reference, never concurrent with an ioctl on the same file. The full argument is at the top ofcrates/drm/src/device.rs. It is tested on the host (threads with an invariant check after every step) and in the kernel (the stress run above).Open issues
ATOMIC=1to processes namedX*(the Xorg modesetting DDX). That needs the process name, which no committed DDI interface provides; it is noted incaps.rsfor R3.SUNW_drm_linkremove rule (^dri/[a-z]D?[0-9]+$) does not matchcard0orrenderD128, sodevfsadm -Cleaves dangling/dev/drilinks afterrem_drv. This is a gfx-drm bug worth fixing there.system/header/header-drmships gfx-drm's old kerneldrm.h, not the libdrm 2.4.109 headers libdrm is built with. Packaging should deliver the patched 2.4.109 headers.drmCommandWriteReaduses the 14-bit_IOCsize field from the illumos drm.h patch, not_IOWR. The dispatch for those must accept that encoding.drm-r0branch) must merge before this pins illumos-ddimain.drmGetDeviceNameFromFd._sun_drm_find_device(used bydrmGetDeviceNameFromFd2anddrmGetDevice2) and the stockdrmGetMinorTypedo not, so clone fds will likely not resolve there. That matters for Mesa's loader in R4 and needs a libdrm fix in gfx-drm or a different minor layout.virtgpu_drm.hhas noRESOURCE_CREATE_BLOBorCONTEXT_INIT(added in later libdrm), so their structures and numbers are not indrm-uapiyet; R4 must add them from a newer header with the same layout proof.Anima work item: WI-452
01a0e386-ea75-7031-82e8-cdcc4baf4ddd