Linux內核模塊

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章