← Back · the faithful follow-on to the kext PoC (#183); gates #179 / #177

Faithful kext_tools / OSKext port

The kext PoC (#183) proved the load path with a minimal kld-backed trio. This plan ports Apple’s real OSKext engine (bundle discovery, dependency-graph resolution, validation, personalities) onto NextBSD with a kld backend — the faithful foundation the bulk conversion (#179) and the kextd autoloader (#177) build on. Tracking ticket: nextbsd#182.

2026-06-04. Code-grounded scope of Apple IOKitUser kext.subproj/OSKext.c (pre-SIP, APSL 2.0) against the NextBSD tree (libCoreFoundation, libIOKit, the kld syscalls).

Verdict Realistic — ~75% of OSKext.c ports unchanged. OSKext.c is ~21k LOC but highly modular. Bundle discovery, Info.plist parsing, dependency-graph math, and validation (~15.7k LOC) are CoreFoundation-based and portable as-is. Only ~5.3k LOC (25%) is XNU-specific and swaps out: the load path (kext_request MIG → kldload), unload (→ kldunload), and the KXLD linker / mkext / prelink code (deleted — the kernel’s kld does the linking). Personalities (IOCatalogueSendData) are stubbed here: NextBSD has no in-kernel IOCatalogue, and device matching is userspace — the personality→match→load loop is kextd’s job in #177 (which is also what retires hwregd), not a bridge to hwregd in this port. Pre-SIP avoids codesign/AuxKC/kernelcache entirely.

Scale This is a multi-week, phased effort (est. ~3k LOC written + the 21k-LOC vendor drop; ~5–6 weeks to production), not a single PR. It is sequenced after #180 (done) and lands in phases, each independently mergeable and CI-gated. Phase 1 (dependency resolution) is the first shippable milestone.

Contents

  1. What OSKext is (and what we keep)
  2. Dependency surface vs. NextBSD
  3. The re-backing: XNU → kld
  4. Phased delivery
  5. The kext_tools family on top
  6. Risks

1. What OSKext is (and what we keep)

Base: a pre-SIP IOKitUser release (APSL 2.0; ~2008–2012), to minimize codesign/kernelcache surface. kext.subproj/OSKext.c ≈ 21k LOC. Responsibility map:

Component~LOCDisposition
Bundle discovery (OSKextCreate*, caching)2,000keep (CFBundle)
Info.plist parsing (arch-keyed lookup)1,500keep (libCoreFoundation)
Dependency-graph resolution (OSBundleLibraries, topo-sort, version/compat)2,500keep (in-memory graph)
Validation (Mach-O format, plist)3,000keep (minus codesign)
Load path (kext_request MIG, mkext)2,000re-back → kld
Personalities (IOCatalogueSendData)1,500stub in #182; real match→load is kextd (#177) — not hwregd
Unload (kext_request stop)800re-back → kldunload
KXLD linking / mkext / prelink (AuxKC)3,000delete (kld links)
Codesign / Security.framework800stub/delete (pre-SIP)
Utilities, logging, diagnostics, caching4,000keep

2. Dependency surface vs. NextBSD

OSKext needsNextBSD statusWork
CoreFoundation (CFBundle/Dictionary/Array/Data/Serialize)have libCoreFoundation (full)none
IOKitLib (IOCFSerialize/Unserialize, IOCatalogue feed)have libIOKit; missing IOCatalogue feedlow — add a matcher-feed shim
Mach kext_request (load/unload/query)absent by design (we use kld)high — re-back onto kld (the heart of the port)
KXLD linker, mkext, prelinked kerneln/a (kld links in-kernel)delete
codesign / Security.framework / kernelcachenot wanted (no SIP)stub/delete (pre-SIP)

~95% of dependencies are already satisfied by NextBSD’s libCoreFoundation + libIOKit. The one genuine kernel-interface gap this port closes is kext_request (→ kld). IOCatalogueSendData has no NextBSD analog (no in-kernel IOCatalogue) and is stubbed — userspace personality matching is kextd’s job (#177), which is when hwregd is retired.

3. The re-backing: XNU → kld

OSKextLoad / __OSKextLoadWithArgsDict
   XNU:  build mkext (linked) -> kext_request(HOST_PRIV) -> kernel links+loads
   kld:  resolve deps (UNCHANGED) -> for each, kldload(Contents/MacOS/<exec>) in order
                                   -> feed IOKitPersonalities to the matcher

OSKextReadLoadedKextInfo / OSKextIsLoaded
   XNU:  kext_request "Get Loaded"        kld:  kldnext(0) loop + kldstat(id)

__OSKextUnload
   XNU:  kext_request "Stop"              kld:  reverse-dep check (UNCHANGED) -> kldunload(id)

OSKextSendPersonalitiesToKernel
   XNU:  IOCatalogueSendData(kIOCatalogAddDrivers)  [in-kernel IOCatalogue matches]
   NextBSD #182:  STUB (no in-kernel IOCatalogue)
   NextBSD #177:  kextd holds the personalities it scanned from /S/L/E and matches
                  them in USERSPACE against device-match notifications (the #176
                  device_match hook + EVFILT_MACHPORT) -> OSKext-loads the match.
                  This loop replaces hwregd, so #177 is the PR that deletes hwregd.

The dependency-graph resolution, version/compat math, bundle parsing, and validation — the genuinely hard logic — are reused verbatim. The swap is concentrated in a small OSKext_FreeBSD.c (~600 LOC of kld wrappers + the matcher feed).

4. Phased delivery

  1. Phase 0 — vendor + compile. Drop kext.subproj into nextbsd/src/kext_tools; build against libCoreFoundation/libIOKit with the kext_request/IOCatalogue/KXLD paths stubbed. Deliverable: OSKext compiles; load fails gracefully. (This phase is itself iterative — getting 21k LOC to compile against the NextBSD headers is the bulk of the early CI churn; do it behind a build flag so it can’t regress the shipping image until it links.)
  2. Phase 1 — dependency resolution + validation (first shippable). OSKextResolveDependencies, OSKextCopyLoadList (topo-sort), OSKextValidate (no codesign). A kextlibs/kextdeps CLI prints resolved load order. Feeds #179 (dependency-correct conversion).
  3. Phase 2 — kld load/unload/query. The OSKext_FreeBSD.c wrappers; kextload/kextunload/kextstat graduate from the minimal trio to OSKext-backed (dependency-ordered load, reverse-dep unload).
  4. Phase 3 — personalities API (no hwregd bridge). Keep OSKextSendPersonalitiesToKernel a stub and instead expose the parsed IOKitPersonalities to callers. The actual device-match→load loop — and hwregd’s retirement — is built in #177 (kextd) on top of this + the #176 notifications, not here. (Avoid wiring OSKext into hwregd: hwregd is the thing #177 deletes.)
  5. Phase 4 — polish. diagnostics, caching, kextfind/kextutil/kextsymboltool. kextcache (collections) deferred — ties to the boot-collection work, not needed early.

First shippable milestone = Phase 1 (dependency resolution); loading arrives in Phase 2.

5. The kext_tools family on top

ToolWith OSKextWeight
kextload/kextunloaddependency-ordered load / reverse-dep unload (today: bare kld)medium
kextstatkld state + dependency/personality infosmall
kextfindfind kexts by identifier over /System/Library/Extensionsthin
kextlibssymbol→OSBundleLibraries (the converter’s dep step, §5 of the conversion plan)medium
kextsymboltoolkext symbol filesthin
kextcachecollection builder — deferred (boot-collection work)heavy

6. Risks

OSKext port plan, 2026-06-04. Follows the kext PoC (#183, proven), gates the faithful parts of #179 and #177. Sourced from Apple IOKitUser kext.subproj/OSKext.{c,h} (pre-SIP, APSL 2.0) and the NextBSD libCoreFoundation/libIOKit/kld surface.