1. module
1.1 模块加载函数 __init
· 模块加载函数,当通过 insmod 或 modprobe 命令加载kernel module时,module的初始化函数会被自动调用执行,完成模块的初始化
· insmod 命令是单独加载内核模块而已,modprobe 命令加载模块的同时,还加载模块依赖的其他模块
· rmmod 命令用来卸载内核模块,而 modprobe -r 命令用来卸载指定的内核,并且卸载该模块依赖的所有模块
1.1.1 代码段
#include <liunx/init.h>
static __init int hello_init(void)
{
/* module init code */
return 0;
}
module_init(hello_init);
· #include <liunx/init.h> 是Linux初始化相关的头文件
· static 为静态函数,只具备文件作用域
· __init 标识,有__init标识的函数只会在kernel初始化的时候才被加载到内存调用,调用结束后即对应的代码段内存空间被释放,再次调用该标识的函数就会报错
· module_init 是一个回调函数
1.1.2 数据段
static __initdata int a = 1;
· __initdata标识,拥有该标识的数据,在kernel初始化完成后,该数据在内存占用的数据段会被释放
1.2 模块卸载函数 __exit
1.2.1 代码段
#include <liunx/init.h>
static __exit void hello_exit(void)
{
/* module exit code */
return 0;
}
module_exit(hello_exit);
· #include <liunx/init.h> 是Linux初始化相关的头文件
· static 为静态函数,只具备文件作用域
· __exit 标识,有__exit标识的函数只会在模块卸载时才被到加载到内存中,调用结束后即对应的代码段内存空间被释放,再次调用该标识的函数就会报错。但如果模块是编译到kernel中,那模块将失去热插拔的特性,卸载模块函数也失去意义
· module_init 是一个回调函数
1.2.2 数据段
static __exitdata int a = 1;
· __exitdata标识,拥有该标识的数据,在kernel模块卸载完成后,该数据在内存占用的数据段会被释放
1.3 模块许可证声明
· 许可证说明:描述kernel module的许可权限,如果不声明LICENSE(许可证),module加载时,将会收到kernel被污染(Kernel Tainted)的警告
· 在Linux module领域,可接受的LICENSE包括:''GPL''、''GPL v2''、''GPL and additional rights''、''Dual BSD/GPL''、''Dual MPL/GPL''、''Proprietary''(关于module是否可采用非GPL许可权,如''Proprietary''现在还是饱受争议的)
· 大多数情况下,kernel module都应遵循GPL兼容许可权,最常见的是使用GPL v2版本的
1.3.1声明许可证的实现
以最常见的GPL v2为例
#include <linu/module.h>
MOUDLE_LICENSE("GPL v2");
1.3.2 使用module"规避"GPL
· 只使用GPL module的运行结果,间接的使用module''规避''GPL,但这也是具有争议的
· 一般认为,保守的做法是Linux kernel 不能使用非GPL LICENSE
1.4 模块参数(可选)
1.5 模块导出符号(可选)
· /proc/kallsyms 文件对应着内核符号表,里面记录着符号以及符号所在的内存地址
module 通过下面的宏将符号导出到内核符号表中
#include <linux/export.h>
EXPORT_SYMBOL(符号名); //非GPL许可证的module使用
EXPORT_SYMBOY_GPL(符号名); // 只适用与GPL许可证的module使用
1.6 模块作者等信息(可选)
#include <linux/module.h>
MODULE_AUTHOR(author); //作者信息
MODULE_DESCRIPTION(description); //描述模块信息
MODULE_VERSION(version_string); //版本描述
MODULE_DEVICE_TABLE(table_info); //对于USB,PCI等设备驱动,通常会创建一个表明该驱动模块所支持的是设备
MODULE_ALIAS(alternate_name); //模块别名
1.7 模块使用计数(附加)
· kernel module的使用计数为0时,才允许module的卸载
· module的使用计数的增加和减少由kernel操作,操作对象为dev -> owner
· 但可能特殊情况我们也需自己管理module的使用次数
#include <linux/module>
try_module_get(dev -> owner); //module 使用次数加一
module_put(dev -> owner); //module 使用次数减一
1.8 模块的依赖性
1.8.1 模块的命名与别名
· 模块的名字一般是系统规定的,为你模块文件去掉后缀后的名字,比如DS18B20.ko的模块,模块名字一般为DS18B20
1.8.1.1 模块名字的宏
#include <linux/module.h>
.owner = THIS_MODULE; //THIS_MODULE为当前模块名的宏
1.8.1.2 模块的别名
#include <linux/module.h>
MODULE_ALIAS("my_driver_name"); //为当前模块创建一个别名