← Back · the faithful follow-on to the kext PoC (#183); gates #179 / #177
kext_tools / OSKext portThe 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.
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.
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 | ~LOC | Disposition |
|---|---|---|
Bundle discovery (OSKextCreate*, caching) | 2,000 | keep (CFBundle) |
| Info.plist parsing (arch-keyed lookup) | 1,500 | keep (libCoreFoundation) |
Dependency-graph resolution (OSBundleLibraries, topo-sort, version/compat) | 2,500 | keep (in-memory graph) |
| Validation (Mach-O format, plist) | 3,000 | keep (minus codesign) |
Load path (kext_request MIG, mkext) | 2,000 | re-back → kld |
Personalities (IOCatalogueSendData) | 1,500 | stub in #182; real match→load is kextd (#177) — not hwregd |
Unload (kext_request stop) | 800 | re-back → kldunload |
| KXLD linking / mkext / prelink (AuxKC) | 3,000 | delete (kld links) |
| Codesign / Security.framework | 800 | stub/delete (pre-SIP) |
| Utilities, logging, diagnostics, caching | 4,000 | keep |
| OSKext needs | NextBSD status | Work |
|---|---|---|
| CoreFoundation (CFBundle/Dictionary/Array/Data/Serialize) | have libCoreFoundation (full) | none |
| IOKitLib (IOCFSerialize/Unserialize, IOCatalogue feed) | have libIOKit; missing IOCatalogue feed | low — 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 kernel | n/a (kld links in-kernel) | delete |
| codesign / Security.framework / kernelcache | not 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.
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).
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.)OSKextResolveDependencies, OSKextCopyLoadList (topo-sort), OSKextValidate (no codesign). A kextlibs/kextdeps CLI prints resolved load order. Feeds #179 (dependency-correct conversion).OSKext_FreeBSD.c wrappers; kextload/kextunload/kextstat graduate from the minimal trio to OSKext-backed (dependency-ordered load, reverse-dep unload).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.)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.
| Tool | With OSKext | Weight |
|---|---|---|
kextload/kextunload | dependency-ordered load / reverse-dep unload (today: bare kld) | medium |
kextstat | kld state + dependency/personality info | small |
kextfind | find kexts by identifier over /System/Library/Extensions | thin |
kextlibs | symbol→OSBundleLibraries (the converter’s dep step, §5 of the conversion plan) | medium |
kextsymboltool | kext symbol files | thin |
kextcache | collection builder — deferred (boot-collection work) | heavy |
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.