核心模組是Linux核心向外部提供的一個插口,其全稱為動態可載入核心模組(Loadable Kernel Module,LKM),我們簡稱為模組。Linux核心之所以提供模組機制,是因為它本身是一個單核心(monolithic kernel)。單核心的最大優點是效率高,因為所有的內容都整合在一起,但其缺點是可擴充性和可維護性相對較差,模組機制就是為了彌補這一缺陷。
一、 什麼是模組
模組是具有獨立功能的程式,它可以被單獨編譯,但不能獨立運行。它在運行時被連結到核心作為核心的一部分在核心空間運行,這與運行在使用者空間的進程是不同的。模組通常由一組函數和資料結構組成,用來實現一種檔案系統、一個驅動程式或其他核心上層的功能。
應用程式與核心模組的比較
為了加深對核心模組的瞭解,表一給出應用程式與核心模組程式的比較。
表一 應用程式與核心模組程式的比較
從表一我們可以看出,核心模組程式不能調用libc庫中的函數,它運行在核心空間,且只有超級使用者可以對其運行。另外,模組程式必須通過module_init()和module_exit()函數來告訴核心“我來了”和“我走了”。
二、 編寫一個簡單的模組
模組和核心都在核心空間運行,模組編程在一定意義上說就是核心編程。因為核心版本的每次變化,其中的某些函數名也會相應地發生變化,因此模組編程與核心版本密切相關。以下例子針對Ubuntu 11.04 核心2.6.37.2
1.hello.c
#include "linux/init.h"<br />#include "linux/kernel.h"<br />#include "linux/module.h"</p><p>MODULE_LICENSE("GPL");</p><p>static int __init hello_init(void) {<br /> printk(KERN_ALERT "Hello world!/n");<br /> return 0;<br />}</p><p>static void __exit hello_exit(void) {<br /> printk(KERN_ALERT "Goodbye!/n");<br />}</p><p>module_init(hello_init);<br />module_exit(hello_exit);<br />MODULE_AUTHOR("gengjia");<br />MODULE_DESCRIPTION("hello");
說明
hello.c檔案可以放在任意檔案夾之下。
所有模組都要使用標頭檔module.h,此檔案必須包含進來。
標頭檔kernel.h包含了常用的核心功能。
標頭檔init.h包含了宏_init和_exit,它們允許釋放核心佔用的記憶體。
hello_init是模組的初始化函數,它必需包含諸如要編譯的代碼、初始化資料結構等內容。
使用了printk()函數,該函數是由核心定義的,功能與C庫中的printf()類似,它把要列印的資訊輸出到終端或系統日誌。
hello_exit是模組的退出和清理函數。此處可以做所有終止該驅動程式時相關的清理工作。
module_init()和module_exit()是模組編程中最基本也是必須的兩個函數。
module_init()是驅動程式初始化的進入點。而module_exit()登出由模組提供的所有功能。
2、Makefile
obj-m:=hello.o<br />KERNELBUILD :=/lib/modules/$(shell uname -r)/build<br />default:<br /> make -C $(KERNELBUILD) M=$(shell pwd) modules<br /> echo insmod ./hello.ko to turn it on<br />clean:<br /> rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
(注意makefile裡面要求的tab)
Makefile檔案與hello.c檔案放在同一個目錄。
KERNELBUILD :=/lib/modules/$(shell uname -r)/build是編譯核心模組需要的Makefile的路徑,我的Ubuntu下是
/lib/modules/2.6.37.2/build
make -C $(KERNELBUILD) M=$(shell pwd) modules 編譯核心模組。-C 將工作目錄轉到KERNELBUILD,調用該目錄下的Makefile,並向這個Makefile傳遞參數M的值是$(shell pwd) modules。
3. 編譯模組
#sudo make (調用第一個命令default)
這時,在hello.c 所在檔案夾就會有 hello.ko ,這個就是我們需要的核心模組啦。
#sudo make clean
清理編譯垃圾,hello.ko 也會清理掉。
4. 插入模組,讓其工作。注意必須是root許可權
#sudo insmod ./hello.ko 我們用dmesg就可以看到產生的核心資訊啦,Hello world!
如果沒有輸出"Hello world!",因為如果你在字元終端而不是終端模擬器下啟動並執行話,就會輸出,因為在終端模擬器下時會把核心訊息輸出到記錄檔/var/log/kern.log中。
#sudo rmmod ./hello.ko 再用dmesg可以看到Goodbye!
modutils是管理核心模組的一個軟體包。可以在任何獲得核心原始碼的地方擷取Modutils(modutils-x.y.z.tar.gz)原始碼,然後選擇最進階別的patch.x.y.z等於或小於當前的核心版本,安裝後在/sbin目錄下就會有insomod、rmmod、ksyms、lsmod、modprobe等公用程式。當然,通常我們在載入Linux核心時,modutils已經被載入。
1.insmod命令
調用insmod程式把需要插入的模組以目標代碼的形式插入到核心中。在插入的時候,insmod自動調用module_init()函數運行。注意,只有超級使用者才能使用這個命令,其命令格式為:#insmod [path] modulename.ko
2.rmmod命令
調用rmmod程式將已經插入核心的模組從核心中移出,rmmod會自動運行module_exit()函數,其命令格式為:#rmmod [path] modulename.ko
3.lsmod命令
調用lsmod程式將顯示當前系統中正在使用的模組資訊。實際上這個程式的功能就是讀取/proc檔案系統中的檔案/proc/modules中的資訊,其命令格式為:#lsmod
以上就是在2.6.xx下一個最簡單的模組編寫過程。
本文轉載自:
http://www.xker.com/page/e2011/0214/100154_1.html
並對其做了一些修改。