R5a: misc/drm_core with a versioned C facade, cdrmnull (C) on it #9
Loading…
Reference in a new issue
No description provided.
Delete branch "r5a-facade"
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?
Anima work item: R5a
01a0f883-0bd5-7c83-a6b3-9f0848a39255The DRM core as one kernel module,
misc/drm_core, with the first versioned C facade (include/drm), andcdrmnull, a C port ofrdrmnullthat proves the facade. Stacked on #8 (g6-minors); needs illumos-ddir5a-char-table(pinned at10bdfba, illumos-ddi PR #8, stacked on its #7).Rename: the work item asked for
misc/drm; the module ismisc/drm_core(cratedrm-module,drm_core.mapfile, packagedriver/graphics/drm-core), because gfx-drm's legacy C core is/kernel/misc/amd64/drmindriver/graphics/drm, which libdrm requires. Both packages install together; the two stacks are never loaded at once:misc/drm_core's_initrefuses withEBUSYand a warning while the legacydrmmodule is loaded (the symmetric guard in gfx-drm is a separate item).What was built
modules/drm_core(misc/drm_core):drm-core(renamed fromcrates/drm, featurekernelfor the stateful layer) monomorphised once over a facade driver (CDriver,FObj,CKms); the device table and character entry points (drm_open…drm_segmap,drm_getinfo,DRM_CB_OPS) over illumos-ddi'sCharTable/table_glue; the device numbers (absorbsmisc/drm_minor); a module fence domain (drm:0:sync) fordma_fence_initon drivers' structures; per-thread ioctl frames fordrm_copy_*and fd creation; 98 facade functions plusdrm_debug.ld -B reduce -M modules/drm_core/drm_core.mapfileleaves exactly_init,_fini,_infoand the facade (102 globals); the test scripts and CI compare the module's globals with the mapfile.tools/facade/gen_facade.pygeneratesdrm_core.mapfile, the drivers'include/drm/drm_facade.mapfile,facade_layout.cand xtask's table from the bindings;tools/facade/check-generated.sh(CI) checks they are current (and regenerates the bindings with bindgen where a gate is available).drm_facade_version(struct drm_facade_version *)reports major/minor and the sizes of 28 structures (append-only list). Policy: major on any size/offset/meaning change or removal, minor on additions; a driver loads only on the same major, a core minor ≥ its own and identical sizes. C drivers calldrm_facade_check()in_init; Rust drivers calldrm_facade::check_facade()fromddi::Driver::load;drm_dev_alloc()checks again. Version 0.1, unstable.crates/drm-facade-sys(bindgen ofinclude/drm, 98 functions, 38 structs, 233 offset tests) andcrates/drm-facade(safe layer:Driverconsts → staticstruct drm_driver, one ioctl thunk,GemObject→drm_gem_object_funcs, KMS throughdrm_rkms_funcs, owning handles whose drops are the facade's puts).rdrmnullandvirtio_gpuuse only the facade,-N misc/drm_core. Generic code stays in the module: the facade is non-generic C over#[repr(C)]; drivers compiledrm-corewithoutkernel(value helpers only), and CI/tests check that no driver carries a stateful core symbol (pattern generated from module names, with a positive control on the core's archive).ctfconvertdoes not read Rust DWARF, somodules/drm_core/ctf/drm_facade_ctf.c(names every facade struct) is compiled with DWARF, converted with the gate'sctfconvert -l drm, stripped of DWARF (57 KB) and linked in: a standalone container of 2664 types;mdb -kprints::print -t struct drm_deviceand live devices;kernel-checkverifiesdrm-facade-sysagainst it.drivers/cdrmnull(C,build.shwith the gate's kernel flags,-N misc/drm_core -z defs -M ddi.mapfile -M include/drm/drm_facade.mapfile -M private.mapfile): device, dumb buffers, movable objects, PUT_LATER, HOLD, the R2 fence timeline (soft interrupt), BO_WAIT,PRIME_SELFTEST(dma_buf_get/import/export/fd) andFENCE_SELFTEST; its detach racesdrm_dev_unregisteragainst facade calls. Deferred: rdrmnull's virtual display (R3) to R5i, and rdrmnull's DMA test properties.ENOTSUP): import returns the exporter's object, one handle per object per file; an import's re-export exports the original buffer, as on Linux.drm-core.p5m,cdrmnull.p5m,virtio-gpu.p5mrequiring and incorporatingdrm-core@0.0.1), CI (build/link all modules, symbol scope, core-symbol check, cdrmnull-z defs, facade-check committed and live, check-generated), README (module layout, ABI policy, how a C driver links, concurrency, deviations, results).Facade structures (public fields, Linux v7.2 names and order, MIT reimplementation per D7, opaque
__coretail)drm_device22 (296 B, nomode_configuntil R5i),drm_minor4,drm_file6,drm_driver22 (Linux hooks +illumos_*),drm_gem_object15 (256 B),drm_gem_object_funcs8 (free/open/close + 5 illumos),dma_fence8 (96 B, unions counted once),dma_fence_ops7,dma_fence_cb2,dma_resv2,dma_buf8,dma_buf_attachment4; plus thedrm_rkms_*KMS structures for Rust drivers. Each header records its origin.Design decisions and alternatives
drm_dev_unregisterruns every refusal check on the published device; only then table → facade (drm_core::published::Published, SeqCst, waits for every in-flight call) → teardown → free.getinfo(9E)never touches the device. Fence callbacks: intrusive list throughdma_fence_cbunder a spin lock held with interrupts blocked (ddi_enter_critical); a callback may drop its own structure's last reference; callbacks queued behind it never run; releases wait only for callbacks running on other threads.dma_fence_init,drm_illumos_fence_create,dma_fence_signalnever block;drm_gem_object_put/dma_buf_putdocument the contexts the core cannot tell apart (usedrm_illumos_gem_object_put_deferred); RustGemRef/GemAnydrops defer,put(&Sleepable)releases at once;Syncobjis!Send.ddi::private::module_loaded(c"drm", &Sleepable)walks the module list undermod_lockby module name (the framework's identity; the file name changes with the load path), no hold (no deadlock with a symmetric guard).Deviations from Linux
No
mode_config(R5i);struct lx_mutex(illumos hasstruct mutex);dma_fence_wait_timeoutin ticks; fence ops other thanreleasenot called; fence lock unused,cb_listnot a list;dma_resvNULL ctx only, lock owned by the locking thread (EDEADLK on relock, foreign unlock ignored), unknown usages refused;drm_dev_unregisterreturns-EBUSYwhen refused; illumos backings/devmap for GEM memory;dma_buf_fdtakes over the reference (as Linux).Evidence (hephaistos guest
r5a-run2, golden-20260930, illumos 7e802e88a3, libdrm 2.4.134 overlay, 2 vCPU / 3 GiB)run-r5a-test.shatb040324: PASS, 167 checks, 0 failures — misc/drm_core alone (102 globals = mapfile; facade layouts 38 sizes / 233 offsets via gcc; drivers built for facade major 1 or a largerdrm_devicerefuse with the check's warning; with gfx-drm'smisc/drmloaded,misc/drm_corerefuses with its warning and loads after it is unloaded); three drivers together: R0/R1 + 32-bit probes on both null drivers, R2 200 checks on each, R3 on rdrmnull, R4 63 checks on virtio_gpu,drm_r5a_test81 checks ×4 (PRIME across all pairs, cross-driver fences, PRIME_SELFTEST, FENCE_SELFTEST 0x1f/0x1f) after three unload orders; core refuses to unload while any driver depends on it; cdrmnull's 4 detaches raced 330k–600k facade calls (5.9k–73k duringdrm_dev_unregister);mdb -kCTF prints; run-g6-test PASS and run-r1-test (cdrmnull, two devices) fail=0 inside the run; /etc and /devices unchanged. Log:logs/hephaistos/illumos-drm/20261003-r5a-run2-combined-b040324.log.08ca41e(kernel code differs only in message prefixes and callback-node reinit): same suite PASS 167 (…-run2-combined-08ca41e.log);cargo xtask kernel-checkwith misc/drm_core loaded: ddi-sys sizes 53/60, offsets 185/185, symbols 984/984; drm-facade-sys sizes 38/41, offsets 233/240 (rest anonymous unions), symbols 99/99; private sizes 3/3, offsets 46/46, symbols 15/15 (incl.modctl,mod_lock,modules) (20261003-r5a-kernel-check.log);facade-checkagainst guest gcc: 271 lines, 0 differences (20261003-r5a-facade-check.log); packagesdriver/graphics/drm-core+driver/graphics/cdrmnullpublished from the build and installed besidedriver/graphics/drmand libdrm 2.4.134 into a new BE (20261003-r5a-pkg-test.log).cargo test -p drm-core -p drm-uapi -p drm-facade(124 + facade 2 + uapi),virtio_gpu --no-default-features6; clippy/fmt/doc clean; check-generated clean incl. bindgen regeneration.20261001-r5a-run1-*) cover the pre-review iterations.Review
Two rounds against the anima-review bar. Round 1 rejected (B1 fence self-put spin, B2 unregister ordering, B3 ddi soundness, B4 packaging, B5 vacuous tests, B6 placeholder) — all fixed, plus decisions on dma_buf_fd ownership, per-type GEM tag, resv usage/owner, callback lock vs. same-CPU interrupts, fd-0 test misuse, stale docs, CI regeneration check. Round 2 approved; notes 3 (callback node left stale) and 4 (
drm:message prefixes) fixed inb040324.Open issues / deferred
misc/drmrefusing whilemisc/drm_coreis loaded) belongs to gfx-drm.FENCE_SELFTESTis single-threaded; a concurrent signal-vs-remove/put test is still to add.drm_illumos_fence_createanddma_fence_initnow never sleep for memory (ENOMEM under pressure even in thread context).misc/drm_coreis ~16 MB on disk (Rust debug info; only allocatable sections load); stripping for packages is open.ctfconvertfor CTF (skipped otherwise) and/usr/include/drm/drm.hfor cdrmnull.08ca41e33cc364e7bb040324