摘要:通過Makefile編譯得到first_drv.ko文件,這是一個可以被安裝到ubuntu中的驅動模塊,要怎樣做呢?在/work/my_drivers/first_drv/1th/目錄下執(zhí)行:insmod first_drv.ko如果你是在普通用戶狀態(tài)下執(zhí)行的這條命令,可以看到系統提醒我們:insmod: error inserting 'first_drv.ko': -1 Ope
通過Makefile編譯得到first_drv.ko文件,這是一個可以被安裝到ubuntu中的驅動模塊,要怎樣做呢?
在/work/my_drivers/first_drv/1th/目錄下執(zhí)行:insmod first_drv.ko
如果你是在普通用戶狀態(tài)下執(zhí)行的這條命令,可以看到系統提醒我們:insmod: error inserting 'first_drv.ko': -1 Operation not permitted
這是因為安裝驅動模塊需要超級權限,你可以在普通用戶狀態(tài)下執(zhí)行:sudo insmod first_drv.ko,或直接切換到root用戶,執(zhí)行insmod first_drv.ko
回車后發(fā)現什么事都沒有發(fā)生,其實在我們執(zhí)行insmod first_drv.ko的時候,就相當于調用了first_drv.c中的module_init(first_drv_init),我們在以前的博文中說過module_init( )定義了一個結構體,當我們寫成module_init(first_drv_init)時,那個結構體中就會有一個函數指針指向了first_drv_init函數,從而跳轉執(zhí)行first_drv_init函數中的內容:
static int __init first_drv_init(void) { printk(KERN_INFO"hello world!\n"); return 0; }
容易得知,該函數被調用時會打印出"hello world!",但是如果我們分析的沒錯的話,為何剛剛又沒有看到命令行中輸出"hello world!"呢?
可能有同學會想是不是打印級別的原因,于是輸入cat /proc/sys/kernel/printk,
打?。? 4 1 7
第一個果然是4,當前打印級別"KERN_INFO"為6,因此改為7,即可讓"KERN_INFO"滿足打印出"hello world!"的打印級別,但事實上,即便改成7后,我們執(zhí)行insmod first_drv.ko后依舊看不出命令行中有任何動靜。
這是為什么呢?原來,ubuntu中嚴格限制printk輸出的數據顯示在命令行中,這內部有一套機制使得我們不論如何設置打印級別,也看不到"hello world!"。
但好在我們可以通過執(zhí)行dmesg命令來查看ubuntu隱藏起來的內核打印信息:
[ 0.000000] Initializing cgroup subsys cpuset
[ 0.000000] Initializing cgroup subsys cpu
···
[ 0.000000] TSC: Frequency read from the hypervisor
[ 0.000000] Detected 2501.000 MHz processor.
[ 0.001144] Console: colour VGA+ 80x25
[ 0.001146] console [tty0] enabled
···
[ 2.665131] EXT4-fs: file extents enabled
[ 2.666123] EXT4-fs: mballoc enabled
[ 2.666135] EXT4-fs (sdb1): mounted filesystem with ordered data mode
[ 2.737083] Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
[ 2.811797] eth4: link up
[ 5.129212] svc: failed to register lockdv1 RPC service (errno 97).
[ 5.129735] NFSD: Using /var/lib/nfs/v4recovery as the NFSv4 state recovery directory
[ 5.129842] NFSD: starting 90-second grace period
[ 14.218140] eth4: no IPv6 routers present
[ 979.436592] first_drv: module license 'unspecified' taints kernel.
[ 979.436620] Disabling lock debugging due to kernel taint
[ 979.437252] hello world!
最后三行打印信息是與我們安裝first_drv.ko驅動模塊相關的,我用紅色標注了,而最后一行打印信息便是我們夢寐以求的"hello world!",這正是我們安裝驅動模塊的過程中成功調用了first_drv_init函數的鐵證。
我們的驅動模塊很簡單,除了我們手寫的"hello world!"和"goodbye world..."外再也沒有可能打印別的了,那么倒數第3行和倒數第2行是怎么回事?
這是因為在安裝驅動模塊的過程中,系統找不到驅動程序的許可證信息,還記得我們之前說first_drv.c這個驅動還有一個不足之處嗎,這就是它的不足之處,這就好像是你經營一家餐館,但是沒有衛(wèi)生許可證,就算飯菜的味道再美味,顧客用餐還是會有點憂心忡忡。
其實說白了這種衛(wèi)生許可證只是一個形式,哪家的衛(wèi)生許可證都差不多,說到底這許可證和食物是否衛(wèi)生沒有必然的聯系,關鍵還是得看做飯菜的人有沒有注意衛(wèi)生。
我們的模塊許可證也是一樣,它與我們的程序沒有半點關系,程序寫得再糟糕,只要加個模塊許可證,內核便會一聲不吭地接納你,如果你代碼寫得再規(guī)范,唯獨丟了模塊許可證,那么內核還是會嘟嚷幾句:"first_drv: module license 'unspecified' taints kernel."、"Disabling lock debugging due to kernel taint",不過驅動模塊還是能夠工作的,但為了更加符合內核的要求,我們最好還是養(yǎng)成良好的習慣,加上模塊許可證,免得出現意想不到的麻煩。
我們只需要在first_drv.c最后再加一句:MODULE_LICENSE("GPL");即可。
符合內核規(guī)范的first_drv.c如下所示:
#include <linux/module.h> #include <linux/init.h> static int __init first_drv_init(void) { printk(KERN_INFO"hello world!\n"); return 0; } static int __exit first_drv_exit(void) { printk(KERN_INFO"goodbye world...\n"); return 0; } module_init(first_drv_init); module_exit(first_drv_exit); MODULE_LICENSE("GPL");
執(zhí)行make重新編譯first_drv.c,新生成的first_drv.ko即可覆蓋舊的first_drv.ko,因此不必每次都執(zhí)行make clean刪除舊文件。
但是舊的first_drv.ko還安裝在內核上,在安裝新的first_drv.ko之前,我們如何卸載舊的first_drv.ko呢。
執(zhí)行l(wèi)smod可以查看ubuntu中已經安裝的驅動模塊,在打印出的一大頁信息的最上面可以看到:
Module Size Used by
first_drv 1020 0
binfmt_misc 8356 1
nfsd 241104 9
exportfs 4412 1 nfsd
nfs 271880 0
···
這說明first_drv驅動模塊還在內核中,我們需要使用rmmod命令來卸載它:
執(zhí)行sudo rmmod first_drv或者sudo rmmod first_drv.ko(在root用戶狀態(tài)下不需要加sudo)
回車后一樣沒有任何事情發(fā)生,執(zhí)行dmesg可以看到最后一行多了:
[ 2333.481131] goodbye world...
這正是first_drv_exit函數中打印的"goodbye world...",與講解insmod first_drv.ko是一樣的原理,執(zhí)行rmmod first_drv.ko時,就相當于去調用first_drv.c中的module_exit(first_drv_exit),然后調用first_drv_exit函數,打印出"goodbye world..."信息。
其實ubuntu每次只會對沒有許可證的驅動模塊發(fā)出一次警告打印信息,對于同一個沒有許可證的驅動,即便卸載該驅動再重裝,ubuntu也不會再打印任何警告信息,似乎有一種對該驅動“徹底失望”的意味,為了讓系統重新認識我們新的驅動程序,并確定在添加了許可證后內核不會再打印警告信息,我們可以將ubuntu重啟,重啟后,在該目錄下執(zhí)行sudo insmod first_drv.ko后,再執(zhí)行dmesg打印驅動安裝信息:
...
[ 5.714574] svc: failed to register lockdv1 RPC service (errno 97).
[ 5.715109] NFSD: Using /var/lib/nfs/v4recovery as the NFSv4 state recovery directory
[ 5.715371] NFSD: starting 90-second grace period
[ 14.690813] eth4: no IPv6 routers present
[ 89.383529] hello world!
只打印了"hello world!",可以證明添加了驅動模塊的"GPL"許可證后,ubuntu內核已經完全認可了我們的驅動模塊first_drv。