1、常用的模塊操作命令
(1)lsmod(list module,將模塊列表顯示),功能是打印出當前內核中已經安裝的模塊列表
(2)insmod(install module,安裝模塊),功能是向當前內核中去安裝一個模塊,用法是insmod xxx.ko
(3)modinfo(module information,模塊信息),功能是打印出一個內核模塊的自帶信息。,用法是modinfo xxx.ko,注意要加.ko,也就是說是一個靜態的文件形式。
(4)rmmod(remove module,卸載模塊),功能是從當前內核中卸載一個已經安裝了的模塊,用法是rmmod xxx.ko rmmod xxx都可以
(5)剩下的后面再說,暫時用不到(如modprobe、depmod等)
2、模塊的安裝
(1)insmod與module_init宏。模塊源代碼中用module_init宏聲明了一個函數(在我們這個例子里是chrdev_init函數),作用就是指定chrdev_init這個函數和insmod命令綁定
起來,也就是說當我們insmod module_test.ko時,insmod命令內部實際執行的操作就是幫我們調用chrdev_init函數。
(3)模塊安裝時insmod內部除了幫我們調用module_init宏所聲明的函數外,實際還做了一些別的事(譬如lsmod能看到多了一個模塊也是insmod幫我們在內部做了記錄,也就是
將我們的模塊加入到內核的一個數據結構中去),但是我們就不用管了。
3、模塊的卸載
(1)module_exit和rmmod的對應關系
當我們執行rmmod命令的時候,就會執行模塊的module_exit宏聲明的函數,同樣也會將我們這個模塊信息從我們內核的模塊管理的數據結構中將其刪除。
4、模塊的版本信息
(1)使用modinfo查看模塊的版本信息
(2)內核zImage中也有一個確定的版本信息
(3)insmod時模塊的vermagic必須和內核的相同,否則不能安裝,報錯信息為:insmod: ERROR: could not insert module module_test.ko: Invalid module format
(4)模塊的版本信息是為了保證模塊和內核的兼容性,是一種安全措施
(5)如何保證模塊的vermagic和內核的vermagic一致?編譯模塊的內核源碼樹就是我們編譯正在運行的這個內核的那個內核源碼樹即可。說白了就是模塊和內核要同出一門。
5、模塊中常用宏
(1)MODULE_LICENSE("GPL"),模塊的許可證。一般聲明為GPL許可證,而且最好不要少,否則可能會出現莫名其妙的錯誤(譬如一些明顯存在的函數提升找不到)。
(2)MODULE_AUTHOR("tao Deng <> 773904075@qq.com"),用來添加模塊的作者信息
(3)MODULE_DESCRIPTION("xxx"),用來添加模塊的描述信息
(4)MODULE_ALIAS("xxxx"),用來添加模塊的別名
以上的這些東西,我們通過modinfo命令查看模塊的時候是可以看到的
6、函數修飾符
(1)__init,本質上是個宏定義,在內核源代碼中就有#define __init xxxx。這個__init的作用就是將被他修飾的函數放入.init.text段中去(本來默認情況下函數是被
放入.text段中)。 實質就是在C高級中講到的attribute的用法。
整個內核中的所有的這類函數都會被鏈接器鏈接放入.init.text段中,所以所有的內核模塊的__init修飾的函數其實是被統一放在一起的。內核啟動時統一會加載.init.text
段中的這些模塊安裝函數,加載完后就會把這個段給釋放掉以節省內存。
(2)__exit
7、printk函數詳解
(1)printk在內核源碼中用來打印信息的函數,用法和printf非常相似。
(2)printk和printf最大的差別:printf是C庫函數,是在應用層編程中使用的,不能在linux內核源代碼中使用;printk是linux內核源代碼中自己封裝出來的一個打印函數,
是內核源碼中的一個普通函數,只能在內核源碼范圍內使用,不能在應用編程中使用。
(3)printk相比printf來說還多了個:打印級別的設置。printk的打印級別是用來控制printk打印的這條信息是否在終端上顯示的。應用程序中的調試信息要么全部打開要么
全部關閉,一般用條件編譯來實現(DEBUG宏),但是在內核中,因為內核非常龐大,打印信息非常多,有時候整體調試內核時打印信息要么太多找不到想要的要么一個沒有沒
法調試。所以才有了打印級別這個概念。
(4)操作系統的命令行中也有一個打印信息級別屬性,值為0-7。當前操作系統中執行printk的時候會去對比printk中的打印級別和我的命令行中設置的打印級別,小於我的
命令行設置級別的信息會被放行打印出來,大於的就被攔截的。譬如我的ubuntu中的打印級別默認是4,那么printk中設置的級別比4小的就能打印出來,比4大的就不能打印出來。
可以通過這個命令查看 : cat /proc/sys/kernel/printk
(5)ubuntu中這個printk的打印級別控制沒法實踐,ubuntu中不管你把級別怎么設置都不能直接打印出來,必須dmesg命令去查看。
8、關於驅動模塊中的頭文件
(1)驅動源代碼中包含的頭文件和原來應用編程程序中包含的頭文件不是一回事。應用編程中包含的頭文件是應用層的頭文件,是應用程序的編譯器帶來的(譬如gcc的頭文件路
徑在 /usr/include下,這些東西是和操作系統無關的)。驅動源碼屬於內核源碼的一部分,驅動源碼中的頭文件其實就是內核源代碼目錄下的include目錄下的頭文件。
9、用開發板來調試模塊
(1)設置bootcmd使開發板通過tftp下載自己建立的內核源碼樹編譯得到的zImage: set bootcmd 'tftp 0x30008000 zImage;bootm 0x30008000'
(2)設置bootargs使開發板從nfs去掛載rootfs(內核配置時需要使其支持掛載NFS文件系統,這個在uboot中已經說過)
setenv bootargs root=/dev/nfs nfsroot=192.168.1.141:/root/porting_x210/rootfs/rootfs ip=192.168.1.10:192.168.1.141:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc console=ttySAC2,115200
(3)修改Makefile中的KERN_DIR使其指向自己建立的內核源碼樹
(4)將自己編譯好的驅動.ko文件放入nfs共享目錄下去
(5)開發板啟動后使用insmod、rmmod、lsmod等去進行模塊實驗
參考: 《朱友鵬嵌入式Linux開發\5.Linux驅動開發\5.2.字符設備驅動基礎》