本系列參考陳學松的《深入Linux設備驅動程序內核機制》
Linux內核模塊形式上以.ko文件存在,概念上類似於Windows的動態鏈接庫dll,內核模塊可以在系統運行期間動態擴展系統功能而無須重新編譯一個新的內核鏡像並重啓系統,這一特性爲內核開發者提供了極大的便利。
1. 內核模塊的動態編譯和靜態編譯
首先得了解兩者的區別,靜態編譯模塊直接進內核鏡像,動態編譯模塊生成.ko文件。本文主要討論模塊的動態加載。
參考一個簡單的實例 http://www.linuxidc.com/Linux/2011-09/42068.htm
2 內核模塊.ko的文件格式ELF
用命令file查看,ko文件,顯示 ELF 32-bit LSB relocatable ... ...
Linux下常見的可執行文件都是以ELF的形式存在。
section是ELF的主體,位於文件視圖中間部分的一個連續區域,模塊被加載時,被分配到一塊內存區域。
3 內存視圖 (HDR視圖)
用戶空間程序insmod首先通過文件系統接口讀取內存模塊的文件數據,放在一塊用戶空間的存儲區域,然後通過系統調用sys_init_module和裏面的load_module,後者將vmalloc分配一塊內存空間,copy_from_user複製數據,在內核空間構造出ELF的內存視圖。
之後,內存視圖留下CORE section部分搬移到一個最終的內存地址,這部分數據是模塊在系統中整個存活期會使用到的數據。
4 INIT和CORE
根據ELF spec,標記有SHF_ALLOC的section表示在模塊的運行過程中,需要佔用內存空間,其分爲兩大類,INIT和CORE,INIT section所在的內存區域會被最終釋放,CORE section中的數據將一直駐留在內存中。
5 模塊的“未解決的引用” (unsolved symbol)
內核模塊ELF中的“未解決的引用”符號,是指當模塊的編譯工具鏈對模塊進行鏈接生成.ko文件時,對於模塊中調用的一些函數,鏈接工具無法在該模塊的所有目標文件中找到這個函數的具體指令碼,只能暫時對這個函數標記爲“未解決的引用”,對它的處理將一直延續到內核模塊被加載時從內核或者其他模塊找到這個函數。
6 模塊導出符號 (EXPORT_SYMBOL)
模塊不僅使用內核和其他模塊導出的符號,而且向外部導出自己的符號供內核使用。
7. 模塊的參數
可以向內核模塊傳遞一些參數,比如 # insmod devdemo.ko dolphin=10 bobcat=5
驅動程序裏應聲明模塊參數如下,
/* devdemo.c */
#include <linux/module.h>
#include <linux/kernel.h>
int dolphin;
int bobcat;
module_param(dolphin, int, 0);
module_param(bobcat, int, 0);
8. 模塊的版本控制
內核和模塊之間協商出一種機制確保不同版本的模塊中的接口可以使用,Linux對此的解決方案是使用接口的校驗和,也叫CRC校驗碼。基本思想就是根據函數的參數生成一個大小爲4個字節的CRC校驗碼,當雙方的校驗碼相等時視爲相同接口,否則爲不同接口。內核通過CONFIG_MODVERSIONS啓用版本控制特性。模塊源碼所在目錄下的.mod.c文件記錄了內核導出的函數接口和其對應的CRC校驗碼。