您的核心必須已經啟用這些選項進行了編譯:
Loadable module support ---> [*] Enable loadable module support [*] Module unloading [ ] Module versioning support (EXPERIMENTAL) [*] Automatic kernel module loading
|
如果按照第一篇教程中的說明編譯核心,那麼就已經正確地設定了這些選項。否則,修改這些選項,重新編譯核心,並引導到新核心。
一個簡單的模組骨架
首先,找到編譯當前 Linux 核心的原始碼。將目錄切換到 Linux 原始碼目錄中的 drivers/misc/。現在,拷貝下面的代碼並將其粘貼到一個名為 mymodule.c 的檔案:
#include #include #include static int __init mymodule_init(void){ printk ("My module worked!\n"); return 0;}static void __exit mymodule_exit(void){ printk ("Unloading my module.\n"); return;}module_init(mymodule_init);module_exit(mymodule_exit);MODULE_LICENSE("GPL");
|
儲存這個檔案,並在同一目錄下編輯
Makefile 檔案。添加這一行:
編譯模組:
# make -C SUBDIRS=$PWD modules
|
使用
insmod ./mymodule.ko 載入這個模組,並查看是否列印了您的訊息:
dmesg | tail。應該會在輸出的結束處看到:
現在刪除核心模組:
rmmod mymodule。再次查看 dmesg;應該會看到:
這樣您就已經編寫並運行了一個新的核心模組!恭喜!
模組/核心介面
現在,我們來做一些與您的模組有關的更有趣的事情。要瞭解的一個關鍵內容是,模組只能“看到”核心故意讓它訪問的函數和變數。首先,我們以錯誤的方式來進行嘗試。
編輯檔案 kernel/printk.c,在所有包含檔案之後其他全域變數聲明附近但要在所有函數之外)添加下面一行:
現在重新編譯核心並引導到新核心。然後,將下面的內容添加到模組的
mymodule_init 函數起始處,置於其他代碼之前。
extern int my_variable;printk ("my_variable is %d\n", my_variable);my_variable++;
|
儲存修改並重新編譯模組:
# make -C SUBDIRS=$PWD modules
|
載入模組這將失敗):
insmod ./mymodule.ko。模組的載入會失敗,並給出訊息:
insmod: error inserting './mymodule.ko': -1 Unknown symbol in module
|
這說明核心不允許模組訪問那個變數。當模組載入時,它必須解析所有外部參考,比如函數名或者變數名。如果它不能找到核心匯出的符號列表中所有未解析的名稱,那麼模組就不能寫入那個變數或者調用那個函數。在核心中某個地方有為變數
my_variable 分配的空間,但模組不知道是哪裡。
為解決此問題,我們將把 my_variable 添加到核心匯出的符號列表中。在很多核心目錄中,都有一個特定的檔案,用於匯出在那個目錄中定義的符號。再次開啟 kernel/printk.c 檔案,在變數聲明之後添加下面一行:
EXPORT_SYMBOL(my_variable);
|
重新編譯並重新引導到新核心。現在再一次嘗試載入模組:
insmod ./mymodule.ko。這一次,當查看 dmesg 時,應該看到:
my_variable is 0My module worked!
|
重新載入模組:
# rmmod mymodule && insmod ./mymodule.ko
|
現在應該看到:
Unloading my module.my_variable is 1My module worked!
|
每次重新載入那個模組,
my_variable 都會增 1。您正在讀寫一個在主核心中定義的變數。只要被
EXPORT_SYMBOL() 顯式地聲明,模組就可以訪問主核心中的任何變數。例如,函數
printk() 是在核心中定義的,並且在檔案
kernel/printk.c 中被匯出。
簡單的可引導核心模組是用來研究核心的一個有趣的途徑。例如,可以使用一個模組來開啟或關閉 printk,方法是在核心中定義一個變數 do_print它初始化為 0)。然後,讓所有 printk 都依賴於“do_print”:
if (do_print) { printk ("Big long obnoxious message\n");}
|
然後,只有當您的模組被載入時才開啟它。
模組參數
引導模組時,可以向它傳遞參數。要使用模組參數載入模組,這樣寫:
insmod module.ko [param1=value param2=value ...]
|
為了使用這些參數的值,要在模組中聲明變數來儲存它們,並在所有函數之外的某個地方使用宏
MODULE_PARM(variable, type) 和
MODULE_PARM_DESC(variable, description) 來接收它們。
type 參數應該是一個格式為
[min[-max]]{b,h,i,l,s} 字串,其中 min 和 max 是數組的長度限度。如果兩者都忽略了,則預設為 1。最後一個字元是類型說明符:
b byteh shorti intl longs string
|
可以在 MODULE_PARM_DESC 的 description 域中添加任何需要的說明符。