Linux固件加载过程简析

您所在的位置:网站首页 加载固件失败 Linux固件加载过程简析

Linux固件加载过程简析

2023-12-16 21:49| 来源: 网络整理| 查看: 265

Linux内核模块使用固件程序时,正确的做法是使用request_firmware_nowait()一类固件接口来获取固件数据。

在使用firmware前,必须对内核做如下配置。

Device Drivers —> Generic Driver Options —> Userspace firmware loading support

否则会出现: Unknown symbol release_firmware 和: Unknown symbol request_firmware 的错误。

下面是request_firmware_nowait函数的原型

int request_firmware_nowait( struct module *module, bool uevent, const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context))

如果一切正常,request_firmware_nowait 开始固件加载过程并返回0。随后会调用驱动程序的回调函数cont并将保存有firmware的fw作为函数cont的参数。 如果找不到对应位置的文件,过了一段时间后(默认60秒),将用fw=NULL作为参数调用cont。

其中struct firmware定义如下:

struct firmware { size_t size; u8 *data; };

这个结构包含实际的固件,它现在可被下载到设备中。但是请注意:在发送它到硬件之前,必须检查这个文件以确保它是正确的固件映象(设备固件常常包含标识字符串、校验和等等)

跟踪request_firmware_nowait的实现过程:

request_firmware_nowait _request_firmware_nowait request_firmware_work_func _request_firmware(desc); desc->cont(fw, desc->context);//调用传入的回调函数 static int _request_firmware(struct fw_desc *desc) { // 为固件分配内存,拷贝固件名到firmware->priv->fw_id ret = _request_firmware_prepare(&fw, desc); // 返回骨架加载超时时间,默认是60s timeout = firmware_loading_timeout(); timeout = usermodehelper_read_lock_wait(timeout); // 从文件系统读固件数据 ret = fw_get_filesystem_firmware(desc->device, fw->priv, desc->dest_addr, desc->dest_size); usermodehelper_read_unlock(); if (ret < 0) { release_firmware(fw); fw = NULL; } *desc->firmware_p = fw; }

我们首先关注fw_get_filesystem_firmware函数,这个函数从文件系统指定路径读取固件数据。

static int fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf, phys_addr_t dest_addr, size_t dest_size) { for (i = 0; i < ARRAY_SIZE(fw_path); i++) { struct file *file; /* skip the unset customized path */ if (!fw_path[i][0]) continue; // 获得固件在文件系统的路径 snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); // open文件 file = filp_open(path, O_RDONLY, 0); rc = fw_read_file_contents(file, buf); fput(file); } }

fw_get_filesystem_firmware从文件系统文件中读取到固件信息保存到内核的firmware_buf变量中,最后将数据传递给最开始的回调函数,给对应的模块使用。

fw_path是内核模块中指定的固件位置,我们可以增加自己的文件目录到该数组中,使内核可以找到更多目录下的固件。

/* direct firmware loading support */ static char fw_path_para[256]; static const char * const fw_path[] = { fw_path_para, "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, "/lib/firmware", "/firmware/image" };


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3