Linux內核模塊
1. Linux內核模塊的基本組成
一個基本的Linux內核模塊包含如下幾個部分:
1)模塊加載函數(一般需要)
通過insmod或modprobe命令加載內核模塊時,模塊的加載函數會自動被內核執行,完成模塊的初始化工作。
2)模塊卸載函數(一般需要)
通過rmmod命令卸載函數,模塊的卸載函數會自從被內核執行,完成模塊卸載函數的相關功能,實現模塊加載函數時申請的資源釋放等。
可能包含如下:
a. 對模塊註冊的註銷功能;
b. 對加載函數中動態申請的內存,進行釋放;
c. 釋放對硬件資源的佔用,可包含中斷、DMA通道、IO端口、IO內存等;
d. 對模塊註冊過程中開啓的硬件進行關閉。
3)模塊許可證聲明(必須)
該部分實現模塊的許可(LICENSE)權限聲明,如果不聲明LICENSE,模塊加載時,將收到模塊被污染的警告。
在Linux2.6中,可接受的許可權限有:“GPL”、“GPL v2”、 “GPL and additional rights”、"Dual BSD/GPL"、“Dual MPL/GPL”和“Proprietay”。
最常用的是:MODULE_LICENSE("Dual BSD/GPL");
4)模塊參數(可選)
模塊在加載時,可以被傳遞給其一定的參數。
a. 可以使用“module_param(參數名,參數類型,參數讀/寫權限)”爲模塊定義一個參數;
在模塊加載時使用“insmod(或modprobe) 參數名=參數值”, 如果不傳遞,則使用模塊內部的默認值。
b. 可以使用"module_param_array(數組名,數組類型,數組長度,數組讀寫全新啊)"爲模塊定義一個數組;
在模塊加載過程中可以使用“insmode(或modprobe)參數名=參數值1,參數值2”。
5)模塊導出符號(可選)
模塊可以導出符號,這樣,其它模塊可以調用該模塊導出的函數或是變量。
可以使用“EXPORT_SYMBOL(符號名);”和“EXPORT_SYMBOL_GPL(符號名);”,後者只適用於GPL許可的模塊。
6)模塊作者等信息聲明(可選)
MODULE_AUTHOR(autor);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);
2. 簡單內核模塊的示例
hello.c
/************************************************************************
* Filename: hello.c
* File Description: A simplest kernel module
* Author: Vinvian Cheng
* Emaile:
* Ver: 1.0.0
* Date: 2014.11.10
* History:
* 1.
************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
/***********************************************************************
* Function Name: hello_init
* Paramter: type name [IN]: void
* Function Descrition:
* Module init
* Return: 0
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static int hello_init(void)
{
printk(KERN_INFO " Hello World for init!\n");
return 0;
}
/***********************************************************************
* Function Name: hello_exit
* Paramter: type name [IN]: void
* Function Descrition:
* Module exit
* Return: void
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static void hello_exit(void)
{
printk(KERN_INFO " Hello World for exit\n ");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Vinvian");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");
Makefile文件
KVERS = $(shell uname -r)
#Kernel modules
obj-m += hello.o
#Specify flags for the modules compilation.
#EXTRA_CFLAGS=-g -OO
build: hello
hello:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
Makefile文件說明
1) obj-m :這個變量是指定你要聲稱哪些模塊模塊的格式爲 obj-m := <模塊名>.o
2) modules-objs :這個變量是說明聲稱模塊modules需要的目標文件 格式要求 <模塊名>-objs := <目標文件>
切記:模塊的名字不能取與目標文件相同的名字。如在這裏模塊名不能取成 mymod;
3) KDIR :這是我們正在運行的操作系統內核編譯目錄。也就是編譯模塊需要的環境
4) M= :指定我們源文件的位置
5) PWD :這是當前工作路徑$(shell )是make的一個內置函數。用來執行shell命令。
3. 完整的內核模塊的示例
calcul.c(含參數和導出符號)
/************************************************************************
* Filename: sum.c
* File Description: A complete kernel module with param and symbol
* Author: Vinvian Cheng
* Emaile: [email protected]
* Ver: 1.0.0
* Date: 2014.11.10
* History:
* 1.
************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
static int a = 0;
static int b = 0;
/***********************************************************************
* Function Name: sum
* Paramter:
* type name [IN]: a;
* type name [IN]: b;
* Function Descrition:
* sum for a and b
* Return: a+b
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
int integer_sum(int a, int b)
{
return a+b;
}
/***********************************************************************
* Function Name: dec
* Paramter:
* type name [IN]: a;
* type name [IN]: b;
* Function Descrition:
* sum for a and b
* Return: a-b
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
int integer_dec(int a, int b)
{
return a-b;
}
/***********************************************************************
* Function Name: hello_init
* Paramter: type name [IN]: void
* Function Descrition:
* Module init
* Return: 0
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static int hello_init(void)
{
printk(KERN_INFO " Sum for init!\n");
return 0;
}
/***********************************************************************
* Function Name: sum_exit
* Paramter: type name [IN]: void
* Function Descrition:
* Module exit
* Return: void
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static void hello_exit(void)
{
printk(KERN_INFO " Sum for exit\n ");
}
/*module_init*/
module_init(hello_init);
/*module_exit*/
module_exit(hello_exit);
/*module_param*/
module_param(a, int, S_IRUGO);
module_param(b, int, S_IRUGO);
/*symbol*/
EXPORT_SYMBOL(integer_sum);
EXPORT_SYMBOL(integer_dec);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Vinvian");
MODULE_DESCRIPTION("A complete Module");
MODULE_ALIAS("a complete module");
Mafefile文件同上。
4.導出符號測試模塊
calcul_test.c
/************************************************************************
* Filename: sum.c
* File Description: A complete kernel module with param and symbol
* Author: Vinvian Cheng
* Emaile: [email protected]
* Ver: 1.0.0
* Date: 2014.11.10
* History:
* 1.
************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
extern int integer_sum(int, int);
extern int integer_dec(int, int);
/***********************************************************************
* Function Name: hello_init
* Paramter: type name [IN]: void
* Function Descrition:
* Module init
* Return: 0
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static int hello_init(void)
{
printk(KERN_INFO " Sum for init!\n");
int sum = integer_sum(1, 2);
printk(KERN_INFO " Sum is %d!\n", sum);
return 0;
}
/***********************************************************************
* Function Name: sum_exit
* Paramter: type name [IN]: void
* Function Descrition:
* Module exit
* Return: void
* Error:
* Author: Vinvian 2014/11/10
***********************************************************************/
static void hello_exit(void)
{
printk(KERN_INFO " Sum for exit\n ");
}
/*module_init*/
module_init(hello_init);
/*module_exit*/
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Vinvian");
MODULE_DESCRIPTION("A complete Module");
MODULE_ALIAS("a complete module");
Makefile文件KVERS = $(shell uname -r)
#Kernel modules
obj-m += calcul_test.o
#Specify flags for the modules compilation.
#EXTRA_CFLAGS=-g -OO
build: calcul_test
calcul_test:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
5. 附錄
1)可以通過tail命令查看內核模塊在加載過程中的輸出信息,如: tail -n 3 /var/log/meassage;
2) insmod模塊加載命令;modprobe模塊加載命令,同時會加載模塊所依賴的其它模塊;lsmod模塊列舉命令;modinfo列舉模塊的相關信息;depmod分析模塊的依懶性,並 生產modules.dep文件。
3)符號查詢命令:cat /proc/kallsysm;
6. 後續學習
1) Makefile文件編寫的深化學習。
參考文獻:
1) Linux驅動開發詳解 宋寶華著
2)http://hi.baidu.com/20065562/item/15dcc4ce92c3d510b67a24af