R5e: carried Linux helpers (drm_mm, drm_cache) in misc/drm_helpers #14

Merged
toasterson merged 10 commits from r5e-helpers into main 2026-10-05 17:00:06 +00:00
Owner

Anima work item: R5e 01a0f883-6620-7de1-a462-ffdadb97dc82

Carries the Linux DRM helper code that modern i915's headless build needs and that the Rust core's facade does not provide, as Linux C in one illumos kernel module, misc/drm_helpers, with its self-tests in the kernel and on the host, an IPS manifest and CI steps. Stacked on #13 (r5b-layouts, 501c309).

Inventory and classification

Source: R5c's measurement of i915's headless build (Linux v7.2 8d3ae59288, R5c's configuration, 163 translation units, 113,093 lines: i915.mod minus display/, the display glue and the excluded i915_pmu.o, gt/intel_ggtt_gmch.o). Non-kernel imports by provider:

provider symbols classification
drm.ko 63 19 in the facade; 12 carried here (10 drm_mm, 2 drm_cache); 31 core-owned (files, ioctls, GEM, PRIME, syncobj, mmap offsets, printing, managed: facade gaps for R5c's inventory / the i915 port); 1 display (drm_mode_config_reset)
dma-buf 39 facade (17); the rest facade gaps (arrays, chains, resv iterators, attach/map, sync_file_create)
TTM 29 not carried (R5d, deferred). Reached on integrated GPUs only via ttm_device_init/fini from i915_driver_early_probe(); R5c excludes and stubs i915's TTM backend
gpu_buddy / drm_buddy 4 / 2 not carried: only i915_ttm_buddy_manager.o uses them, for local memory (IS_DGFX); it also imports TTM, so the TTM decision governs it (R5c stubs it). MIT, carryable for amdgpu
drm_kms_helper 3 display (behind HAS_DISPLAY)
drm_suballoc, drm_exec, gpu-sched, drm_gpuvm 0 not used by i915
intel-gtt (drivers/char/agp) (excluded) gen2-gen5 only; R5c leaves intel_ggtt_gmch.o out
drm_rect, drm_fourcc, DP/DSC/HDCP 0 headless display phase

drm.ko by file: drm_mm.c 10 (carried), drm_cache.c 2 (carried), drm_vma_manager.c 6 (core-owned: offsets live in the core's devmap path), drm_print.c 8 (5 facade), drm_drv.c 9 (4), drm_file.c 6 (2), drm_gem.c 4 (2), drm_prime.c 5 (0), drm_syncobj.c 5 (3), drm_ioctl.c 3 (1), drm_managed.c 3 (2), drm_auth.c 1 (0), drm_mode_config.c 1 (display).

Licences

file licence treatment
drivers/gpu/drm/drm_mm.c, include/drm/drm_mm.h MIT text (Tungsten Graphics, Intel), no SPDX vendored byte for byte, no patch
drivers/gpu/drm/drm_cache.c, include/drm/drm_cache.h MIT text (Tungsten Graphics; Red Hat), no SPDX vendored byte for byte, patch 0001 (conditionals only)
drivers/gpu/drm/tests/drm_mm_test.c GPL-2.0-only not copied; its six cases re-expressed (MIT) plus eight more
lib/rbtree.c, rbtree*.h, interval_tree_generic.h GPL-2.0-or-later MIT reimplementation in linuxkpi/ (D7)
include/linux/*.h, arch/x86/include/asm/*.h used GPL-2.0 minimal MIT reimplementations in linuxkpi/ (D7)
lib/stackdepot.c GPL-2.0-only not needed (CONFIG_DRM_DEBUG_MM off)

carried/fetch-and-patch vendors only MIT or dual-MIT files listed in <helper>/SOURCES with their SHA-256, refuses anything else, -f compares them with git.kernel.org at the pin (done: identical), -u refreshes them for a new pin.

Module decision

One misc/drm_helpers for the C helpers Linux builds into drm.ko (our drm.ko is the Rust misc/drm_core, which should not depend on the compatibility layer); later drm_rect/drm_fourcc join it. Helpers that are separate Linux modules (buddy, drm_exec, drm_suballoc_helper, gpu-sched, TTM, display helpers) get a module each when a driver needs them.

  • Linked -ztype=kmod -z defs -B reduce with carried/drm_helpers/drm_helpers_scope.mapfile: the globals are exactly _init, _fini, _info, the ten drm_mm functions i915 imports and drm_clflush_virt_range; build.sh fails otherwise. Dependents link -N misc/drm_helpers -M carried/drm_helpers/drm_helpers.mapfile.
  • Depends only on genunix. Its only state is the CPUID facts (CLFLUSH, CLFLUSHOPT, line size) read in _init before mod_install; _init refuses a processor without CLFLUSH. No guard against the legacy stack is needed: gfx-drm's misc/drm exports drm_mm_* too, and krtld resolves each module against its own dependencies.
  • drm_cache patch 0001: drm_clflush_pages/drm_clflush_sg under CONFIG_LKPI_STRUCT_PAGE (R5c's struct page/sg_table; then drm_clflush_sg, which i915 imports, builds unchanged and joins the mapfiles); drm_need_swiotlb and the WC-copy functions under CONFIG_LKPI_IOSYS_MAP (not used by i915 headless). wbinvd_on_all_cpus() has no definition on purpose: the -z defs link proves the no-CLFLUSH path is compiled out.

Tests and evidence

  • Kernel (tools/test/run-r5e-test.sh, hephaistos guest r5e-run4, fresh overlay of golden-20260930, illumos 7e802e88a3, build of 65afae7 on oibuild with gcc 14.3 and the gate's flags): PASS, 27 checks. The module loads and unloads alone. The test driver drm_helpers_test (rselftest style; linked -N misc/drm_helpers against the exported functions only; kstat drm_helpers_test:0:selftest plus syslog) runs 16 tests at attach (14 drm_mm, 2 drm_cache) for five seeds up to scale 50: 130,876 to 6,464,544 checks, none failed. misc/drm_helpers refuses to unload under its dependent and unloads after rem_drv. inject_failure=1 is counted (1 test, 1 check) and logged, and the attach still succeeds. /etc and /devices/pseudo are unchanged afterwards. The package installs, verifies and uninstalls with the tested module (same SHA-256) in a scratch boot environment. The guest was stopped and its overlay deleted.
  • Host (carried/host-test.sh):
    • gcc on illumos: 26 tests, 840,436 checks.
    • clang on arm64 under ASan and UBSan: 24 tests, 839,569 checks (no drm_cache there).
    • A seed gives the same drm_mm counts on both compilers and in the kernel.
    • The tree tests verify the red-black rules, parent pointers, leftmost caches and augmented maxima after every operation. Five deliberate bugs in the tree code were each caught.
  • What the tests cover: the drm_mm tests cover what i915 relies on: reservations, the four insertion modes and ONCE, ranges, non-power-of-two alignment, colour adjustment with guard gaps, interval queries, and the eviction scan with colour eviction as i915_gem_evict_something() drives it. Random walks run against an exhaustive feasibility oracle, and four allocators run on four threads. After every change the whole allocator (list, holes, three trees) is verified.
  • Package: packaging/drm-helpers.p5m published into a scratch repository, pkglint clean, archived as a p5p.
  • CI: the illumos job runs carried/build.sh and carried/host-test.sh.

Compatibility files to reconcile with R5c

Written for R5e before R5c's layer existed, at R5c's paths, each marked "to be reconciled with R5c". The merge replaces them; misc/drm_helpers then links R5c's trees instead of its local copy, and carried/test/host/rbtree_test.c can test R5c's.

  • linuxkpi/include/linux/: types.h, compiler.h (defines typeof: the gate's -fno-asm removes the keyword), limits.h, bug.h, math64.h, log2.h, bitops.h, kernel.h, list.h (no list_move_tail: illumos' sys/list.h has its own), errno.h, export.h, slab.h, seq_file.h, stacktrace.h, mm_types.h, spinlock.h, scatterlist.h, rbtree_types.h, rbtree.h, rbtree_augmented.h, interval_tree_generic.h
  • linuxkpi/include/asm/: barrier.h, processor.h, cpufeature.h, special_insns.h, smp.h
  • linuxkpi/lib/: rbtree.c, x86_cpu.c
  • For R5c: define CONFIG_LKPI_STRUCT_PAGE once struct page/sg_table exist, and add drm_clflush_sg to both carried/drm_helpers/*.mapfile.

Reviews

  • Round 1 (Opus, Anima review rules): rejected, no correctness bug. Fixed:
    • fetch-and-patch with a relative output directory, and unlisted files;
    • drm_cache is now carried instead of handed off;
    • the buddy allocator's owner is stated;
    • the evidence comes from committed trees;
    • the package was validated;
    • the scale clamp is reported;
    • a wrong path in a comment.
  • Round 2: approved, with three non-blocking notes, all fixed in 65afae7:
    • the empty-range drm_cache test now keeps slack before its buffer, because Linux flushes addr + len - 1;
    • patch 0001's guard is split into two macros;
    • the note's stale sections are updated.

Open issues

  • The 31 core-owned drm.ko gaps and the dma-buf gaps are not provided anywhere yet (R5c's inventory, a facade follow-up, the i915 port).
  • drm_clflush_sg waits for R5c's page model.
  • i915's mmap offsets (mmo) need a facade extension.
  • ttm_device_init on integrated GPUs needs the i915 port's TTM stubs.
  • intel_graphics_stolen_res (x86 early quirks) is an R5c kernel symbol.
  • CI has not run this branch yet.

Per the owner's rule of 2026-10-05, this is not to be merged until the stack is tested on the X230; the branch stays pushed for graphics-dev.

Anima work item: R5e `01a0f883-6620-7de1-a462-ffdadb97dc82` Carries the Linux DRM helper code that modern i915's headless build needs and that the Rust core's facade does not provide, as Linux C in one illumos kernel module, `misc/drm_helpers`, with its self-tests in the kernel and on the host, an IPS manifest and CI steps. Stacked on #13 (`r5b-layouts`, `501c309`). ## Inventory and classification Source: R5c's measurement of i915's headless build (Linux v7.2 `8d3ae59288`, R5c's configuration, 163 translation units, 113,093 lines: `i915.mod` minus `display/`, the display glue and the excluded `i915_pmu.o`, `gt/intel_ggtt_gmch.o`). Non-kernel imports by provider: | provider | symbols | classification | | --- | --- | --- | | `drm.ko` | 63 | 19 in the facade; **12 carried here** (10 `drm_mm`, 2 `drm_cache`); 31 core-owned (files, ioctls, GEM, PRIME, syncobj, mmap offsets, printing, managed: facade gaps for R5c's inventory / the i915 port); 1 display (`drm_mode_config_reset`) | | dma-buf | 39 | facade (17); the rest facade gaps (arrays, chains, resv iterators, attach/map, `sync_file_create`) | | TTM | 29 | not carried (R5d, deferred). Reached on integrated GPUs only via `ttm_device_init/fini` from `i915_driver_early_probe()`; R5c excludes and stubs i915's TTM backend | | `gpu_buddy` / `drm_buddy` | 4 / 2 | not carried: only `i915_ttm_buddy_manager.o` uses them, for local memory (`IS_DGFX`); it also imports TTM, so the TTM decision governs it (R5c stubs it). MIT, carryable for amdgpu | | `drm_kms_helper` | 3 | display (behind `HAS_DISPLAY`) | | `drm_suballoc`, `drm_exec`, `gpu-sched`, `drm_gpuvm` | 0 | not used by i915 | | `intel-gtt` (`drivers/char/agp`) | (excluded) | gen2-gen5 only; R5c leaves `intel_ggtt_gmch.o` out | | `drm_rect`, `drm_fourcc`, DP/DSC/HDCP | 0 headless | display phase | `drm.ko` by file: `drm_mm.c` 10 (carried), `drm_cache.c` 2 (carried), `drm_vma_manager.c` 6 (core-owned: offsets live in the core's devmap path), `drm_print.c` 8 (5 facade), `drm_drv.c` 9 (4), `drm_file.c` 6 (2), `drm_gem.c` 4 (2), `drm_prime.c` 5 (0), `drm_syncobj.c` 5 (3), `drm_ioctl.c` 3 (1), `drm_managed.c` 3 (2), `drm_auth.c` 1 (0), `drm_mode_config.c` 1 (display). ## Licences | file | licence | treatment | | --- | --- | --- | | `drivers/gpu/drm/drm_mm.c`, `include/drm/drm_mm.h` | MIT text (Tungsten Graphics, Intel), no SPDX | vendored byte for byte, no patch | | `drivers/gpu/drm/drm_cache.c`, `include/drm/drm_cache.h` | MIT text (Tungsten Graphics; Red Hat), no SPDX | vendored byte for byte, patch 0001 (conditionals only) | | `drivers/gpu/drm/tests/drm_mm_test.c` | GPL-2.0-only | not copied; its six cases re-expressed (MIT) plus eight more | | `lib/rbtree.c`, `rbtree*.h`, `interval_tree_generic.h` | GPL-2.0-or-later | MIT reimplementation in `linuxkpi/` (D7) | | `include/linux/*.h`, `arch/x86/include/asm/*.h` used | GPL-2.0 | minimal MIT reimplementations in `linuxkpi/` (D7) | | `lib/stackdepot.c` | GPL-2.0-only | not needed (`CONFIG_DRM_DEBUG_MM` off) | `carried/fetch-and-patch` vendors only MIT or dual-MIT files listed in `<helper>/SOURCES` with their SHA-256, refuses anything else, `-f` compares them with git.kernel.org at the pin (done: identical), `-u` refreshes them for a new pin. ## Module decision One `misc/drm_helpers` for the C helpers Linux builds into `drm.ko` (our `drm.ko` is the Rust `misc/drm_core`, which should not depend on the compatibility layer); later `drm_rect`/`drm_fourcc` join it. Helpers that are separate Linux modules (buddy, `drm_exec`, `drm_suballoc_helper`, `gpu-sched`, TTM, display helpers) get a module each when a driver needs them. - Linked `-ztype=kmod -z defs -B reduce` with `carried/drm_helpers/drm_helpers_scope.mapfile`: the globals are exactly `_init`, `_fini`, `_info`, the ten `drm_mm` functions i915 imports and `drm_clflush_virt_range`; `build.sh` fails otherwise. Dependents link `-N misc/drm_helpers -M carried/drm_helpers/drm_helpers.mapfile`. - Depends only on genunix. Its only state is the CPUID facts (CLFLUSH, CLFLUSHOPT, line size) read in `_init` before `mod_install`; `_init` refuses a processor without CLFLUSH. No guard against the legacy stack is needed: gfx-drm's `misc/drm` exports `drm_mm_*` too, and krtld resolves each module against its own dependencies. - `drm_cache` patch 0001: `drm_clflush_pages`/`drm_clflush_sg` under `CONFIG_LKPI_STRUCT_PAGE` (R5c's `struct page`/`sg_table`; then `drm_clflush_sg`, which i915 imports, builds unchanged and joins the mapfiles); `drm_need_swiotlb` and the WC-copy functions under `CONFIG_LKPI_IOSYS_MAP` (not used by i915 headless). `wbinvd_on_all_cpus()` has no definition on purpose: the `-z defs` link proves the no-CLFLUSH path is compiled out. ## Tests and evidence - **Kernel** (`tools/test/run-r5e-test.sh`, hephaistos guest `r5e-run4`, fresh overlay of `golden-20260930`, illumos `7e802e88a3`, build of `65afae7` on oibuild with gcc 14.3 and the gate's flags): **PASS, 27 checks**. The module loads and unloads alone. The test driver `drm_helpers_test` (rselftest style; linked `-N misc/drm_helpers` against the exported functions only; kstat `drm_helpers_test:0:selftest` plus syslog) runs 16 tests at attach (14 `drm_mm`, 2 `drm_cache`) for five seeds up to scale 50: 130,876 to 6,464,544 checks, none failed. `misc/drm_helpers` refuses to unload under its dependent and unloads after `rem_drv`. `inject_failure=1` is counted (1 test, 1 check) and logged, and the attach still succeeds. `/etc` and `/devices/pseudo` are unchanged afterwards. The package installs, verifies and uninstalls with the tested module (same SHA-256) in a scratch boot environment. The guest was stopped and its overlay deleted. - **Host** (`carried/host-test.sh`): - gcc on illumos: 26 tests, 840,436 checks. - clang on arm64 under ASan and UBSan: 24 tests, 839,569 checks (no `drm_cache` there). - A seed gives the same `drm_mm` counts on both compilers and in the kernel. - The tree tests verify the red-black rules, parent pointers, leftmost caches and augmented maxima after every operation. Five deliberate bugs in the tree code were each caught. - **What the tests cover:** the `drm_mm` tests cover what i915 relies on: reservations, the four insertion modes and ONCE, ranges, non-power-of-two alignment, colour adjustment with guard gaps, interval queries, and the eviction scan with colour eviction as `i915_gem_evict_something()` drives it. Random walks run against an exhaustive feasibility oracle, and four allocators run on four threads. After every change the whole allocator (list, holes, three trees) is verified. - **Package:** `packaging/drm-helpers.p5m` published into a scratch repository, pkglint clean, archived as a p5p. - **CI:** the illumos job runs `carried/build.sh` and `carried/host-test.sh`. ## Compatibility files to reconcile with R5c Written for R5e before R5c's layer existed, at R5c's paths, each marked "to be reconciled with R5c". The merge replaces them; `misc/drm_helpers` then links R5c's trees instead of its local copy, and `carried/test/host/rbtree_test.c` can test R5c's. - `linuxkpi/include/linux/`: `types.h`, `compiler.h` (defines `typeof`: the gate's `-fno-asm` removes the keyword), `limits.h`, `bug.h`, `math64.h`, `log2.h`, `bitops.h`, `kernel.h`, `list.h` (no `list_move_tail`: illumos' `sys/list.h` has its own), `errno.h`, `export.h`, `slab.h`, `seq_file.h`, `stacktrace.h`, `mm_types.h`, `spinlock.h`, `scatterlist.h`, `rbtree_types.h`, `rbtree.h`, `rbtree_augmented.h`, `interval_tree_generic.h` - `linuxkpi/include/asm/`: `barrier.h`, `processor.h`, `cpufeature.h`, `special_insns.h`, `smp.h` - `linuxkpi/lib/`: `rbtree.c`, `x86_cpu.c` - For R5c: define `CONFIG_LKPI_STRUCT_PAGE` once `struct page`/`sg_table` exist, and add `drm_clflush_sg` to both `carried/drm_helpers/*.mapfile`. ## Reviews - Round 1 (Opus, Anima review rules): rejected, no correctness bug. Fixed: - `fetch-and-patch` with a relative output directory, and unlisted files; - `drm_cache` is now carried instead of handed off; - the buddy allocator's owner is stated; - the evidence comes from committed trees; - the package was validated; - the scale clamp is reported; - a wrong path in a comment. - Round 2: approved, with three non-blocking notes, all fixed in `65afae7`: - the empty-range `drm_cache` test now keeps slack before its buffer, because Linux flushes `addr + len - 1`; - patch 0001's guard is split into two macros; - the note's stale sections are updated. ## Open issues - The 31 core-owned `drm.ko` gaps and the dma-buf gaps are not provided anywhere yet (R5c's inventory, a facade follow-up, the i915 port). - `drm_clflush_sg` waits for R5c's page model. - i915's mmap offsets (mmo) need a facade extension. - `ttm_device_init` on integrated GPUs needs the i915 port's TTM stubs. - `intel_graphics_stolen_res` (x86 early quirks) is an R5c kernel symbol. - CI has not run this branch yet. Per the owner's rule of 2026-10-05, this is not to be merged until the stack is tested on the X230; the branch stays pushed for `graphics-dev`.
Minimal Linux headers at R5c's paths (linuxkpi/include/linux) for the
carried helpers: types, compiler annotations (typeof for the gate's
-fno-asm), limits, bitops, math64, log2, bug (WARN through cmn_err),
kernel (min/max), errno, lists over the facade's struct list_head
(without list_move_tail, which illumos' sys/list.h has), red-black trees
with Linux's node layout and augmentation protocol (linuxkpi/lib/rbtree.c,
textbook algorithms), the generic interval tree, and stubs drm_mm only
includes (slab, seq_file, stacktrace, mm_types, export, spinlock).
Reimplementations, not copies: Linux's are GPL (decision D7).
drm_mm.c and drm_mm.h (MIT text, Tungsten Graphics and Intel) vendored
byte for byte at 8d3ae59288 (carried/linux.pin) with their SHA-256 in
carried/drm_mm/SOURCES and an empty patch series. fetch-and-patch
verifies them (-f against git.kernel.org at the pin, -u refreshes),
refuses non-MIT files and applies the series; build.sh compiles them
with the gate's kernel flags and links misc/drm_helpers -z defs -B
reduce, failing unless its globals are exactly _init, _fini, _info and
the ten drm_mm functions i915's headless build imports
(drm_helpers_scope.mapfile; drm_helpers.mapfile for dependents).
carried/drm_mm/tests/drm_mm_selftest.c re-expresses the six KUnit
cases of Linux's GPL-only drm_mm_test.c and adds what i915 relies on:
reservations, insertion modes and ONCE, ranges, non-power-of-two
alignments, colour adjustment with guard gaps, interval queries, the
eviction scan with colour eviction, random walks against an exhaustive
feasibility oracle and independent allocators on four threads. Every
change is followed by a full verification of the allocator's list,
holes and three red-black trees.

drm_helpers_test is a pseudo driver linked -N misc/drm_helpers against
the exported functions only; it runs the tests at attach and reports
through a kstat and the system log (inject_failure=1 proves the failure
path). tools/test/run-r5e-test.sh drives it on a guest. host-test.sh
builds the same tests, host-only drm_mm tests and red-black/interval
tree tests into a userland program.
packaging/drm-helpers.p5m; the illumos CI job builds misc/drm_helpers
and drm_helpers_test and runs carried/host-test.sh; the README records
the inventory, the module decision, the vendoring rules, the
compatibility headers to reconcile with R5c and the test results.
drm_cache.c and drm_cache.h (MIT) are carried too: patch 0001 builds only
drm_clflush_virt_range() until R5c's struct page and scatterlist models
exist (CONFIG_LKPI_STRUCT_PAGE), which then bring drm_clflush_sg(); the
module exports it (11 functions), reads CLFLUSH and CLFLUSHOPT and the
line size from CPUID in _init (linuxkpi/lib/x86_cpu.c, asm/*.h) and
refuses a processor without CLFLUSH; wbinvd_on_all_cpus() has no
definition, so -z defs proves the fallback is compiled out. Self-tests for
it in the kernel and on x86-64 hosts.

fetch-and-patch makes OUT absolute, copies only the files SOURCES lists
and refuses others, and takes GNU or BSD patch without fuzz. The test
driver reports a scale outside 1..100 instead of silently using 1, and
run-r5e-test.sh checks the kstat's scale and can test the package
(PKG=<p5p>).
The manifest carries drm_cache's notice; the README classifies the 63
drm.ko imports with drm_cache carried (19 facade, 12 carried, 31 core,
1 display), describes the drm_cache patch and the CLFLUSH rule, and says
who decides the buddy allocator: i915_ttm_buddy_manager.o also imports
TTM, so the TTM decision of the i915 port settles it.
Removing the reboot-needed module from the live image makes pkg(1) clone
the boot environment, so the uninstall check failed on the live root
(found on the guest). The package phase now runs with pkg -R in a
scratch boot environment that is destroyed afterwards.
Patch 0001 now guards the page and scatterlist functions
(CONFIG_LKPI_STRUCT_PAGE, R5c's struct page and sg_table) separately from
the swiotlb and write-combining-copy ones (CONFIG_LKPI_IOSYS_MAP:
iosys_map, Xen, memory encryption, static keys, kernel FPU), so that
defining the first brings drm_clflush_sg and nothing that needs the
second. The drm_cache tests keep 256 bytes before their buffers: Linux's
drm_clflush_virt_range also flushes the line of addr + len - 1, which
for an empty range at the buffer's start is the byte before it.
README: R5e results at 65afae7
Some checks failed
ci / check-hosted (pull_request) Failing after 23m46s
ci / kmod-illumos (pull_request) Failing after 2h32m7s
f76f376e1f
toasterson changed target branch from r5b-layouts to main 2026-10-05 16:59:55 +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!14
No description provided.