← Back · builds on the in-kernel IOKit matcher, the ko→kext conversion, and the shipped drm-kmod → IntelGraphics/AMDGraphics/RadeonGraphics kexts
NextBSD already builds drm-kmod (Intel/AMD/Radeon) into Apple-style .kext bundles that the in-kernel IOKit matcher autoloads. But that whole match → autoload → bind → KMS path is untested end-to-end — qemu emulates no real Intel/AMD/Radeon GPU, so those drivers can never reach attach in CI. A DRM driver for a virtual GPU fixes both gaps at once: real KMS graphics in VMs, and the first true end-to-end graphics CI test. This plan scopes the open virtual-GPU ports (bochs, virtio-gpu, vmwgfx, VirtualBox vboxvideo), the repo architecture (an unmodified drm-kmod fork + a single nextbsd-graphics kext factory), and the separate, license-constrained NVIDIA legacy track.
Guiding principle Start with bochs. It binds qemu’s default -vga std device (1234:1111) with no qemu reconfiguration, and matches as a raw IOPCIPrimaryMatch PCI node — exactly the personality shape ko2kext.sh already emits for i915/amd/radeon. So it unlocks the first end-to-end CI test by reusing the existing match→kextd→load→bind machinery unchanged. The real cost is not the driver; it is the missing DRM GEM helper(s) that drm-kmod never compiles. virtio-gpu and vmwgfx are larger follow-ons; NVIDIA is a separate, license-shaped repo.
Status 2026-08-16 — arm64 split out This plan treats virtio-gpu and vmwgfx as “larger follow-ons” to bochs. That framing held for amd64, where bochs and vboxvideo now ship — but not for arm64, where neither binds anything an ARM VM presents and no FreeBSD system has ever had /dev/dri in an ARM virtual machine. The arm64 question turned out to be a different problem with six candidate answers, a licensing decision and two blocking unknowns, so it has its own page: NextBSD arm64 KMS — six routes to /dev/dri/card0 in an ARM virtual machine, which also corrects two claims made here and in the surrounding work.
That question is now decided, and the work split into two independent plans:
card0, a render node, dynamic resolution and hardware GL via Mesa's virgl. Priority work.Status 2026-08-15 — IMPLEMENTED bochs works. BochsGraphics.kext binds and publishes /dev/dri/card0 on the shipped amd64 image, verified end-to-end in CI
(nextbsd-kernel-modules#30):
drmn0: <drmn> on vgapci0
[drm] Found bochs VGA, ID 0xb0c5.
[drm] Initialized bochs-drm 1.0.0 for drmn0 on minor 0
VT: Replacing driver "efifb" with new "drmfb".
# ls -l /dev/dri
card0 -> ../drm/0
That efifb → drmfb line is the vt(4) framebuffer handover — the step this plan named as the canonical “binds but black screen” failure. It succeeded. This is also the first true match → load → bind → KMS test in the tree, and it needed no qemu reconfiguration: q35’s default -vga std is the 1234:1111 device the kext matches.
Correction The helper gate was over-estimated; the real cost was elsewhere. This plan called drm_gem_vram_helper (~1050 LOC, TTM-coupled) the make-or-break piece and budgeted most of 1–2 weeks for it. Measured against 6.12-lts, its entire FreeBSD delta was one argument:
ret = ttm_device_init(&vmm->bdev, &bo_driver, dev->dev,
#ifdef __linux__
dev->anon_inode->i_mapping,
#elif defined(__FreeBSD__)
NULL, /* drm-kmod takes void *dummy here */
#endif
FreeBSD has no anon_inode, so drm-kmod’s ttm_device_init() takes a void *dummy; radeon_ttm.c already passes NULL through the same #ifdef. drm_simple_kms_helper.c compiled verbatim. The actual work was four latent drm-kmod/LinuxKPI defects that no shipped driver reaches.
Measured drm-kmod / LinuxKPI defects this port surfaced. All four are latent for any small DRM driver — i915, amdgpu and radeon dodge every one — so vboxvideo and vmwgfx will hit them too unless fixed once, centrally:
drm_module_pci_driver_if_modeset() expands to a four-argument module_driver(); FreeBSD’s linuxkpi declares it with exactly three (Linux’s is variadic). The macro cannot expand at all.drm_module_* family emits only SYSINITs and never DECLARE_MODULE, so a module built with it carries dependency metadata for a module that does not exist and kldload rejects it outright — surfacing as a bare ENOEXEC / “Exec format error”. Use LKPI_DRIVER_MODULE.drivers/gpu/drm/drm_gem_framebuffer_helper.c is a 76-line “Public domain” stub implementing three functions, while include/drm/drm_gem_framebuffer_helper.h still declares drm_gem_fb_create and friends. A driver using the generic helper compiles clean and dies at link.pdrv->isdrm = strcmp(pdrv->name, "drmn") == 0, choosing the vgapci devclass only when it matches. A DRM driver not called drmn registers on the plain pci devclass and silently never probes — it loads, sits resident, and prints nothing. i915 and radeon both carry an #ifdef __FreeBSD__ override for exactly this.A fifth, cheaper one: a module that others MODULE_DEPEND on must declare MODULE_VERSION, or the dependant fails with “not available or version mismatch” — also reported as ENOEXEC.
Revised What changed in the plan’s shape.
/tmp/drm-kmod clone at build time, so it stays an untouched upstream checkout — the “fork unmodified + companion repo” split is still the right end state, but it is not a prerequisite.nextbsd-kernel-modules rather than a new nextbsd-graphics repo, because that repo already had a green drm-kmod build and the toolchain container. Moving later is a directory move.IOGraphicsExtras.kext (drm_extra_helpers.ko) — it now carries drm_simple_kms_helper, drm_gem_vram_helper and the real drm_gem_framebuffer_helper, so the next driver inherits all three.Measured Which driver serves which architecture. Taken from upstream Linux’s own Kconfig gates plus the EDK2 firmware manifests, not from inference:
| Driver | Linux Kconfig gate | amd64 | arm64 | Why |
|---|---|---|---|---|
| virtio-gpu | DRM && VIRTIO_MENU && MMU | yes | yes | No arch gate, and ArmVirtQemu.dsc builds VirtioGpuDxe — so the firmware provides a GOP, giving efifb/vt at boot and then the same DRM handover amd64 demonstrated. |
| vmwgfx | (X86 && HYPERVISOR_GUEST) || ARM64 | yes | yes | Upstream explicitly supports ARM64 — VMware Fusion runs arm64 guests on Apple Silicon. The only other dual-arch candidate. |
| bochs | DRM && PCI && MMU | yes | no, in practice | The driver has no arch gate and qemu’s bochs-display is a plain PCI device that attaches on virt — but ArmVirtQemu.dsc ships no QemuVideoDxe (x86’s OvmfPkgX64.dsc does). Nothing initializes the device until a KMS driver loads, so there is no boot framebuffer, no efifb, and nothing for the efifb → drmfb handover to replace. Observed directly: a UTM arm64 guest set to bochs sits at “guest has not initialized the display yet”. |
| vboxvideo | DRM && X86 && PCI | yes | no | Gated x86-only upstream; VirtualBox has no arm64 guests either. |
| i915 | — | yes | no | Intel integrated graphics is x86. |
| NVIDIA (proprietary) | — | yes | no | The FreeBSD port is amd64/i386 only. |
| amdgpu / radeon | — | yes | possible | Discrete PCIe cards do work on ARM hosts in Linux; drm-kmod lists aarch64 as supported. Low priority for NextBSD, not blocked. |
What to build and package, per arch. The driver matrix above says which driver can serve which arch; this is the shipping decision that follows from it. Note the first row: the core kexts are not drivers, they are the substrate every DRM driver links against, so an arm64 package without them carries nothing loadable.
| Kext | amd64 | arm64 | Rationale |
|---|---|---|---|
| DMABuf, IOGraphics, TTM, IOGraphicsExtras (core) | build | build — required | Every DRM driver links against these; without them an arm64 driver kext has nothing to load onto. |
| VirtIOGraphics (virtio-gpu) | build | build — the primary | Firmware-backed on ARM, so it also provides the boot console. The arm64 answer. |
| VMwareGraphics (vmwgfx) | build | build, optional | Only if VMware Fusion on Apple Silicon matters; upstream supports ARM64. |
| BochsGraphics | build | skip | No firmware driver on ARM — nothing initializes the device before a KMS driver loads. |
| VBoxGraphics (vboxvideo) | build | skip | depends on X86 upstream; VirtualBox has no arm64 guests. |
| IntelGraphics, NVIDIA | build | skip | Intel iGPU is x86; the FreeBSD NVIDIA port is amd64/i386. |
| AMDGraphics, RadeonGraphics | build | defer | Not x86-gated, and drm-kmod supports aarch64 — a discrete Radeon in an ARM workstation is a real configuration. But it is speculative hardware for this audience and the firmware bundles are hundreds of MB per package. Unblocked, not unsupported; revisit on demand. |
Sequencing. There is no arm64 kext lane today, and virtio-gpu exists for neither arch. Adding the arm64 lane before virtio-gpu would ship a package containing core kexts and no driver — real plumbing, no user-visible effect. Prefer to build the arm64 lane with virtio-gpu, unless you deliberately want the modules-lane and nextbsd-pkg plumbing proven early to de-risk that work.
Delivery path. On amd64 nothing new is needed to ship these: nextbsd-pkg already pulls --pattern '*kext*.tar.gz' from nextbsd-kernel-modules’ continuous release, and the graphics bundle publishes as graphics-kexts.tar.gz, so it lands in NextBSD-kernel-extensions and thence into the image (which is assembled purely from pkg install NextBSD-everything). A kext-only change still needs nextbsd-pkg’s workflow_dispatch to repackage. arm64 does need work: that download is guarded by if [ "$ARCH" = amd64 ], and the package is amd64-only “until the arm64 kext build path exists”. So arm64 virtio-gpu needs three things, in order: an arm64 lane in the modules build, the arm64 kext download in nextbsd-pkg, and an arm64 end-to-end boot test.
Consequence for the roadmap: bochs remains the right P0 — it delivered the end-to-end amd64 test cheaply, and its helper work is what every later driver inherits — but it cannot be the arm64 story. arm64 needs virtio-gpu, whose remaining cost is unchanged from this plan (drm_gem_shmem_helper, the linuxkpi virtio bridge, and IOKit sub-bus matcher plumbing) minus the four defects and three helpers already closed by the bochs work.
nextbsd-graphicsNextBSD builds the FreeBSD drm-kmod port (branch 6.6-lts) green in CI — the drm.ko/drmn core, ttm.ko, dmabuf.ko, linuxkpi, plus the i915kms/amdgpu/radeonkms drivers — each wrapped into an Apple-style .kext with IOPCIPrimaryMatch personalities so the in-kernel IOKit matcher autoloads the matched driver via kextd. That entire match→autoload→bind→KMS pipeline is, today, untested end-to-end: qemu emulates no real Intel/AMD/Radeon GPU, so those drivers can never device-match in CI. Their personalities are only unit-tested (personalities-selftest.sh); no driver ever reaches attach.
A DRM driver for a virtual GPU changes that on both axes: (a) real KMS graphics inside VMs, and (b) the first true end-to-end CI test, because a virtual-GPU device actually appears on the qemu PCI bus and binds.
The honest catch drm-kmod 6.6-lts vendors none of these drivers. Its drivers/gpu/drm/ holds only amd, display, i915, radeon, scheduler, ttm — no tiny/ (bochs), no virtio, no vmwgfx. (It once shipped vboxvideo + vmwgfx and removed them in commit 787a917 — unmaintained >1yr, drm-kmod issue #356.) So every candidate is a net-new port: vendor the Linux 6.6 source, write a FreeBSD bsd.kmod.mk Makefile, fill the gaps — all on top of the unmodified drm-kmod core.
| Driver | Target device | Where it binds | Missing helper to vendor | Hardest gap | PoC effort | Kext match | CI value |
|---|---|---|---|---|---|---|---|
| bochs | Bochs VBE / stdvga 1234:1111 | qemu -vga std (default) — no config change | drm_gem_vram_helper + drm_simple_kms_helper | TTM-coupled VRAM helper | 1–2 wks | raw 0x11111234 | highest |
| vboxvideo | VBoxVGA 80ee:beef | VirtualBox (set adapter = VBoxVGA) | drm_gem_vram_helper + fbdev-TTM (same VRAM helper as bochs) | shares the bochs VRAM-helper gate | ~days after bochs | raw 0xbeef80ee | medium (needs VirtualBox) |
| virtio-gpu | virtio-gpu 1af4:1050 (virtio type 16) | qemu -device virtio-gpu-pci | drm_gem_shmem_helper | no linuxkpi virtio layer at all | 2–4 wks (revive prior art) | virtio sub-bus (not raw PCI) | high (different match path) |
| vmwgfx | VMware SVGA II 15ad:0405 | qemu -vga vmware / real VMware | brings its own ttm_object.c | page_dirty mmap write-protect over Linux MM | 3–6 wks | raw 0x040515ad | low (real value = VMware guests) |
The cheapest path. A single ~950-LOC file (drivers/gpu/drm/tiny/bochs.c), pure MMIO (Bochs DISPI over a BAR offset, with an 0x1ce/0x1cf I/O-port fallback) — no command FIFO, no hypervisor backdoor, no virtio. It matches qemu’s default -vga std device, so the kext device-matches in CI with no qemu change (the same match covers -device bochs-display). The PCI register/autoload plumbing (linux_pci_register_drm_driver) already exists in drm-kmod’s linuxkpi. The work is the two missing helpers. The canonical failure mode (freebsd/drm-kmod issue #62, “binds but black screen”) is exactly the symptom of getting the TTM-coupled VRAM helper 90% right.
The mainline Linux drivers/gpu/drm/vboxvideo/ driver (a few kLOC; MMIO + the HGSMI guest↔host protocol, no firmware, single PCI id 80ee:beef) is its own small driver — and it needs the same drm_gem_vram_helper bochs forces. So once that helper exists in the shared module (§5), vboxvideo is days of work, not weeks. Note: FreeBSD’s emulators/virtualbox-ose-additions ships only the legacy Xorg vboxvideo_drv.so (UMS) + vboxguest.ko/vboxvfs.ko — no KMS, no /dev/dri, no Wayland — so a modern KMS vboxvideo kext is genuinely net-new value for VirtualBox guests. Caveat: VirtualBox’s newer VBoxSVGA adapter reports the VMware id 15ad:0405 and is driven by vmwgfx, not vboxvideo — so target/standardize on the VBoxVGA adapter for this kext.
The “modern VM” answer (qemu/KVM, crosvm, cloud-hypervisor), with abandoned prior art (Alex Richardson’s port on ravynsoft/drm-kmod branch virtio, orig. freebsd/drm-kmod PR #119 against Linux 5.5). Two blockers: (1) linuxkpi has zero virtio support — no <linux/virtio.h>, virtio_device, virtqueue, virtio_driver; FreeBSD’s native sys/dev/virtio is structurally different (newbus, virtio_alloc_virtqueues, virtqueue_enqueue), so a bridge must be hand-written. The ~208-LOC linux_virtio.c prototype maps the common calls but has compile errors, panic() stubs for the mandatory reset/del_vqs, and is against 5.5. (2) drm_gem_shmem_helper.c backs virtio-gpu’s entire buffer lifecycle and is absent. And it does not match as a raw PCI node — FreeBSD’s virtio_pci claims 1af4:1050 and presents a child keyed by a virtio device-type ivar (GPU = 16), so the IOPCIPrimaryMatch model doesn’t apply and new IOKit-matcher plumbing is needed.
Architecturally friendly (TTM-based, no virtio, slots next to radeon/amdgpu) but large (~45k vendored lines) with genuinely hard linuxkpi gaps concentrated in vmwgfx_page_dirty.c (mmap write-protect / mkwrite dirty-tracking over Linux MM internals that linuxkpi does not expose). The small shims (asm/vmware.h, asm/hypervisor.h, linux/cc_platform.h, kmap_atomic_prot) are cheap; FreeBSD base already ships sys/x86/include/vmware.h. For the CI goal it is poor cost/benefit — bochs reaches the same milestone for a fraction of the code. vmwgfx’s value is real VMware/ESXi/Workstation guest support + 3D, not the CI test (qemu -vga vmware emulates only the 2D-incomplete SVGA2).
The single most important finding: the real cost of every tiny virtual-GPU driver is a DRM GEM-helper layer that drm-kmod never compiles — not the driver .c files. drm-kmod ships ttm/ + drm_gem_ttm_helper, but lacks the convenience helpers these drivers sit on:
| Helper | Needed by | In drm-kmod 6.6-lts? |
|---|---|---|
drm_gem_vram_helper.c (~1050 LOC, TTM-backed VRAM GEM) | bochs, vboxvideo | missing |
drm_simple_kms_helper.c (~550, pure-core) | bochs | missing |
drm_gem_shmem_helper.c (~1000, GPL-2.0) | virtio-gpu | missing |
ttm/, drm_gem_ttm_helper, atomic/format/fbdev helpers | all | present |
This is what makes bochs the right first step: porting drm_gem_vram_helper (the TTM-coupled, make-or-break piece) is most of the bochs effort — and it simultaneously unblocks vboxvideo. virtio-gpu needs a different helper (gem_shmem) and the virtio bridge; vmwgfx brings its own object manager. So the helper work isn’t throwaway: it is the foundation the open-driver track is built on.
P0 — bochs. The only candidate that (1) binds qemu’s default VGA with no reconfiguration, (2) matches as a raw IOPCIPrimaryMatch node — reusing the existing match→kextd→load→bind machinery unchanged, and (3) is small and self-contained. It is the cheapest thing that delivers the first true end-to-end graphics CI test. Substantive work = drm_simple_kms_helper.c (low risk) + drm_gem_vram_helper.c (the blocker).
P0.5 — vboxvideo, folded in right after bochs since it reuses the same VRAM helper. Cheap incremental KMS for VirtualBox guests.
P1 — virtio-gpu, the modern-VM follow-on — eyes open that the virtio KPI bridge is the dominant cost, not the driver. Plus drm_gem_shmem_helper and new sub-bus matcher plumbing. PoC ~2–4 wks given the prototype; production 2–4 months. virgl/3D explicitly out of scope.
P2 — vmwgfx, optional, justified only for real VMware guest support. The page_dirty MM port is the schedule risk; a first cut can stub it (losing the 2D dirty fast path) to get KMS up.
nextbsd-graphicsVersion target — planned bump NextBSD is moving its drm core 6.6 → 6.12. The fork tracks 6.12-lts (the branch exists), the new drivers vendor Linux 6.12 sources, and the kernel-baked linuxkpi becomes LINUXKPI_VERSION 61200. Because drm-612-kmod needs a newer linuxkpi than releng/15.0 bakes, this likely pulls the FreeBSD base to 15.1 / 15-stable — the maintainer accepts that bump. The NVIDIA bridge follows in lockstep: graphics/nvidia-drm-612-kmod (rebuilding the NVIDIA ports against 6.12 as needed). References to 6.6-lts / LINUXKPI_VERSION 60600 elsewhere in this plan describe today’s shipping state — read them as 6.12-lts / 61200 once the bump lands.
Keep the design intact: fork freebsd/drm-kmod UNMODIFIED (a SHA-pinned mirror under nextbsd-redux) and add a single companion repo — nextbsd-graphics — that vendors the extra drivers + Makefiles + helper sources + linuxkpi shims and builds against the fork. This mirrors how nextbsd-kernel-modules layers on the kernel, and keeps the fork a clean, rebaseable upstream mirror.
drm-kmod builds out-of-tree: a top Makefile descends via bsd.subdir.mk into per-module dirs (dmabuf/ttm/drm/amd/radeon/i915), each a self-contained bsd.kmod.mk driven by SYSDIR=/usr/src/sys. A new driver is just another such subdir — a near-copy of i915/Makefile: the verbatim -I block (linuxkpi/gplv2/include, linuxkpi/bsd/include, ${SYSDIR}/compat/linuxkpi/common/include, the fork’s include/include/drm/include/uapi), -DLINUXKPI_VERSION=60600, per-driver -DCONFIG_* and the required string defines (-DKBUILD_MODNAME, -DLINUXKPI_PARAM_PREFIX). MODULE_DEPEND lines live in a glue C file (<driver>_freebsd.c): MODULE_DEPEND(<kmod>, drmn, 2,2,2) + ttm/linuxkpi/dmabuf as needed (linuxkpi is baked into the NextBSD kernel, so no OSBundleLibraries for it).
Key decision Where the missing helpers live. The GEM helpers are drm-core code, and the plan forbids modifying the fork — and if two drivers each bundle the same VRAM helper, EXPORT_SYMS collide. Resolution: a small companion drm_extra_helpers.ko that compiles the missing helpers once, exports them, and that each new driver MODULE_DEPENDs on. This preserves “fork unmodified” without symbol duplication. (drm_gem_shmem_helper.c is GPL-2.0 — fine in the gplv2 companion module, but isolate it.)
Today’s CI does git clone --depth 1 --branch 6.6-lts — not reproducible (the branch moves, and the kernel-baked linuxkpi LINUXKPI_VERSION 60600 must match the fork’s linuxkpi_version.mk or symbols drift). The companion repo MUST pin the fork to a SHA (a git submodule with a locked commit; nesting also makes the relative -I paths resolve naturally). In CI: check out the pinned fork SHA, build it inside make.py … buildenv, then build the companion drivers + drm_extra_helpers.ko against that checkout, linking at load via MODULE_DEPEND. Always rebuild the fork and the extras together from the pinned pair.
Reuse ko2kext.sh and add per-driver personality generators modeled on gen-i915-personalities.sh (each parses its driver’s own PCI id table):
| Driver | Kext | Match |
|---|---|---|
| bochs | BochsGraphics.kext | IOPCIPrimaryMatch 0x11111234 (ideally 4-tuple incl. subsystem 1af4:1100; do not add qxl 1b36:0100) |
| vboxvideo | VBoxGraphics.kext | IOPCIPrimaryMatch 0xbeef80ee (VBoxVGA) |
| virtio-gpu | VirtIOGraphics.kext | virtio sub-bus (device-type ivar 16) — needs new matcher plumbing |
| vmwgfx | VMwareGraphics.kext | IOPCIPrimaryMatch 0x040515ad |
All wrap with ko2kext.sh -l org.nextbsd.kext.iographics (the drm core); no -f firmware — virtual GPUs ship none (a welcome contrast to amdgpu’s hundreds of MB).
The full set across the shipping work and this plan. Bundle ids follow org.nextbsd.kext.<name> (lowercased). ␀ = proposed name (open to change).
| Kext | Wraps (.ko) | GPU / role | Device match | Depends on | Status |
|---|---|---|---|---|---|
| IOGraphics | drm.ko | DRM/KMS core (shared family) | — (loaded as dep) | DMABuf | shipping |
| DMABuf | dmabuf.ko | dma-buf sharing | — | (linuxkpi baked) | shipping |
| TTM | ttm.ko | GPU memory manager | — | IOGraphics | shipping |
| IntelGraphics | i915kms.ko | Intel iGPU | 0x….8086 | IOGraphics, TTM | shipping |
| AMDGraphics | amdgpu.ko | AMD GCN+/RDNA | 0x….1002 | IOGraphics, TTM, DMABuf | shipping |
| RadeonGraphics | radeonkms.ko | older ATI/AMD Radeon | 0x….1002 (de-overlapped vs amdgpu) | IOGraphics, TTM | shipping |
| DRMExtraHelpers ␀ | drm_extra_helpers.ko | gem_vram + gem_shmem + simple_kms helpers | — | IOGraphics, TTM | planned P0 |
| BochsGraphics ␀ | bochsdrm.ko | Bochs / stdvga (qemu default) | 0x11111234 | IOGraphics, TTM, DRMExtraHelpers | planned P0 |
| VBoxGraphics ␀ | vboxvideo.ko | VirtualBox VBoxVGA | 0xbeef80ee | IOGraphics, TTM, DRMExtraHelpers | planned P0.5 |
| VirtIOGraphics ␀ | virtio_gpu.ko | virtio-gpu (qemu/KVM/cloud) | virtio sub-bus (type 16) | IOGraphics, DRMExtraHelpers, virtio | planned P1 |
| VMwareGraphics ␀ | vmwgfx.ko | VMware SVGA II | 0x040515ad | IOGraphics, TTM | planned P2 |
NVIDIA — one kext per FreeBSD nvidia-kmod* port (separate recipe repo; see §7) | |||||
| NVIDIA ␀ | nvidia + nvidia-modeset + nvidia-drm (main) | Turing+ (RTX 20xx→Blackwell) | 0x10de:* (main list) | IOGraphics (via nvidia-drm) | planned |
| NVIDIA580 ␀ | nvidia+modeset+drm (580) | Maxwell/Pascal/Volta (900/1000) | 0x10de:* (580 list) | IOGraphics | planned |
| NVIDIALegacy470 ␀ | nvidia + nvidia-modeset (470) | Kepler (600/700) | 0x10de:* (470 list) | — (no KMS bridge; X11 only) | planned |
| NVIDIALegacy390 ␀ | nvidia (390) | Fermi (400/500) | 0x10de:* (390 list) | — (X11 only) | planned |
| NVIDIALegacy340 ␀ | nvidia (340) | Tesla (8/9/200/300) | 0x10de:* (340 list) | — (X11 only) | planned |
| NVIDIALegacy304 ␀ | nvidia (304) | GeForce 6/7 (Curie) | 0x10de:* (304 list) | — (X11 only) | planned |
The CI test (bochs, the clean case). Boot the continuous image headless with qemu’s default -vga std. The device goes unmatched → device_nomatch → the IOKit matcher reads IOPCIPrimaryMatch → kextd kextloads BochsGraphics.kext → MODULE_DEPEND pulls drmn/ttm/drm_extra_helpers in order → driver attaches. Assertions: kextstat shows it loaded; dmesg shows drmn/bochs attach + [drm] fb + connector init; /dev/dri/card0 exists; sysctl dev.drmn.0 present; no panic. This is the first time the path is exercised against a device that actually appears. Watch two attach pitfalls: the aperture/vgaarb handoff (must release the boot/efifb framebuffer or the driver fights the console — a common KMS hang), and (virtio only) ensuring the DRM driver out-scores FreeBSD base’s native non-DRM virtio_gpu(4) scanout driver.
NVIDIA is its own repo — not because of the kext mechanics (those are identical) but because of licensing and build shape. The idea: repackage only the kernel modules needed to load for X11/KMS — no libGL, no X driver, no Vulkan ICD — as per-legacy-branch kexts.
nvidia.ko — the proprietary core (open OS-shim recompiled + a precompiled nv-kernel.o blob), exposing its own /dev/nvidia char interface. Not a DRM driver; does not use drm.ko.nvidia-modeset.ko — kernel modesetting (NvKmsKapi).nvidia-drm.ko — the DRM/KMS bridge that registers with and links the same drm.ko/drmn core this plan’s IOGraphics.kext provides (MODULE_DEPEND(nvidia_drm, drmn, 2,2,2)). FreeBSD even split the port: x11/nvidia-driver (userland) → x11/nvidia-kmod (the .kos) + graphics/nvidia-drm-kmod (the bridge).Distribution — same as FreeBSD NVIDIA’s driver is redistributable: FreeBSD ships nvidia-driver/nvidia-kmod as binary packages under LICENSE_PERMS = dist-mirror no-dist-sell pkg-mirror no-pkg-sell auto-accept. NextBSD builds the three .kos from NVIDIA’s tarball exactly like the FreeBSD port (compile the glue against the local kernel, link the blob, wrap as a kext) and ships the result the same way — carrying NVIDIA’s doc/license.txt and not selling it. Building in a sibling repo vs a job inside nextbsd-graphics is a build-architecture choice, not a licensing one.
One kext per FreeBSD nvidia-kmod* port. FreeBSD ships the current driver plus five pinned legacy branches; each becomes a kext carrying that branch’s .kos and its own supported-GPU match table. Crucially, the DRM/KMS bridge (graphics/nvidia-drm-612-kmod, pinned to NextBSD’s drm 6.12 core — see the note in §5) is packaged only for the main and 580 branches; the four older branches are core / X11-only (proprietary /dev/nvidia path, no /dev/dri, no Wayland), so only main/580 depend on IOGraphics.
| FreeBSD port | Branch | GPU generation(s) | DRM/KMS bridge (drm 6.12) | → Kext |
|---|---|---|---|---|
x11/nvidia-kmod | main / current | Turing+ (RTX 20xx → Blackwell) | yes nvidia-drm-612-kmod | NVIDIA.kext |
x11/nvidia-kmod-580 | 580.xx | Maxwell / Pascal / Volta (GTX 900/1000) | yes nvidia-drm-612-kmod-580 | NVIDIA580.kext |
x11/nvidia-kmod-470 | 470.xx | Kepler (GeForce 600/700) | no — X11 only | NVIDIALegacy470.kext |
x11/nvidia-kmod-390 | 390.xx | Fermi (GeForce 400/500) | no | NVIDIALegacy390.kext |
x11/nvidia-kmod-340 | 340.xx | Tesla (GeForce 8/9/200/300) | no | NVIDIALegacy340.kext |
x11/nvidia-kmod-304 | 304.xx | GeForce 6/7 (Curie / NV4x–G7x) | no | NVIDIALegacy304.kext |
(x11/nvidia-kmod-devel is the beta track — an optional NVIDIADevel.kext if wanted.) Matching: vendor 0x10de; a gen-nvidia-personalities parses each branch’s supportedchips.html (NVIDIA’s own per-branch device table) into a branch-specific IOPCIPrimaryMatch list (NVIDIA’s ids are non-contiguous, so exact lists, not ranges). Biggest blocker: the same linuxkpi/DRM KBI fragility — nvidia-drm.ko must be commit-matched to the drm 6.12 core, which is why build-from-source (not a stock pkg .ko) is mandatory. The maintainer accepts rebuilding the NVIDIA ports against drm 6.12 as part of this track.
One plan, but the heterogeneity (open build-from-source vs. NVIDIA recipe-with-blob) is real, so it lands as three repos, with the per-driver-class differences expressed as jobs/subdirs inside the open one rather than a repo explosion:
| Repo | Role | Publishes |
|---|---|---|
nextbsd-redux/drm-kmod | Unmodified, SHA-pinned mirror of freebsd/drm-kmod (the core + intel/amd/radeon source). Kept clean for rebasing. | nothing (a source dep) |
nextbsd-redux/nextbsd-graphics | The open kext factory. Vendors the new drivers (bochs/vboxvideo/virtio/vmwgfx) + drm_extra_helpers.ko; builds them and wraps drm-kmod’s intel/amd/radeon, all via the shared ko2kext/gen-personalities toolchain. | prebuilt .kexts → continuous |
nextbsd-redux/nextbsd-nvidia (name TBD) | The NVIDIA recipe (proprietary, per-legacy-branch). Builds on-target/at-build-time; hosts no binaries. | a port/recipe, not binaries |
Naming: nextbsd-graphics reads cleaner than nextbsd-graphics-modules (these are kexts, not kld modules, and “modules” collides confusingly with nextbsd-kernel-modules). The fork stays plainly drm-kmod. Migration: the current IntelGraphics/AMDGraphics/RadeonGraphics kext work stays in nextbsd-kernel-modules for now; the roadmap migrates it into nextbsd-graphics once that repo exists, so nothing has to move all at once.
nextbsd-graphics; pin the drm-kmod fork by SHA (submodule); decide submodule layout (it dictates every Makefile’s -I block).drm_extra_helpers.ko: vendor + compile drm_simple_kms_helper.c (low risk first), then drm_gem_vram_helper.c (the TTM-coupled blocker); wire in drm_format_helper.c.bochs.c; write its bsd.kmod.mk + bochs_freebsd.c glue; resolve DISPI MMIO/io-port + the aperture handoff.kldload, and bind under qemu -vga std; chase the “binds but black screen” symptom in the VRAM helper to a working KMS console.ko2kext + gen-bochs-personalities.sh → BochsGraphics.kext; add the qemu -vga std line + /dev/dri/card0 + kextstat + dmesg assertions to CI. First end-to-end graphics CI test.vboxvideo + HGSMI; MODULE_DEPEND on drm_extra_helpers; VBoxGraphics.kext on 80ee:beef. Optional VirtualBox-guest CI if a runner exists.linuxkpi virtio bridge: revive linux_virtio.c, fix the compile errors, implement the panic()-stubbed reset/del_vqs, settle the virtio_driver probe model. This is the dominant cost.drm_gem_shmem_helper.c into drm_extra_helpers.ko; re-port the 5.5→6.6 virtgpu deltas.virtgpu_*.c set + glue; new IOKit-matcher plumbing for the virtio sub-bus; ensure the DRM driver beats base virtio_gpu(4).-device virtio-gpu-pci; assert bind + /dev/dri/card0 + renderD128. Descope virgl/3D.ttm_object.c); stub vmwgfx_page_dirty.c for a first cut; VMwareGraphics.kext on 15ad:0405.nextbsd-nvidia as a recipe (fetch unmodified tarball at build; compile nvidia-kmod against the NextBSD kernel; wrap the 3 .kos); start with branch 470 (Kepler), then 390/340; gen-nvidia-personalities from supportedchips.html.drm_gem_vram_helper (bochs/vbox) and drm_gem_shmem_helper (virtio) are absent from drm-kmod and the ravynsoft fork; the kernel-baked linuxkpi was never exercised for them, so the first build surfaces a cascade of missing symbols. The VRAM helper’s TTM coupling yields exactly the “binds but black screen” of drm-kmod issue #62.linuxkpi virtio layer exists; the prototype is against 5.5, doesn’t compile, and panic()s on the mandatory reset/del_vqs. Its scatterlist→sglist conversion and interrupt-context casts are likely buggy under real traffic.IOPCIDevice), so the cleanest end-to-end CI demonstration is bochs, not virtio.nvidia-driver as a binary pkg (LICENSE_PERMS pkg-mirror no-pkg-sell auto-accept); NextBSD ships the kext on the same terms (carry the license file, don’t sell).page_dirty leans on Linux MM internals linuxkpi doesn’t expose; correct (un-stubbed) support may require touching linuxkpi VM-fault handling. kmap_atomic_prot is x86-specific — an arm64 target needs more.Open questions to settle first:
nextbsd-graphics (dictates every Makefile’s -I block).IOPCIPrimaryMatch honor the full 4-tuple (subvendor/subdevice), or only vendor/device? bochs ideally keys on subsystem 1af4:1100 to avoid grabbing non-qemu 1234:1111.CONFIG_DRM_FBDEV_EMULATION? Without it KMS may work but the fbdev console is absent.virtio_gpu(4).LINUXKPI_VERSION 60600) and the CI rule that rebuilds both together.Research scope: 5-agent virtual-GPU workflow (bochs/virtio-gpu/vmwgfx + build architecture + CI/kext/nvidia-drm) + dedicated VirtualBox-vboxvideo and NVIDIA-legacy studies. Primary sources: Linux 6.6 drivers/gpu/drm (tiny/bochs.c, virtio/, vmwgfx/, vboxvideo/), freebsd/drm-kmod (incl. issues #62/#356 and the removed vboxvideo/vmwgfx), ravynsoft/drm-kmod branch virtio (PR #119), freebsd-ports (x11/nvidia-kmod, graphics/nvidia-drm-kmod, emulators/virtualbox-ose-additions), and NVIDIA’s per-branch supportedchips.html + redistribution license. A plan, not a promise — the GEM-helper port and the virtio KPI bridge are the two pieces that decide the schedule.