內核模塊是Linux內核向外部提供的一個插口,其全稱爲動態可加載內核模塊(Loadable Kernel Module,LKM),咱們簡稱爲模塊。Linux內核之因此提供模塊機制,是由於它自己是一個單內核(monolithic kernel)。單內核的最大優勢是效率高,由於全部的內容都集成在一塊兒,但其缺點是可擴展性和可維護性相對較差,模塊機制就是爲了彌補這一缺陷。不少驅動程序都以模塊的形式存在,用戶能夠有選擇的加載須要的驅動程序。html
1、 什麼是模塊linux
模塊是具備獨立功能的程序,它能夠被單獨編譯,但不能獨立運行。它在運行時被連接到內核做爲內核的一部分在內核空間運行,這與運行在用戶空間的進程是不一樣的。模塊一般由一組函數和數據結構組成,用來實現一種文件系統、一個驅動程序或其餘內核上層的功能。shell
2、 編寫一個簡單的模塊編程
模塊和內核都在內核空間運行,模塊編程在必定意義上說就是內核編程。由於內核版本的每次變化,其中的某些函數名也會相應地發生變化,所以模塊編程與內核版本密切相關。如下例子針對2.6內核:數據結構
tasklet.c文件函數
1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/kernel.h> 4 #include <linux/interrupt.h> 5 6 static struct tasklet_struct my_tasklet; 7 8 static void tasklet_handler (unsigned long data) 9 { 10 printk(KERN_ALERT "tasklet_handler is running.\n"); 11 } 12 13 static int __init test_init(void) 14 { 15 tasklet_init(&my_tasklet, tasklet_handler, 0); 16 tasklet_schedule(&my_tasklet); 17 return 0; 18 } 19 20 static void __exit test_exit(void) 21 { 22 tasklet_kill(&my_tasklet); 23 printk(KERN_ALERT "test_exit running.\n"); 24 } 25 MODULE_LICENSE("GPL"); 26 27 module_init(test_init); 28 module_exit(test_exit);
1.頭文件說明:全部模塊都要使用頭文件module.h,此文件必須包含進來;頭文件kernel.h包含了經常使用的內核函數;頭文件init.h包含了宏_init和_exit,它們容許釋放內核佔用的內存。interrupt.h文件時編寫tasklet(關於tasklet的說明能夠參考linux中斷與異常)必需要用的頭文件。spa
2.test_init是模塊的初始化函數,它必需包含諸如要編譯的代碼、初始化數據結構等內容,其中的tasklet_init初始化咱們本身建立的tasklet,tasklet_schedule函數則是將咱們初始化後的tasklet掛到tasklet鏈表中,並激活軟中斷來執行咱們的tasklet。日誌
3.test_exit是模塊的退出和清理函數。此處能夠作全部終止該內核模塊時相關的清理工做。code
4.函數module_init()和module_exit()是模塊編程中最基本也是必須的兩個函數。module_init()向內核註冊模塊,並調用註冊作模塊的初始化工做的函數,而module_exit()註銷模塊並註冊模塊註銷時執行的清理函數。htm
5.第10行使用了printk()函數,該函數是由內核定義的,功能與C庫中的printf()相似,它把要打印的信息輸出到終端或系統日誌。字符串前面的KERN_ALERT是輸出的級別,表示當即在終端輸出,能夠調用dmesg命令來查看輸出。
有了上面的各個組成,一個模塊就算編寫好了。
3、 編譯模塊
編譯模塊不想編譯普通的c文件,直接敲幾個命令就能夠了,編譯模塊必須用Makefile文件,並且Makefile文件必須按必定的規則編寫,這個和平時編寫的Makefile文件不同。編寫內核模塊的Makefile文件內容幾乎相同的。下面是模版:
obj-m += tasklet.o # 產生tasklet 模塊的目標文件 CURRENT_PATH := $(shell pwd) #模塊所在的當前路徑 LINUX_KERNEL := $(shell uname -r) #Linux內核源代碼的當前版本 LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL) #Linux內核源代碼的絕對路徑 all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #編譯模塊了 clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
除了第一行要把tasklet換成編寫的目標模塊的.c文件名外,其它都是同樣的。
一切都準備好以後,直接make一下就ok了。
4、 運行模塊
運行模塊也不能像運行普通程序同樣,直接./tasklet來運行,必須經過專門的命令來運行。
使用$insmod tasklet.ko命令直接將咱們的模塊插入到內核中,模塊被插入內核時就會調用咱們註冊的初始化函數test_init,用dmesg命令查看輸出,能夠看到tasklet_handler is running.消息被打印了。
使用$lsmod命令來查看系統中的模塊:
使用$rmmod tasklet來卸載模塊,卸載模塊的同時會執行註冊函數test_exit,用dmesg能夠查看打印消息。