FreeBSD devmatch: Diagnose Device-to-Driver Auto-Loading
Trace FreeBSD devmatch from unmatched-device evidence to module candidates, blocklist decisions, and verification without mistaking a match for a working driver.
FreeBSD’s devmatch(8) helps explain one narrow but important part of device discovery: which loadable kernel modules advertise a match for an enabled device that is not attached. It is a diagnostic and auto-loading component in a larger path involving a bus driver, kernel PNP metadata, linker.hints, devd, and the module loader. A reported candidate is not proof that a driver was loaded, attached, configured, or able to operate the hardware.
That distinction makes devmatch useful during triage. Instead of manually loading every plausible module, first ask what the running system can match and then verify each later stage independently. The commands below are intended for evidence gathering. Test any change to automatic loading in a disposable VM or a maintenance window, especially when the device provides storage, network access, or the only console.
The matching path has several separate stages
The bus reports device identity information, which FreeBSD documentation broadly calls PNP data. PNP in this context is not limited to legacy ISA Plug and Play. It includes the identifying data exposed by buses such as USB and PCI. Kernel modules can publish tables that associate such identities with a driver. The build process makes module hints available for lookup, and devmatch compares those hints with devices in the system.
The ordinary devmatch invocation lists modules it found for unattached, enabled devices. That is a candidate report, not a probe result. The module may not be present in the active module path, the PNP table may omit the device revision or alias, or the module may load and still fail to attach. Some drivers do not publish complete PNP table metadata, which means an empty result is not conclusive evidence that no driver exists.
The runtime event path adds another layer. The default devd configuration handles a NOMATCH event by invoking the devmatch service for that event. The event-based input lets matching run against the device notification instead of rescanning the full device tree. The devmatch utility reports candidates; the separate RC service applies the blocklist and may then attempt to load an eligible module. After that, the bus and driver still have to perform normal attachment and initialization.
Use the following mental model when reading logs:
- The bus enumerates a device and supplies identity data.
- Kernel driver tables and module hints determine which modules advertise a match.
devmatchreports a candidate; the RC service may then attempt to load it.- The kernel driver probes and either attaches or declines.
- The attached driver creates interfaces or devices that can then be configured and tested.
Each boundary has different evidence. A devmatch match is not the same as devinfo showing an attached driver, and an attached driver is not the same as successful device I/O.
Start with read-only inventory
Record the exact release and kernel before comparing output with a manual page or another machine. Then inspect normal candidates, include already-attached devices for comparison, and review the generated hints only when necessary:
freebsd-version -kru
uname -a
devmatch -v
devmatch -a -v
devmatch -d
devmatch -u -v
The flags answer different questions. -a includes all devices rather than only unattached ones. -d prints a human-readable linker.hints dump. -u attempts to list drivers with PNP information whose driver tables containing that PNP information cannot be found. Avoid interpreting these as interchangeable “show everything” modes. Save the command, standard output, standard error, exit status, kernel version, and module path together so a later comparison is meaningful.
For a focused live event, preserve the exact standard NOMATCH event emitted by devd and pass that event to devmatch -p. Do not invent a shortened event string: the manual specifies that this option parses the standard event format. If reproducing an event in a lab, keep the event fields intact and record whether the result came from live hardware or a synthetic fixture.
Interpret candidates without overstating them
If devmatch prints a plausible module, verify what happened next. The diagnostic invocation reports candidates; it does not prove a load was requested. For the event-driven path, check the kernel message around the event, inspect the device tree, and query the module list. A candidate that is still not present in kldstat may not have been attempted, may have failed to load, or may have been excluded by configuration. A module that is loaded but has no attached device may have declined during probe or may not match the actual device revision.
If no candidate appears, work through the evidence in order rather than trying random kldload commands:
| Observation | Questions to test |
|---|---|
| Device is absent from the device tree | Did the bus enumerate it? Is firmware, cabling, power, or the bus controller involved? |
| Device is present but unattached | Does the module contain an appropriate PNP table? Does the running release include the driver? |
| Hints are absent or stale | Is the expected module in the current module path, and were hints generated for that tree? |
| Candidate loads but probe fails | What exact kernel diagnostic or driver-specific manual explains the failure? |
| Device attaches but does not function | Are interface creation, firmware loading, configuration, and device-level tests succeeding? |
The MODULE_PNP_INFO(9) interface is relevant to driver authors because it documents how module PNP information is declared. For operators, its significance is diagnostic: matching depends on the information a driver publishes, not on a universal database that knows every hardware revision. A missing candidate can therefore be a metadata or packaging gap rather than evidence that the hardware is unsupported.
Also account for documented output quirks. The devmatch(8) manual warns that some modules are hard links in /boot/kernel and can be reported twice. It also notes limitations in PNP table decorations. Deduplicate a report for analysis, but retain the original output as evidence instead of silently removing repeated lines from the record.
Control automatic loading narrowly
rc.conf(5) documents devmatch_enable=NO as disabling automatic loading of kernel modules through devmatch. It also documents devmatch_blocklist as a whitespace-separated list of module names to ignore. A boot-loader kenv value named devmatch_blocklist is appended to the configured list. The older devmatch_blacklist variable is deprecated. kld_list is a separate mechanism for loading named modules after local disks are mounted; do not treat it as another spelling of a devmatch match rule.
For a controlled test, preserve the existing configuration and add only the intended exclusion in a lab copy of /etc/rc.conf. This assignment replaces the current value, so use it only when no blocklist is already configured:
# Example only, when no blocklist is already set; the value is a placeholder.
devmatch_blocklist="if_example"
Do not paste the example name into a production configuration. If a blocklist already exists, append the confirmed module name to that existing whitespace-separated value rather than replacing its entries or adding a second assignment. First determine whether the intended module is required for boot storage, networking, or management access. Record the original value, test one change at a time, and maintain a recovery path. After a controlled reboot or event test, verify that the unwanted module was not auto-loaded and that required devices still attach. Restore the previous value when the test is complete.
Disabling the automatic path is not a repair for a wrong driver match, a missing driver, or a broken hardware probe. It changes how candidates are automatically loaded; the right correction may instead be a module update, a driver-table fix, a release-specific regression report, or a supported manual configuration. Avoid using a broad blocklist to mask a kernel error.
Build a useful incident record
For each device, record the bus path, vendor and product identity as exposed by the system, the exact event time, devmatch output, relevant devd and kernel messages, module state, and final attachment state. Include the FreeBSD release, kernel build, architecture, and whether the module is built into the kernel or supplied as a loadable module. If you compare working and failing hosts, compare those fields before concluding that the driver table changed.
The stopping condition is a stage-specific finding. For example: “the USB bus enumerates the device; devmatch reports no candidate; the installed driver has no matching table entry” is actionable and bounded. “FreeBSD cannot see the device” collapses enumeration, matching, module loading, attachment, and function into an ambiguous claim.
Related:
- FreeBSD KLD Modules: Runtime Loading, Dependencies, and Safe Unload
- FreeBSD devctl Operations: Inspect and Change Device State Safely
Sources:
- FreeBSD upstream
devmatch(8)manual - command flags, behavior, event parsing, known output and PNP metadata limitations. - FreeBSD 15.1
rc.conf(5)manual -devmatch_enable,devmatch_blocklist, deprecateddevmatch_blacklist, and separatekld_listsemantics. - FreeBSD
devmatchimplementation - upstream matching and candidate-reporting implementation. - FreeBSD
devmatchRC service - applies the blocklist and invokesload_kldfor eligible candidates. - FreeBSD default
devdrule fordevmatch- upstreamNOMATCHevent integration. - FreeBSD upstream
MODULE_PNP_INFO(9)manual - the kernel-module interface for declaring PNP match metadata.