《Rice linux 學(xué)習(xí)開發(fā)》-linux 了解內(nèi)核模塊的原理
如果將所有的設(shè)備驅(qū)動(dòng)和內(nèi)核功能都集成在內(nèi)核中,則內(nèi)核會(huì)不斷的龐大,對(duì)我們的內(nèi)核裁剪也會(huì)帶來更大的挑戰(zhàn),為了解決這個(gè)問題,Linux內(nèi)核引入內(nèi)核模塊機(jī)制,通過動(dòng)態(tài)加載內(nèi)核模塊,從而實(shí)現(xiàn)在運(yùn)行過程中擴(kuò)展內(nèi)核的功能。
內(nèi)核模塊是什么?
1 內(nèi)核模塊是一種沒有經(jīng)過鏈接,不能獨(dú)立運(yùn)行的目標(biāo)文件,是在內(nèi)核空間中運(yùn)行的程序。經(jīng)過鏈接裝載到內(nèi)核里面成為內(nèi)核的一部分,可以訪問內(nèi)核的公用符號(hào)(函數(shù)和變量)。
2 內(nèi)核模塊可以讓操作系統(tǒng)內(nèi)核在需要時(shí)載入和執(zhí)行,在不需要時(shí)由操作系統(tǒng)卸載。它們擴(kuò)展了操作系統(tǒng)內(nèi)核的功能卻不需要重新啟動(dòng)系統(tǒng)。
3 如果沒有內(nèi)核模塊,我們不得不一次又一次重新編譯生成單內(nèi)核操作系統(tǒng)的內(nèi)核鏡像來加入新的功能。這還意味著一個(gè)臃腫的內(nèi)核。
模塊機(jī)制的優(yōu)點(diǎn):
1 減小內(nèi)核映像尺寸,增加系統(tǒng)靈活性;
2 節(jié)省開發(fā)時(shí)間;修改內(nèi)核,不必重新編譯整個(gè)內(nèi)核。
3 模塊的目標(biāo)代碼一旦被鏈入內(nèi)核,作用和靜態(tài)鏈接的內(nèi)核目標(biāo)代碼完全等價(jià)。
模塊機(jī)制的缺點(diǎn):
1 對(duì)系統(tǒng)性能有一定損失;
2 使用不當(dāng)時(shí)會(huì)導(dǎo)致系統(tǒng)崩潰;
接下來通過介紹一下內(nèi)核模塊的實(shí)現(xiàn):
首先先附上模塊的代碼(hello_world.c)
1 #include
2 #include
3 #include
4
5 static int hello_init(void)
6 {
7 printk("hello world module! ");
8 return 0;
9 }
10
11 static void hello_exit(void)
12 {
13 printk("good bye module! ");
14 }
15
16 module_init(hello_init);
17 module_exit(hello_exit);
18
19 MODULE_LICENSE("GPL");
內(nèi)核模塊至少包含兩個(gè)函數(shù):
入口函數(shù)->初始化函數(shù)(xxx_init()):模塊加載時(shí),被調(diào)用
出口函數(shù)->卸載函數(shù)(xxx_exit()):模塊卸載時(shí),被調(diào)用
模塊的入口函數(shù)名和出口函數(shù)名可以任意命名,通過宏module_init()申明入口函數(shù),通過宏module_exit()申明出口函數(shù)。模塊需要包含頭文件:#include
內(nèi)核模塊證書:2.4內(nèi)核后,引入識(shí)別代碼是否在GPL許可下發(fā)布的機(jī)制 。在使用非公開的源代碼產(chǎn)品時(shí)會(huì)得到警告。通過宏MODULE_LICENSE(“GPL”),設(shè)置模塊遵守GPL證書,取消警告信息。
內(nèi)核模塊的構(gòu)建:
管理模塊源碼方法: ① 模塊源碼加入到內(nèi)核源碼樹中。② 模塊源碼飯仔內(nèi)核源碼樹之外。
注:本文介紹的是放在內(nèi)核源碼樹外編譯。
接下來是Makefile的實(shí)現(xiàn):
首先附上Makefile的源碼
1 KERNEL_DIR = /home/FAN/linux-kernel
2
3 all:
4 make -C $(KERNEL_DIR) M=`pwd` modules
5 clean:
6 make -C $(KERNEL_DIR) M=`pwd` modules clean
7 rm -rf modules.order Module.symvers
8
9 obj-m += hello_world.o
其中:
1、KERNEL_DIR:參數(shù),賦值內(nèi)核的位置,例如我的內(nèi)核源碼的路徑:/home/fan/linux-kernrl
2、當(dāng)終端執(zhí)行make時(shí),會(huì)運(yùn)行make -C $(KERNEL_DIR) M=`pwd` modules,其中M=`pwd`指向是模塊所在的路徑。
3、當(dāng)終端執(zhí)行make clean時(shí),會(huì)運(yùn)行下面兩條命令,將編譯生成的文件刪除
make -C $(KERNEL_DIR) M=`pwd` modules clean
rm -rf modules.order Module.symvers
4、obj-m += hello_world.o:其中 –m 表示將hello_world.c編譯成模塊
–y 表示將hello_world.c編譯進(jìn)內(nèi)核鏡像中
編譯生成文件:
在終端運(yùn)行make,則會(huì)生成hello_world.ko文件.
將hello_world.ko發(fā)送到板子上,然后在板子上運(yùn)行insmod hello_world.ko, 會(huì)調(diào)用hello_init()函數(shù)運(yùn)行rmmod hello_world.ko,會(huì)調(diào)用hello_exit()函數(shù)
下圖為運(yùn)行結(jié)果: