I'm compiling a custom kernel under Ubuntu and I'm running into the problem that my kernel doesn't seem to know where to look for firmware. Under Ubuntu 8.04, firmware is tied to kernel version the same way driver modules are. For example, kernel 2.6.24-24-generic stores its kernel modules in:
我正在Ubuntu下编译一个自定义内核,我遇到的问题是我的内核似乎不知道在哪里寻找固件。在Ubuntu 8.04下,固件与内核版本绑定的方式与驱动程序模块相同。例如,内核2.6.24-24-generic将其内核模块存储在:
/lib/modules/2.6.24-24-generic
and its firmware in:
及其固件:
/lib/firmware/2.6.24-24-generic
When I compile the 2.6.24-24-generic Ubuntu kernel according the "Alternate Build Method: The Old-Fashioned Debian Way" I get the appropriate modules directory and all my devices work except those requiring firmware such as my Intel wireless card (ipw2200 module).
当我按照“备用构建方法:老式Debian方式”编译2.6.24-24通用Ubuntu内核时,我得到了相应的模块目录,除了需要固件的设备外,我的所有设备都工作,例如我的英特尔无线网卡(ipw2200)模块)。
The kernel log shows for example that when ipw2200 tries to load the firmware the kernel subsystem controlling the loading of firmware is unable to locate it:
内核日志显示,例如,当ipw2200尝试加载固件时,控制固件加载的内核子系统无法找到它:
ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2
errno-base.h defines this as:
errno-base.h将其定义为:
#define ENOENT 2 /* No such file or directory */
(The function returning ENOENT puts a minus in front of it.)
(返回ENOENT的函数在它前面加一个减号。)
I tried creating a symlink in /lib/firmware where my kernel's name pointed to the 2.6.24-24-generic directory, however this resulted in the same error. This firmware is non-GPL, provided by Intel and packed by Ubuntu. I don't believe it has any actual tie to a particular kernel version. cmp
shows that the versions in the various directories are identical.
我尝试在/ lib / firmware中创建一个符号链接,其中我的内核名称指向2.6.24-24-generic目录,但是这导致了同样的错误。此固件是非GPL,由Intel提供并由Ubuntu打包。我不相信它与特定内核版本有任何实际联系。 cmp显示各个目录中的版本是相同的。
So how does the kernel know where to look for firmware?
那么内核如何知道在哪里寻找固件呢?
Update
I found this solution to the exact problem I'm having, however it no longer works as Ubuntu has eliminated /etc/hotplug.d
and no longer stores its firmware in /usr/lib/hotplug/firmware
.
我找到了解决我遇到的确切问题的解决方案,但是它不再有效,因为Ubuntu已经取消了/etc/hotplug.d并且不再将其固件存储在/ usr / lib / hotplug / firmware中。
Update2
Some more research turned up some more answers. Up until version 92 of udev
, the program firmware_helper
was the way firmware got loaded. Starting with udev
93 this program was replaced with a script named firmware.sh providing identical functionality as far as I can tell. Both of these hardcode the firmware path to /lib/firmware
. Ubuntu still seems to be using the /lib/udev/firmware_helper
binary.
一些更多的研究提出了更多的答案。直到udev版本92,程序firmware_helper才是固件加载的方式。从udev 93开始,这个程序被替换为一个名为firmware.sh的脚本,据我所知,它提供了相同的功能。这两个都硬编码到/ lib / firmware的固件路径。 Ubuntu似乎仍在使用/ lib / udev / firmware_helper二进制文件。
The name of the firmware file is passed to firmware_helper
in the environment variable $FIRMWARE
which is concatenated to the path /lib/firmware
and used to load the firmware.
固件文件的名称将传递给环境变量$ FIRMWARE中的firmware_helper,该变量连接到路径/ lib / firmware并用于加载固件。
The actual request to load the firmware is made by the driver (ipw2200 in my case) via the system call:
加载固件的实际请求是由驱动程序(在我的情况下为ipw2200)通过系统调用完成的:
request_firmware(..., "ipw2200-bss.fw", ...);
Now somewhere in between the driver calling request_firmware
and firmware_helper
looking at the $FIRMWARE
environment variable, the kernel package name is getting prepended to the firmware name.
现在位于驱动程序调用request_firmware和firmware_helper查看$ FIRMWARE环境变量之间的某个地方,内核程序包名称将被添加到固件名称之前。
So who's doing it?
那么谁在做呢?
4 个解决方案
#1
From the kernel's perspective, see /usr/src/linux/Documentation/firmware_class/README:
从内核的角度来看,请参阅/ 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 doesn't actually load any firmware at all. It simply informs userspace, "I want a firmware by the name of xxx", and waits for userspace to pipe the firmware image back to the kernel.
内核实际上根本不加载任何固件。它只是通知用户空间,“我想要一个名为xxx的固件”,并等待用户空间将固件映像传送回内核。
Now, on Ubuntu 8.04,
现在,在Ubuntu 8.04上,
$ grep firmware /etc/udev/rules.d/80-program.rules # Load firmware on demand SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"
so as you've discovered, udev
is configured to run firmware_helper
when the kernel asks for firmware.
正如您所发现的那样,udev配置为在内核请求固件时运行firmware_helper。
$ 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 14 Apr 2009 05:31:34 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, you'll find that Ubuntu wrote a firmware_helper
which is hard-coded to first look for /lib/modules/$(uname -r)/$FIRMWARE
, then /lib/modules/$FIRMWARE
, and no other locations. Translating it to sh
, it does approximately this:
如果您阅读了源代码,您会发现Ubuntu编写了一个solid_helper,它是硬编码的,首先查找/ lib / modules / $(uname -r)/ $ FIRMWARE,然后是/ lib / modules / $ FIRMWARE,没有其他地方。把它翻译成sh,它大致如下:
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 is exactly the format the kernel expects.
这正是内核期望的格式。
To make a long story short: Ubuntu's udev
package has customizations that always look in /lib/firmware/$(uname -r)
first. This policy is being handled in userspace.
总而言之:Ubuntu的udev软件包具有首先在/ lib / firmware / $(uname -r)中查找的自定义。此策略正在用户空间中处理。
#2
Wow this is very useful information and it led me to the solution for my problem when making a custom USB kernel module for a device requiring firmware.
哇这是非常有用的信息,它使我在为需要固件的设备制作自定义USB内核模块时解决了我的问题。
Basically, every Ubuntu brings a new rehash of hal,sysfs,devfs,udev,and so on...and things just change. In fact I read they stopped using hal.
基本上,每个Ubuntu都会带来hal,sysfs,devfs,udev等的新版本......而且事情只会改变。事实上我读过他们停止使用hal。
So let's reverse engineer this yet again so it's pertinent to the latest [Ubuntu] systems.
所以让我们再次对它进行逆向工程,这与最新的[Ubuntu]系统相关。
On Ubuntu Lucid (the latest at time of writing), /lib/udev/rules.d/50-firmware.rules
is used. This file calls the binary /lib/udev/firmware
, where magic happens.
在Ubuntu Lucid(编写本文时),使用/lib/udev/rules.d/50-firmware.rules。这个文件调用二进制/ lib / udev / firmware,魔术发生在那里。
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 along these lines (source: Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model):
魔术应该是这些方面的东西(来源:Linux设备驱动程序,第3版,第14章:Linux设备模型):
- echo 1 to
loading
- copy firmware to
data
- on failure, echo -1 to
loading
and halt firmware loading process - echo 0 to
loading
(signal the kernel) - then, a specific kernel module receives the data and pushes it to the device
回显1加载
将固件复制到数据
失败时,回显-1加载并停止固件加载过程
echo 0加载(发信号内核)
然后,特定的内核模块接收数据并将其推送到设备
If you look at Lucid's source page for udev, in udev-151/extras/firmware/firmware.c
, the source for that firmware /lib/udev/firmware binary, that's exactly what goes on.
如果你看看udev的Lucid的源页面,在udev-151 / extras / firmware / firmware.c中,该固件/ lib / udev / firmware二进制文件的来源,这正是发生的事情。
Excerpt: Lucid source, udev-151/extras/firmware/firmware.c
摘录: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");
Additionally, many devices use an Intel HEX format (textish files containing checksum and other stuff) (wiki it i have no reputation and no ability to link). The kernel program ihex2fw (called from Makefile in kernel_source/lib/firmware on .HEX files) converts these HEX files to an arbitrary-designed binary format that the Linux kernel then picks up with request_ihex_firmware
, because they thought reading text files in the kernel was silly (it would slow things down).
此外,许多设备使用英特尔HEX格式(包含校验和和其他东西的文本文件)(维基,我没有声誉,没有链接能力)。内核程序ihex2fw(从.sEX文件中的kernel_source / lib / firmware中的Makefile调用)将这些HEX文件转换为任意设计的二进制格式,然后Linux内核将其与request_ihex_firmware一起获取,因为他们认为在内核中读取文本文件是愚蠢(这会减慢事情)。
#3
On current Linux systems, this is handled via udev
and the firmware.agent
.
在当前的Linux系统上,这是通过udev和firmware.agent处理的。
#4
Linux 3.5.7 Gentoo, I have the same issue. SOLVED:
Linux 3.5.7 Gentoo,我有同样的问题。解决了:
emerge ipw2200-firmware
Then go to /usr/src/linux
然后转到/ usr / src / linux
make menucofig
on device driver, remove all wirless drivers don't needed, set Intell 2200 as module and recompile.
在设备驱动程序上,删除不需要的所有无线驱动程序,将Intell 2200设置为模块并重新编译。
make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault
#1
From the kernel's perspective, see /usr/src/linux/Documentation/firmware_class/README:
从内核的角度来看,请参阅/ 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 doesn't actually load any firmware at all. It simply informs userspace, "I want a firmware by the name of xxx", and waits for userspace to pipe the firmware image back to the kernel.
内核实际上根本不加载任何固件。它只是通知用户空间,“我想要一个名为xxx的固件”,并等待用户空间将固件映像传送回内核。
Now, on Ubuntu 8.04,
现在,在Ubuntu 8.04上,
$ grep firmware /etc/udev/rules.d/80-program.rules # Load firmware on demand SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"
so as you've discovered, udev
is configured to run firmware_helper
when the kernel asks for firmware.
正如您所发现的那样,udev配置为在内核请求固件时运行firmware_helper。
$ 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 14 Apr 2009 05:31:34 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, you'll find that Ubuntu wrote a firmware_helper
which is hard-coded to first look for /lib/modules/$(uname -r)/$FIRMWARE
, then /lib/modules/$FIRMWARE
, and no other locations. Translating it to sh
, it does approximately this:
如果您阅读了源代码,您会发现Ubuntu编写了一个solid_helper,它是硬编码的,首先查找/ lib / modules / $(uname -r)/ $ FIRMWARE,然后是/ lib / modules / $ FIRMWARE,没有其他地方。把它翻译成sh,它大致如下:
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 is exactly the format the kernel expects.
这正是内核期望的格式。
To make a long story short: Ubuntu's udev
package has customizations that always look in /lib/firmware/$(uname -r)
first. This policy is being handled in userspace.
总而言之:Ubuntu的udev软件包具有首先在/ lib / firmware / $(uname -r)中查找的自定义。此策略正在用户空间中处理。
#2
Wow this is very useful information and it led me to the solution for my problem when making a custom USB kernel module for a device requiring firmware.
哇这是非常有用的信息,它使我在为需要固件的设备制作自定义USB内核模块时解决了我的问题。
Basically, every Ubuntu brings a new rehash of hal,sysfs,devfs,udev,and so on...and things just change. In fact I read they stopped using hal.
基本上,每个Ubuntu都会带来hal,sysfs,devfs,udev等的新版本......而且事情只会改变。事实上我读过他们停止使用hal。
So let's reverse engineer this yet again so it's pertinent to the latest [Ubuntu] systems.
所以让我们再次对它进行逆向工程,这与最新的[Ubuntu]系统相关。
On Ubuntu Lucid (the latest at time of writing), /lib/udev/rules.d/50-firmware.rules
is used. This file calls the binary /lib/udev/firmware
, where magic happens.
在Ubuntu Lucid(编写本文时),使用/lib/udev/rules.d/50-firmware.rules。这个文件调用二进制/ lib / udev / firmware,魔术发生在那里。
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 along these lines (source: Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model):
魔术应该是这些方面的东西(来源:Linux设备驱动程序,第3版,第14章:Linux设备模型):
- echo 1 to
loading
- copy firmware to
data
- on failure, echo -1 to
loading
and halt firmware loading process - echo 0 to
loading
(signal the kernel) - then, a specific kernel module receives the data and pushes it to the device
回显1加载
将固件复制到数据
失败时,回显-1加载并停止固件加载过程
echo 0加载(发信号内核)
然后,特定的内核模块接收数据并将其推送到设备
If you look at Lucid's source page for udev, in udev-151/extras/firmware/firmware.c
, the source for that firmware /lib/udev/firmware binary, that's exactly what goes on.
如果你看看udev的Lucid的源页面,在udev-151 / extras / firmware / firmware.c中,该固件/ lib / udev / firmware二进制文件的来源,这正是发生的事情。
Excerpt: Lucid source, udev-151/extras/firmware/firmware.c
摘录: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");
Additionally, many devices use an Intel HEX format (textish files containing checksum and other stuff) (wiki it i have no reputation and no ability to link). The kernel program ihex2fw (called from Makefile in kernel_source/lib/firmware on .HEX files) converts these HEX files to an arbitrary-designed binary format that the Linux kernel then picks up with request_ihex_firmware
, because they thought reading text files in the kernel was silly (it would slow things down).
此外,许多设备使用英特尔HEX格式(包含校验和和其他东西的文本文件)(维基,我没有声誉,没有链接能力)。内核程序ihex2fw(从.sEX文件中的kernel_source / lib / firmware中的Makefile调用)将这些HEX文件转换为任意设计的二进制格式,然后Linux内核将其与request_ihex_firmware一起获取,因为他们认为在内核中读取文本文件是愚蠢(这会减慢事情)。
#3
On current Linux systems, this is handled via udev
and the firmware.agent
.
在当前的Linux系统上,这是通过udev和firmware.agent处理的。
#4
Linux 3.5.7 Gentoo, I have the same issue. SOLVED:
Linux 3.5.7 Gentoo,我有同样的问题。解决了:
emerge ipw2200-firmware
Then go to /usr/src/linux
然后转到/ usr / src / linux
make menucofig
on device driver, remove all wirless drivers don't needed, set Intell 2200 as module and recompile.
在设备驱动程序上,删除不需要的所有无线驱动程序,将Intell 2200设置为模块并重新编译。
make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault