How does Linux Kernel know where to look for driver firmware?

I am compiling a custom kernel under Ubuntu, and I ran into a problem that the kernel does not seem to where to look for the firmware. In Ubuntu 8.04, the firmware is tied to the kernel version in the same way as the driver modules. For example, the 2.6.24-24-generic kernel stores its kernel modules in:

/lib/modules/2.6.24-24-generic 

and its firmware in:

 /lib/firmware/2.6.24-24-generic 

When I compile the Ubuntu 2.6.24-24 kernel according to " Alternative build method: Debian's old-fashioned path " I get the appropriate module directory and all my devices except those that require firmware, such as my Intel wireless card (ipw2200 module )

The kernel log shows, for example, that when ipw2200 tries to download firmware, the kernel subsystem that controls the firmware download cannot find it:

 ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2 

errno-base.h defines this as:

 #define ENOENT 2 /* No such file or directory */ 

(The function returning ENOENT places a minus sign in front of it.)

I tried to create a symbolic link in / lib / firmware where my kernel name was pointing to a shared directory 2.6.24-24, however this led to the same error. This firmware is not a GPL provided by Intel and is packaged by Ubuntu. I do not believe that it has a real binding to a specific version of the kernel. cmp shows that versions in different directories are identical.

So how does the kernel know where to look for firmware?

Update

I found this solution for the specific problem that I encountered, however, it no longer works, since Ubuntu deleted /etc/hotplug.d and no longer saves its firmware in /usr/lib/hotplug/firmware .

Update2

Several studies have received several more answers. Prior to version 92 udev , firmware_helper was a way to download firmware. Starting with udev 93, this program has been replaced by a script called firmware.sh, which provides identical functionality, as far as I can tell. Both of these files indicate the firmware path to /lib/firmware . Ubuntu still uses the binary /lib/udev/firmware_helper binary.

The name of the firmware file is passed by firmware_helper to the $FIRMWARE environment variable, which is combined with the /lib/firmware loop and used to download the firmware.

The actual request to download the firmware was made by the driver (ipw2200 in my case) using a system call:

 request_firmware(..., "ipw2200-bss.fw", ...); 

Now, somewhere between the driver calling request_firmware and firmware_helper looking at the $FIRMWARE environment variable, the kernel package name is added to the firmware name.

So who does this?

+44
linux-kernel linux-device-driver firmware
Jun 04 '09 at 12:04
source share
4 answers

From a kernel perspective, see / usr / src / linux / Documentation / firmware_class / README :

  kernel (driver): calls request_firmware (& fw_entry, $ FIRMWARE, device)

  userspace:
         - / sys / class / firmware / xxx / {loading, data} appear.
         - hotplug gets called with a firmware identifier in $ FIRMWARE
           and the usual hotplug environment.
                 - hotplug: echo 1> / sys / class / firmware / xxx / loading

  kernel: Discard any previous partial load.

  userspace:
                 - hotplug: cat appropriate_firmware_image> \
                                         / sys / class / firmware / xxx / data

  kernel: grows a buffer in PAGE_SIZE increments to hold the image as it
          comes in.

  userspace:
                 - hotplug: echo 0> / sys / class / firmware / xxx / loading

  kernel: request_firmware () returns and the driver has the firmware
          image in fw_entry -> {data, size}.  If something went wrong
          request_firmware () returns non-zero and fw_entry is set to
          NULL

  kernel (driver): Driver code calls release_firmware (fw_entry) releasing
                  the firmware image and any related resource.

The kernel does not actually load the firmware. It simply informs the user space: “I want firmware called xxx” and waits for the user space to return the firmware image back to the kernel.

Now, on Ubuntu 8.04,

 $ grep firmware /etc/udev/rules.d/80-program.rules
 # Load firmware on demand
 SUBSYSTEM == "firmware", ACTION == "add", RUN + = "firmware_helper"

