[Linux]用request_firmware()加载firmware

本文详细介绍了Linux内核如何通过request_firmware()函数加载固件,包括从内核映像、文件系统直接加载以及用户空间加载的流程。讲解了内核配置、固件内置机制、搜索路径以及用户空间交互方式。同时提到了固件加载的优先级和不同加载方法的适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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_KERNELCONFIG_EXTRA_FIRMWARE_DIRCONFIG_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

该程序集文件包含三个部分:.rodatarodata.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

内核使用以下路径中的固件名称搜索固件:

  1. fw_path_para(kernel command line 定义的 firmware_class.path = xxx)
  2. /lib/firmware/updates UTS_RELEASE,
  3. /lib/firmware/updates,
  4. /lib/firmware UTS_RELEASE,
  5. /lib/firmware,

注意:

  1. UTS_RELEASE 是 kernel release 版本号 , 例如 3.8.10-07312013
  2. 搜索优先级从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
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山猫Show

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值