当前位置:  开发笔记 > 编程语言 > 正文

Linux内核如何知道在哪里查找驱动程序固件?

如何解决《Linux内核如何知道在哪里查找驱动程序固件?》经验,为你挑选了2个好方法。

我正在Ubuntu下编译一个自定义内核,我遇到了我的内核似乎不知道在哪里寻找固件的问题.在Ubuntu 8.04下,固件与内核版本绑定的方式与驱动程序模块相同.例如,内核2.6.24-24-generic将其内核模块存储在:

/lib/modules/2.6.24-24-generic

及其固件:

/lib/firmware/2.6.24-24-generic

当我根据" 备用构建方法:老式Debian方式 " 编译2.6.24-24通用Ubuntu内核时,我得到了相应的模块目录,除了需要固件的设备外,我的所有设备都工作,例如我的英特尔无线网卡(ipw2200)模块).

内核日志显示,例如,当ipw2200尝试加载固件时,控制固件加载的内核子系统无法找到它:

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

errno-base.h将此定义为:

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

(返回ENOENT的函数在它前面放一个减号.)

我尝试在/ lib/firmware中创建一个符号链接,其中我的内核名称指向2.6.24-24-generic目录,但是这导致了同样的错误.此固件是非GPL,由Intel提供并由Ubuntu打包.我不相信它与特定内核版本有任何实际联系.cmp表明各个目录中的版本是相同的.

那么内核如何知道在哪里寻找固件呢?

更新

我找到了解决我遇到的确切问题的解决方案,但是它不再有效,因为Ubuntu已经淘汰/etc/hotplug.d并且不再存储其固件/usr/lib/hotplug/firmware.

UPDATE2

更多的研究提出了更多的答案.直到版本92 udev,该程序firmware_helper是固件加载的方式.从udev93 开始,这个程序被替换为一个名为firmware.sh的脚本,据我所知,它提供了相同的功能.这两个硬编码固件路径/lib/firmware.Ubuntu似乎仍在使用/lib/udev/firmware_helper二进制文件.

固件文件的名称将传递到firmware_helper环境变量中$FIRMWARE,该变量连接到路径/lib/firmware并用于加载固件.

加载固件的实际请求是由驱动程序(在我的情况下为ipw2200)通过系统调用完成的:

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

现在,在驱动程序调用request_firmwarefirmware_helper查看$FIRMWARE环境变量之间的某处,内核程序包名称将被添加到固件名称之前.

那么谁在做呢?



1> ephemient..:

从内核的角度来看,请参阅/ 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.

内核实际上根本不加载任何固件.它只是通知用户空间,"我想要一个名为xxx的固件",并等待用户空间将固件映像传送回内核.

现在,在Ubuntu 8.04上,

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

正如您所发现的那样,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

如果您阅读了源代码,您会发现Ubuntu编写了一个firmware_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

这正是内核期望的格式.


简而言之:Ubuntu的udev软件包具有始终/lib/firmware/$(uname -r)首先查看的自定义.此策略正在用户空间中处理.


给定的README链接指向当前的Linux行为,该行为自发布此响应以来已发生更改.现在,在查询udev之前,Linux会查看几个目录,包括`/ lib/firmware/$(uname -r)`**.另见lwn文章:[Udev和固件](https://lwn.net/Articles/518942/).

2> Andy Matteso..:

哇这是非常有用的信息,它使我在为需要固件的设备制作自定义USB内核模块时解决了我的问题.

基本上,每个Ubuntu都会带来hal,sysfs,devfs,udev等的新版本......而且事情就会发生变化.事实上我读过他们停止使用hal.

所以让我们再次对它进行逆向工程,这与最新的[Ubuntu]系统相关.

在Ubuntu Lucid(写作时最新)/lib/udev/rules.d/50-firmware.rules上使用.这个文件调用二进制文件/lib/udev/firmware,魔术发生在那里.

清单:/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}"

魔术应该是这些方面的东西(来源:Linux设备驱动程序,第3版,第14章:Linux设备模型):

回声1到 loading

将固件复制到 data

失败时,回显-1 loading并停止固件加载过程

echo 0 to loading(发信号内核)

然后,特定的内核模块接收数据并将其推送到设备

如果你看一下Lucid的udev源代码页面,udev-151/extras/firmware/firmware.c那个固件/ lib/udev/firmware二进制文件的来源,那就是正是如此.

摘录: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");

此外,许多设备使用英特尔HEX格式(包含校验和和其他东西的文本文件)(维基,我没有声誉,没有链接能力).内核程序ihex2fw(从.sEX文件中的kernel_source/lib/firmware中的Makefile调用)将这些HEX文件转换为Linux内核随后选择的任意设计的二进制格式request_ihex_firmware,因为他们认为在内核中读取文本文件是愚蠢的(它会减慢速度).

推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有