as you discovered, udev configured to run firmware_helper when the kernel asks for firmware.

 $ apt-get source udev
 Reading package lists ... Done
 Building dependency tree
 Reading state information ... Done
 Need to get 312kB of source archives.
 Get: 1 http://us.archive.ubuntu.com hardy-security / main udev 117-8ubuntu0.2 (dsc) [716B]
 Get: 2 http://us.archive.ubuntu.com hardy-security / main udev 117-8ubuntu0.2 (tar) [245kB]
 Get: 3 http://us.archive.ubuntu.com hardy-security / main udev 117-8ubuntu0.2 (diff) [65.7kB]
 Fetched 312kB in 1s (223kB / s)
 gpg: Signature made Tue Apr 14, 2009 5:31:34 PM PM EDT using DSA key ID 17063E6D
 gpg: Can't check signature: public key not found
 dpkg-source: extracting udev in udev-117
 dpkg-source: unpacking udev_117.orig.tar.gz
 dpkg-source: applying ./udev_117-8ubuntu0.2.diff.gz
 $ cd udev-117 /
 $ cat debian / patches / 80-extras-firmware.patch

If you read the source code, you will find that Ubuntu wrote firmware_helper , which is hard-coded to first look for /lib/modules/$(uname -r)/$FIRMWARE , then /lib/modules/$FIRMWARE and other places. Translating it to sh , it does something like the following:

 echo -n 1 > /sys/$DEVPATH/loading cat /lib/firmware/$(uname -r)/$FIRMWARE > /sys/$DEVPATH/data \ || cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data if [ $? = 0 ]; then echo -n 1 > /sys/$DEVPATH/loading echo -n -1 > /sys/$DEVPATH/loading fi 

which exactly matches the kernel format.




In short: the Ubuntu udev package has settings that always look in /lib/firmware/$(uname -r) . This policy is processed in user space.

+38
Jun 04 '09 at 10:15
source share

Wow, this is very useful information, and this led me to solve my problem when creating a custom USB kernel module for a device that requires firmware.

Basically, every Ubuntu offers a new rework of hal, sysfs, devfs, udev, etc .... and things just change. In fact, I read that they stopped using hal.

So, let's convert this again to fit the latest [Ubuntu] systems.

Ubuntu Lucid (the latter at the time of writing) uses /lib/udev/rules.d/50-firmware.rules . This file calls the binary /lib/udev/firmware where the magic happens.

Listing: /lib/udev/rules.d/50-firmware.rules

 # firmware-class requests, copies files into the kernel SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware --firmware=$env{FIRMWARE} --devpath=$env{DEVPATH}" 

The magic should be something like these lines (source: Linux device drivers, 3rd ed., Chapter 14: Linux device model )

  • from echo from 1 to loading
  • copy firmware to data
  • upon failure, from echo -1 to loading and stopping the firmware download process
  • echo 0 to loading (kernel signal)
  • then a specific kernel module receives data and pushes it to the device

If you look at the Lucid source page for udev, in udev-151/extras/firmware/firmware.c , the source for this firmware / lib / udev / firmware library is what happens.

Exposure: Lucid source, udev-151 / extras / firmware / firmware.c

  util_strscpyl(datapath, sizeof(datapath), udev_get_sys_path(udev), devpath, "/data", NULL); if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) { err(udev, "error sending firmware '%s' to device\n", firmware); set_loading(udev, loadpath, "-1"); rc = 4; goto exit; }; set_loading(udev, loadpath, "0"); 

In addition, many devices use the Intel HEX format (text files containing a checksum and other materials) (I have no reputation on wiki and no way to link). The ihex2fw kernel program (called from the Makefile to kernel_source / lib / firmware on .HEX files) converts these HEX files to an arbitrary binary format, which the Linux kernel selects with request_ihex_firmware , because they thought reading text files in the Kernel was stupid ( it will slow down).

+11
Jun 10 2018-10-10T00:
source share

On current Linux systems, this is handled through udev and firmware.agent .

+1
Jun 04 '09 at 12:12
source share

Linux 3.5.7 Gentoo, I have the same problem. SOLVE:

 emerge ipw2200-firmware 

Then go to / usr / src / linux

 make menucofig 

in the device driver, remove all wirless drivers, no need, install Intell 2200 as a module and recompile.

 make make modules_install cp arch/x86/boot/bzImage /boot/kernel-yourdefault 
+1
Feb 26 '13 at 9:59
source share



All Articles