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:             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) 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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值