1、概念(为什么需要模块)
1.1 我们得到一个内核镜像后,想要增加功能时,两种方式:
(1)一种方式是在配置选项中添加模块,重新编译内核,这样会很麻烦。
(2)找一个默认配置添加了全部功能的内核,这样内核太大了。
1.2 有没有一种机制使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码被动态地加载到内核中呢?
答:Linux提供了这样的一种机制,这种机制被称为模块(Module)。模块具有这样的特点:
(1) 模块本身不被编译入内核映像,这控制了内核的大小。
(2) 模块一旦被加载,它就和内核中的其它部分完全一样。
2、模块代码组成
2.1 模块加载函数(必须)
(2) 使用modinfo <模块名>命令可以获得模块的信息,包括模块作者、模块的说明、模块所支持的参数以及vermagic:
[root@localhost driver_study]# modinfo hello.kofilename: 全路径/ hello.kolicense: Dual BSD/GPLauthor: 作者description: 描述alias: a simplest modulevermagic: 2.6.15.5 686 gcc-3.2 版本号 内核版本和模块版本必须相同才能安装depends: 依赖(这个模块是否依赖其他模块,kconfig中指定)
(3)模块加载函数必须以module_init(函数名) 的形式被指定。它返回整型值,若初始化成功,返回0。初始化失败时,应该返回错误编码。内核的错误码是一个负数,在中定义,形如ENODEV等。
(4)代码如下:
1. static void __exit foo_exit(void)
2. {
3. //...
4. }
5. module_exit(foo_exit);
2.2 模块卸载函数(必须)
(1)当通过rmmod命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。
(2)Linux内核模块卸载函数一般用static 关键字声明为内部链接,并以__exit 标识。和__init 一样, __exit 也可以使对应函数在运行完成后自动回收内存。具体可以查看内核代码中__init 和__exit 这两个宏的定义。
(3)模块卸载函数必须以module_exit(函数名) 的形式指定,不返回任何值。
示例代码如下:
1. static void __exit foo_exit(void)
2. {
3. //...
4. }
5. module_exit(foo_exit);
2.3 模块许可证声明(必须)
(1)模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明 LICENSE,模块被加载时,将收到内核被污染(kernel tainted)的警告,因为内核按照LICENSE标准定义,你写的模块也必须标注相同LICENSE,内核才让你使用。在Linux2.6内核中,可接受的 LICENSE包括“GPL”,“GPL v2”,“GPL and additonal rights”,“Dual BSD/GPL”,“Dual MPL/GPL”和“Proprietary”。
(2)Linux2.6内核模块最常见的是声明代码如下(3.4内核用的GPL v2):
MODULE_LICENSE("Dual BSD/GPL");
2.4 模块vermagic信息
详细细节请看下面博主: