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: vinvia2008@163.com
* 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: vinvia2008@163.com
* 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) clean5. 附录
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
3366

被折叠的 条评论
为什么被折叠?



