這一節主要內容講解linux核心的模組機制。主要參考經典書籍《linux device drivers》。
① 大多數小規模及中規模的應用程式從頭到尾執行單個任務,而模組卻只是預先註冊自己一邊服務於將來的某個請求,然後他的初始化函數就立即結束了。
模組僅僅被連結到核心,因此它能調用的函數僅僅是由核心匯出的那些函數,而不存在任何可連結的函數庫。所以源檔案不能包含常用的標頭檔。核心模組只能使用作為核心一部分的函數。大多數相關的標頭檔儲存在核心源碼樹的(/home/sml/linux2.6.37.4/)標頭檔聲明裡,include/linux和include/asm目錄中。
② 最簡單的模組構造(helloworld)
1. 在虛擬機器上面建立hello.c和Makefile。
2. Hello.c原始碼如下:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
static int hello_init(void)
{
printk(KERN_EMERG "hello world!\n");
return 0 ;
}
static void hello_exit(void)
{
printk(KERN_EMERG "crule world!\n");
}
module_init(hello_init);
module_exit(hello_exit);
3. makefile檔案內容
obj-m := hello.o
4. 虛擬機器上必須要有核心源碼樹,我的在/home/sml/linux2.6.37.4,因為我們構造的模組最終要啟動並執行linux2.6.37.4核心上面,所以要在核心源碼樹下面編譯模組。執行make -C/home/sml/linux2.6.37.4 M=$PWD modules.
root@sml-VirtualBox:/home/sml/nfs_server#make -C /home/sml/linux-2.6.37.4 M=$PWD modules
make:進入目錄'/home/sml/linux-2.6.37.4'
CC[M] /home/sml/nfs_server/hello.o
Buildingmodules, stage 2.
MODPOST 1modules
CC /home/sml/nfs_server/hello.mod.o
LD[M] /home/sml/nfs_server/hello.ko
make:離開目錄“/home/sml/linux-2.6.37.4”
執行完命令,產生hello.ko模組。
5. make-C /home/sml/linux2.6.37.4 M=$PWD modules解析。
前面講到,模組依賴於核心匯出的一些符號,主要的標頭檔聲明在include/linux和include/asm目錄下。所以編譯模組肯定要依賴於核心源碼樹。-C 表示make切換到指定目錄。M是makefile中的一個變數,指定為目前的目錄,也就是hello.c 的所在目錄。Modules指向obj-m變數中設定的模組,就是hello模組。因為在hello.c的Makefile中沒有指定核心源碼樹的目錄,所以-C來告訴make核心源碼樹的路徑。(這個地方理解的不是很透徹,但是我們要明白:核心模組的編譯是依賴於核心源碼樹的。)。
6. 模組的裝載和卸載
裝載命令:insmod;卸載命令:rmmod;查看模組命令:lsmod;查看模組資訊:modinfo;
我們把上面的編譯的模組放在根檔案系統上面,然後執行裝載命令,即可看到我們要列印的資訊。如何放在開發板的根檔案系統上,請參見:NFS實現開發板和虛擬機器之間的檔案分享權限設定。Make工具的使用方法請參見:MAKE工具介紹。
③ 核心符號表(模組層疊技術)
Insmod使用公用核心符號表來解析模組中未定義的符號。公用核心符號表中包含了所有的全域核心項(變數和函數)的地址,這是實現模組化驅動程式的必須的。當模組被裝入核心後,它所匯出的任何符號都會成為核心符號表的一部分。新模組可以使用有我們自己的模組匯出的符號。這樣我們可以在其他模組上層疊新的模組(模組層疊技術)。符號匯出實現模組之間的資源共用。驅動程式的模組層疊可以理解為抽象層為硬體驅動層提供符號,抽象層和硬體驅動層就相當於兩個(或多個)模組。我們可以將模組劃分為多個層,縮短開發時間。
符號匯出方法:
EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);
④ 初始化和關閉
module_init(hello_init);
module_exit(hello_exit);
初始化和關閉是強制性的,是模組被insmod和rmmod時執行的。
⑤ 模組的參數
核心允許驅動程式指定參數,而這些參數可以在裝載驅動程式模組時改變。驅動程式參數包括裝置編號,以及一些其他的控制驅動程式操作方式的參數。如:
insmod hellop howmany=10 whom=”sml”
在模組中,參數的申請方法,包含標頭檔
#include <moduleparam.h>
格式為:
Module_param(name,type,s perm);
如:
Module_param(howmany,int,S_IRUGO);
S_IRUGO表示任何人可讀取參數,但是不能更改;
S_IRUGO|S_IWUSR表示允許root使用者修改該參數。大多數情況下,我們不應該讓模組參數可寫。