If your kernel is built with dynamic debug support (CONFIG_DYNAMIC_DEBUG), you can use a boot parameter to enable debug messages for the firmware loader. It should catch all firmware loads, unless a particular driver does something strange and does not use the kernel's firmware loading API for some reason.
Add the following to your boot parameters:
For kernels 2.6 - 4.16: dyndbg="file drivers/base/firmware_class.c +fmp"
For kernels 4.17 and later: dyndbg="file drivers/base/firmware_loader/main.c +fmp"
(For reference, file blah/foo.c +fmp
means "for all debug calls in the kernel source file blah/foo.c
, enable dynamic debug printing, and make the message show the filename and module name". See the kernel docs for more detail.)
After booting, run dmesg | grep firmware_class
. Of particular interest are lines with firmware_class:fw_get_filesystem_firmware
, which should be sandwiched between calls to __allocate_fw_priv
and __free_fw_priv
.
All firmware loads will be logged until you reboot or disable dynamic debugging.
Background information:
You cannot query for "currently loaded" firmware, because firmware doesn't necessarily remain in system memory. It is often uploaded to some chip in some device outside the system. Drivers usually load a firmware file into a kernel buffer, use that buffer to program the device, then discard the buffer without keeping any record of what the file was. And the standard kernel firmware API does not keep a log by default. Some drivers do log their firmware loading to the kernel log, but it's not universal.
The first thought I had was to "get between" the kernel and whatever userspace program is responsible for grabbing firmware files so that I could add some debug messages. But it turns out this is not always possible: the kernel itself it capable of getting firmware straight from the filesystem, no userspace mechanism involved. (In fact, the kernel prefers to direct load straight from /lib/firmware/ when possible.)
The next thought I had was to use kprobe or some other tracing system to trace kernel function calls that are involved in firmware loading. But it turns out I didn't have to go that far: the firmware loader conveniently includes some debug messages that — once enabled — are enough to see all what files are being loaded. The dyndbg
above takes advantage of these.
Other information:
The kernel's firmware loading API is generally accessed by calls to request_firmware() or request_firmware_nowait(). A driver calls one of these functions with the name of the firmware file it wants, and the kernel attempts to load it using this process:
- Check for firmware in the kernel image, load from there if found.
- Check for firmware on the filesystem, load from there if found.
- [If kernel is configured for it] use a sysfs "fallback": create
/sys/firmware/<xxx>/loading
, wait for some program to write firmware to it.
- [If kernel is configured for it] create a uevent to inform udev or whoever is listening that "it would be really great if you could write to this file".
- If too much time passes (specifically whatever length of time is in /sys/firmware/timeout), give up with an error.