<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:宋体; mso-ascii-font-family:"Times New Roman"; mso-hansi-font-family:"Times New Roman"; mso-bidi-font-family:"Times New Roman"; mso-font-kerning:1.0pt;} h1 {mso-style-next:正文; margin-top:17.0pt; margin-right:0cm; margin-bottom:16.5pt; margin-left:0cm; text-align:justify; text-justify:inter-ideograph; line-height:240%; mso-pagination:lines-together; page-break-after:avoid; mso-outline-level:1; font-size:22.0pt; font-family:宋体; mso-ascii-font-family:"Times New Roman"; mso-hansi-font-family:"Times New Roman"; mso-font-kerning:22.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:646590179; mso-list-type:hybrid; mso-list-template-ids:-2137858994 518141964 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l0:level1 {mso-level-text:%1,; mso-level-tab-stop:39.0pt; mso-level-number-position:left; margin-left:39.0pt; text-indent:-18.0pt;} @list l1 {mso-list-id:801383517; mso-list-type:hybrid; mso-list-template-ids:-239169902 596443084 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l1:level1 {mso-level-text:%1,; mso-level-tab-stop:39.0pt; mso-level-number-position:left; margin-left:39.0pt; text-indent:-18.0pt;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} -->

Firmware 加载原理分析

前言

前段时间移植 wifi 驱动到 android 的内核上,发现 firmware 的加载始终出错,问了几个人,都不是很了解,没办法,只好自己研究一下。

原理分析

从本质上来说, firmware 需要做的事情包括两件:

1, 通知用户态程序,我需要下载 firmware 了;

2, 用户态程序把用户态的数据 copy 到内核层;

3, 内核把内核态的数据写到设备上,比如 wifi 模块里;

其中第三步应该不难,关键是看看, linux 里面是如何实现第一、二步的;

实现机制

简单的说,它的机制分成以下几部分:

1, 通过一定的方式,通知用户态程序,比如 init 程序,如图所示:

显然是通过 kobject_uevent 的方式通知的应用层,它的机制我有空再详细解释,简单的说,就是往一个 socket 广播一个消息,只需要在应用层打开 socket 监听 NETLINK_KOBJECT_UEVENT 组的消息,就可以收到了。

用户态的 init 是如何做的?

可以看到 init 程序打开了一个 socket ,然后绑定它,最后通过 select 来监听 socket 上来的数据,最后调用 handle_device_fd 来处理收到的消息;当内核发送一个 KOBJ_ADD 的消息上来的时候,经过过滤,判断是否是 firmware 要被加载的消息,然后调用

handle_firmware_event 来处理;

2, 用户态的数据如何下载到内核;

本质上它是内核创建了两个文件,一个文件 A 用来标志下载的开始和结束,另外一个文件 B 用来接收用户层传下来的数据,当用户态的程序往 A 文件写入 1 的时候,标志用户态程序已经往里面写程序来,而往里面写入 0 的时候,就标志下载成功结束,如果写入 -1 就表示下载失败了;下面看看这两个文件是如何被创建的 , 以及数据是如何写到内核的,请看图:

这个图基本上就是两个文件被创立的过程,以及当这两个文件被用户态程序访问的时候将要被调用的函数,比如对于标志文件,如果往里面写入数据,将会触发函数 firmware_loading_store 函数,如果往 bin 文件里面写入数据将会触发 bin 文件类型的 write 函数;

用户态写数据的过程大约是这样的:当用户态收到 KOBJ_ADD 消息的时候最终将会调用 handle_firmware_event 的函数;

它的过程就是:

a, 先往标志文件里面写 1

b, 从用户空间读取数据;

c, 往内核创建的文件里面写数据;

d, 如果成功写入 0 ,否则写入 -1

下面看看内核是如何接受这些文件的,前面提到内核创建了一个 bin 文件,用来接收用户态的数据,下面看看这个过程:

对于 SYSFS_KOBJ_BIN_ATTR 属性的文件,在 inode 初始化的时候,将会被赋予 bin_fops 的文件操作函数集,于是当上层调用 write 的时候,将会走到内核的 bin_fops.write 函数;这个函数干的事情很简单,就是把用户态的数据 copyright bb->buffer ,而 bb->buffer 其实是在 open 的时候分配的空间,这样的话,就实现了用户态的数据到内核的 copy ;过程是不是完了?

还有一个步骤,这个 bb->buffer 本身是如何与 wifi 驱动交互的呢?这只是一个中间层,它的数据必须要写到 wifi 的驱动才应该算完整,而这一步其实就是通过 flush_write 来完成的,下面看看这个过程:

这里可以清楚的看到, flush_write 做的事情就是把 bb->buffer 的内容 copy wifi driver 分配的空间 fw->data 里面去了,至此,用户态的数据已经完整的写到了 wifi driver 空间了;

3, 内核态的数据到 wifi 模块

这个就比较简单了,通过函数 sdio_writesb 利用 sdio 总线把数据写到模块里面去了;

总结

Firmware 的加载主要是利用了 uevent 的通讯机制实现用户态和内核态的交互,另外还涉及了 sys 文件系统里的文件创建 , 我加载 wifi firmware 始终出错的原因是 android 的文件系统要求把 wifi firmware helper 放到 /etc/firmware 里面,而把真正的 firmware sd8686.bin 放到 /etc/firmware/mrvl 里面,估计是 marvel 修改后的结果,结论就是,这个设计真丑;

备注

作者 :wylhistory;

联系方式 :wylhistory@gmail.com

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. adb pull命令复制android数据库文件.db到电脑
  4. Android(安卓)之最新最全的Intent传递数据方法
  5. android 多线程断点续传下载 二
  6. Android腾讯微薄客户端开发九:博主详情界面篇(广播,听众,收听)
  7. 将LED驱动增加进内核的方法(Android_OK6410)
  8. Android(安卓)sharedpreferences轻量级存储
  9. Android中保存Activity的状态

随机推荐

  1. “Google 救不了 Android”
  2. ExpandableListView用法和实例
  3. Android开发者必备的42个链接
  4. HAXM is not working and emulator runs
  5. Android应用层View绘制流程与源码分析
  6. Android(安卓)客服端集成高德定位功能(And
  7. android开发-使用Dialog AlertDialog
  8. Android应用程序包解析过程浅析
  9. Android(安卓)WebView的缓存
  10. Android(安卓)Launcher分析和修改2——Ic