亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区
Chinaunix
標題:
Linux模塊編程[ZT]
[打印本頁]
作者:
centipedecn
時間:
2010-01-17 09:10
標題:
Linux模塊編程[ZT]
摘要
Linux內(nèi)核模塊編程的資料有些紛繁復雜,有的過于簡單,有的過于龐雜,我試圖用筆記的形式想讀者展示怎樣來進程Linux模塊編程,力圖做到簡明扼要,這篇文章也是作為本人備忘的資料,所以有些地方過于簡略是難免的。本來這篇文章的目的就是讓用戶知其然,至于所以然還是請參考相應的資料,其實最好的資料莫過于Linux Kernel Source。
適用范圍:
Linux Kernel >= 2.6.0 [在2.4.20-8上試了哈,也行]
Linux模塊簡介
首先這個module不同于microkernel的module,microkernel的module是一個個的daemon進程,工作于用戶空間,Linux的module只是一個內(nèi)核的目標代碼,內(nèi)核通過執(zhí)行運行時的連接,來把它整合到kernel中去,所以說Linux的module機制并沒有改變Linux內(nèi)核為monolithic OS本質(zhì),其module也是工作于內(nèi)核模式,享有內(nèi)核的所有特權(quán)。
至于為什么要引入Linux Kernle Module(一下簡稱LKM),我想至少有一下幾點:
模塊化編程的需要,降低開發(fā)和維護成本。
增強系統(tǒng)的靈活性,使得修改一些內(nèi)核功能而不必重新編譯內(nèi)核和重啟系統(tǒng)。
降低內(nèi)核編程的復雜性,使入門門檻降低。
相關宏及頭文件
LKM需要包含以下頭文件:
需要定義以下宏:__KERNEL__, MODULE
一個簡單的內(nèi)核模塊示例/*file: hello.c*/
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include
#include #include //在2.4.20-8上必須要這個,原文中的內(nèi)核版本沒有試
static int __init hello_init(void)
{
printk(KERN_ALERT "Hello, my LKM.\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "Bye, my LKM.\n");
}
module_init(hello_init);
module_exit(hello_exit);
很簡答吧,不是嗎?這個LKM的功能其實也很簡單,就是當通過insmod加載它的時候,他打印Hello, my LKM.通過rmmod卸載它的時候他打印bye, my LKM.一個最基本的內(nèi)核模塊一般都包含有兩個函數(shù),一個是初始化函數(shù)(比如說這里的hello_init),一個是卸載函數(shù)(hello_exit), 當然也可以沒有任何函數(shù),只是提供一些變量。但是初始化函數(shù)和卸載函數(shù)必須成對出現(xiàn)。并且init函數(shù)當操作成功時返回值大于等于零,當操作失敗時,返回非零。宏module_init和module_exit用于注冊初始化函數(shù)和卸載函數(shù)。
LKM的編譯
一個示例的Makefile如下所示
obj-m := hello.o
KERNELBUILD := /lib/modules/`uname -r`/build
default:
make -C $(KERNELBUILD) M=$(shell pwd) modules
clean:
rm -rf *.o .*.cmd *.ko *.mod.c .tmp_versions
如果這個目錄下面還有其它模塊,只需要在hello.o后面添加就行了。
obj-m := hello.o mod.o
在模塊所在目錄執(zhí)行make,等成功后就可以得到我們想要的模塊(hello.ko)了。
如果一個模塊存在許多源文件,比如:hello, 由hello1.c hello2.c共同連接而成,需要在Makefile中加入如下行
hello-objs := hello1.o hello2.o
LKM的加載
Linux為用戶提供了modutils,用來操縱模塊。這個工具集主要包括:
insmod 安裝模塊
rmmod 刪除模塊
modprobe 比較高級的加載和刪除模塊,可以解決模塊之間的依賴性
lsmod 列出已經(jīng)加載的模塊和其信息
modinfo 用于查詢模塊的相關信息,比如作者,版權(quán)...
試著用命令insmod hello.ko加載模塊,rmmod刪除模塊,看看有什么事情發(fā)生了。你有可能看不見任何輸出,難道是有錯誤發(fā)生?No,執(zhí)行命令tail /var/log/message呵呵,是不是看到了?
Feb 19 00:07:35 gentux Hello, my LKM.
Feb 19 00:07:38 gentux Bye, my LKM.
模塊其它信息
比較常用信息常常包括:作者、描述、版權(quán)等,為此LKM為我們提供了如下宏:
MODULE_AUTHOR("author");
MODULE_DESCRIPTION("the description");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("dev"); // 設備驅(qū)動程序所支持的設備。
比較常用的Free license有"GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MPL/GPL"。
模塊參數(shù)
用戶空間的應用程序可以接受用戶的參數(shù),LKM也可以做到,只是方式有些不同而已。相關的宏有:
MODULE_PARM(var, type);
MODULE_PARM_DESC(var, "the description of the var");
模塊參數(shù)的類型(即MODULE_PARM中的type)有一下幾種:
b byte(unsigned char)
h short
i int
l long
s string(char*)
這些參數(shù)最好有默認值,如果有些必要參數(shù)用戶沒有設置可以通過在module_init指定的init函數(shù)返回負值來拒絕模塊的加載。 LKM還支持數(shù)組類型的模塊,如果在類型符號前加上數(shù)字n則表示最大程度為n的數(shù)組,用“-”隔開的數(shù)字分別代表最小和最大的數(shù)組長度。
示例:
MODULE_PARM(var, "4i"); // 最大長度為4的整形數(shù)組
MODULE_PARM(var, "2-6i"); // 最小長度為2,最大長度為6的整形數(shù)組
如何用insmod傳入?yún)?shù),其實man一下就可以了,不過現(xiàn)在的man有些過于簡單,所以在此說明一下:
insmod variable=value[,value2...] ...
其中value可以用引號括起來,也可以不用。但是有一點“=”前后不能留有空格,并且value中也不能有空格。
模塊符號的導出
和用戶空間的應用程序不同的是,引入一個模塊的目的常常是為了給內(nèi)核提供一些routine,來完成特定的功能,很少有模塊什么符號都不導出,為此Linux為用戶提供了如下宏:
EXPORT_SYMBOL(var); // 輸出symbol var
EXPORT_SYMBOL_GPL(var); // 輸出的symbol版權(quán)為GPL
模塊之間的依賴性
有的時候兩個模塊之間可能有依賴性,要加載的模塊A,依賴于模塊B,此時insmod是無能為力的,只能用modprobe來加載模塊和其依賴的模塊,否則只能手動一個個加載。
modprobe通過讀取由depmod -a生成的/lib/modules/version/modules.dep來獲得其所依賴的模塊列表(也有可能是一個模塊樹),然后調(diào)用insmod來一個個按順序加載。
命名空間的問題
對于不需要export的全局symbol最好用static進行修飾,限制其作用域為本文件,以防污染內(nèi)核的命名空間。
對于由內(nèi)核或其它模塊export的一些symbol,最好用extern進行修飾,以示其不在本文件。
在可能用到errno變量的場合,因為內(nèi)核沒有export此symbol,只能有用戶自行定義,比如:int errno;
一個較復雜的模塊示例/*file: hello.c*/
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include
#include
MODULE_AUTHOR("xiaosuo ");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("This module is a example.");
static int int_var = 0;
static const char *str_var = "default";
static int int_array[6];
MODULE_PARM(int_var, "i");
MODULE_PARM_DESC(int_var, "A integer variable");
MODULE_PARM(str_var, "s");
MODULE_PARM_DESC(str_var, "A string variable");
MODULE_PARM(int_array, "2-6i");
MODULE_PARM_DESC(int_array, "A integer array");
static int __init hello_init(void)
{
int i;
printk(KERN_ALERT "Hello, my LKM.\n");
printk(KERN_ALERT "int_var %d.\n", int_var);
printk(KERN_ALERT "str_var %s.\n", str_var);
for(i = 0; i
本文來自ChinaUnix博客,如果查看原文請點:
http://blog.chinaunix.net/u1/55468/showart_2151108.html
歡迎光臨 Chinaunix (http://www.72891.cn/)
Powered by Discuz! X3.2