- 一个Linux内核模块主要由下面几个部分组成。
- 1模块加载函数(一般需要)。
当通过insmod或modprobe命令加载内核模块时,模块的加载函数就会自动被内核执行,完成本模块的相关初始化工作。
1.2 模块卸载函数(一般需要)。
当通过rmmod命令卸载某模块时,模块的卸载函数就会自动被内核执行,完成与模块加载函数相反的功能。
1.3 模块许可声明(必须)
许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告。
在Linux 2.6内核中,可接受的LICENSE包括’GPL’, ’GPL v2’, ’GPL and additional rights’, ‘Dual BSD/GPL’, ‘Dual MPL/GPL’ 和‘Proprietary’
大多数情况下,内核模块应该遵循GPL兼容许可协议。Linux 2.6内核模块最常见的是以MODULE_LICENSE(“Dual BSD/GPL”)语句声明模块采用BSD/GPL双LICENSE。
1.4 模块参数(可选)。
模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量。
1.5 模块导出符号(可选)。
内核模块可以导出符号(symbol , 对应函数或变量),这样其他模块可以使用本模块中的变量或函数。
1.6 模块作者等信息声明。
2. 模块加载函数
Linux内核模块记载函数一般以__init标志声明,典型的模块加载函数如:
static int __init initialization_function(void)
{
/*init code*/
}
module_init(initialization_function);
模块加载函数必须以”module_init(函数名)”的形式被指定。它返回整型值,若初始化成功,应返回0;若初始化失败,应返回错误编码。
3. 模块卸载函数
Linux内核模块记载函数一般以__exit标志声明,典型的模块卸载函数如:
static void __exit cleanup_function(void)
{
/*cleanup code*/
}
Module_exit(cleanup_function);
模块卸载函数在模块卸载的时候执行,不返回任何值,必须以”module_exit(函数名)”的形式来指定。
通常来说,模块卸载函数要完成与模块加载函数相反的功能,如下所示:
- 若模块加载函数注册了XXX,则模块卸载函数应该注销XXX.
- 若模块加载函数动态申请了内存,则模块卸载函数应该释放该内存。
- 若模块加载函数申请了硬件资源(中断,DMA通道,I/O端口和I/O内存等)的占用,则模块卸载函数应该释放这些资源。
- 若模块加载函数开启了硬件,则模块卸载函数中一般要关闭。
4. 模块参数
我们可以用’module_param(参数名,参数类型,参数读/写权限)’为模块定义一个参数,例如下列代码定义了1个整型参数和1个字符指针参数:
static char *test_name = “Test name is DEREN”;
static int num = 100;
module_param(num, int, S_IRUGO);
module_param(test_name, charp, S_IRUGO);
在加载内核模块时,用户可以向模块传递参数,
形式以”insmode(或modprobe) 模块名 参数名 = 参数值”,如果不传递,参数将使用模块内部定义的缺省值(默认值)。
参数类型可以是byte,short,ushort,int,uint,long,ulong,charp(字符指针),bool或invbool(布尔的反),在模块被编译时会将module_param中声明的参数类型与变量低定义的类型进行比较,判断是否一致。
例子:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE(“Dual BSD/GPL”);
static char *test_name = “Test name is DEREN”;
static int num = 100;
static int book_init(void)
{
printk(KERN INFO “book name:%s\n”, test_name);
printk(KERN INFO “book num:%d\n”, num);
return 0;
}
static void book_exit(void)
{
printk(KERN INFO “Book module exit \n”);
}
module_init(book_init);
module_exit(book_exit);
module_param(num, int, S_IRUGO);
module_param(test_name, charp, S_IRUGO);
对上述模块运行”insmod book.ko”命令加载,相应输出都为模块内的默认值,通过查看”var/log/messages”日志文件可以看到输出:
book name:The test name is DEREN
book num:100
当用户运行”insmod book.ko book_name=’test book’ nun=200 ”命令时,输出的是:
book name :test book
book num:200
5. 模块声明与描述
在Linux内核模块中,我们可以使
MODULE_AUTHOR,MODULE_DESCRIPTION,MODULE_VERSION,MODULE_DEVICE_TABLE,
MODULE_ALIAS分别声明模块的作者,描述,版本,设备表,别名。如:
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name)