Scope
Linux 内核提供了一个函数 request_firmware() 来加载固件二进制文件以配置和启用设备。所以在这里我们进一步挖掘它。
Usage of “request_firmware()”
request_firmware() 的声明:
int request_firmware( const struct firmware **firmware_p, const char *name,
struct device *device )
// @firmware_p : pointer to firmware pointer
// @name : name of firmware file
// @device : device for which firmware is loaded
kernel release 里的api:
void release_firmware(struct firmware *firmware)
在内核中调用“request_firmware()”加载固件的示例:
int ret;
ret = request_firmware(&fw, "abc.bin", dev);
if(ret < 0)
pr_err("failed to load firmware\n");
else
update_device_firmware(); // config or enable device with this firmware
Basic work flow of “request_firmware()”
request_firmware()
|
| Y
firmware built in kernel image? --------------- load from kernel image ----------------
| |
| N |
| Y |
load directly from fs ? ----------- directly load from "path"------------ |
| | |
| N | |
| | |
load with file node "/sys/class/firmware/xx.bin/" | |
| | |
| | |
exit exit
Load firmware from kernel image
Linux 内核提供了将固件构建到内核映像中的方法。但是请注意,因为很多固件内容是非 GPL 的,这会弄脏内核。因此,如果没有必要,请不要将固件构建到内核映像中。
启用 CONFIG_FIRMWARE_IN_KERNEL、CONFIG_EXTRA_FIRMWARE_DIR 和 CONFIG_EXTRA_FIRMWARE 将固件构建到内核映像中:
CONFIG_FIRMWARE_IN_KERNEL=y
CONFIG_EXTRA_FIRMWARE_DIR="firmware" // 这意味着 $(source_dir)/firmware
CONFIG_EXTRA_FIRMWARE="fw_sst_0f28.bin"
如果需要多个固件,请将它们添加为:
CONFIG_EXTRA_FIRMWARE="fw_sst_0f28.bin abc.bin efg.bin"
Mechanism of firmware builtin
当运行命令make bzImage时,firmware下的Makefile会生成一个汇编文件fw_sst_0f28.bin.gen.S:
.section .rodata
_fw_bin:
.incbin "/home/caoxin/linux3.8/firmware/fw_sst_0f28.bin"
.section .rodata.str
_fw_bin_name:
.string "fw_sst_0f28.bin"
.section .builtin_fw
.long _fw_bin_name
.long _fw_bin
.long _fw_end - _fw_bin
该程序集文件包含三个部分:.rodata、rodata.str和.builtin_fw。
.rodata节将固件数据保存在fw_sst_0f28.bin中- section
.rodata.str保存文件名fw_sst_0f28.bin - section
.builtin_fw保存固件名称的地址和固件数据的地址
link script vmlinux.lds 涉及以下部分:
.builtin_fw : {
__start_builtin_fw = 。
*(.builtin_fw)
__end_builtin_fw = 。
}
GNU 链接器将所有目标文件中的此部分定位到内核映像的.builtin_fw部分中。 内核映像在内存中运行后,__start_builtin_fw和__end_builtin_fw是本节的开始和结束地址。
当内核调用request_firmware()时,将检查.builtin_fw部分中的固件名称是否与传入的固件名称匹配。如果匹配,内核将固件数据复制到缓冲区并且request_firmware()成功返回。
Load one target firmware from fs(file system) directly
内核使用以下路径中的固件名称搜索固件:
- fw_path_para(kernel command line 定义的
firmware_class.path = xxx) /lib/firmware/updates UTS_RELEASE,/lib/firmware/updates,/lib/firmware UTS_RELEASE,/lib/firmware,
注意:
- UTS_RELEASE 是 kernel release 版本号 , 例如
3.8.10-07312013 - 搜索优先级从1 到 5.
如果找到目标固件文件,内核会增加一个缓冲区来保存二进制文件,并且request_firmware()会成功返回。
Load firmware in userspace
内核在“/sys/class/firmware/”下创建一个目录。 例如,/sys/class/firmware/fw_sst_0f28.bin/{loading, data}。
在用户空间加载固件的步骤:
1). echo 1 > /sys/class/firmware/fw_sst_0f28.bin/loading
2). cat appropriate_firmware_image > /sys/class/firmware/fw_sst_0f28.bin/data
3). echo 0 > /sys/class/firmware/fw_sst_0f28.bin/loading
当二进制文件进入时,内核会增长一个缓冲区来保存二进制文件,并且request_firmware()会成功返回。
Reference
- kernel/Documentation/firmware_class/README
- 《Using ld, the GNU linker》 by Jeffrey, Osier
本文详细介绍了Linux内核如何通过request_firmware()函数加载固件,包括从内核映像、文件系统直接加载以及用户空间加载的流程。讲解了内核配置、固件内置机制、搜索路径以及用户空间交互方式。同时提到了固件加载的优先级和不同加载方法的适用场景。
8474

被折叠的 条评论
为什么被折叠?



