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 修改後的結果,結論就是,這個設計真醜;

發佈了249 篇原創文章 · 獲贊 9 · 訪問量 107萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章