内核模块结构
加载函数
通过insmod或者modprobe加载模块时,加载函数将会自动执行
卸载函数
通过rmmod卸载模块时,卸载函数将会被自动执行
许可证声明
描述内核模块的许可权限,如果不声明,加载时将收到内核被污染(Kernel Tainted)的警告
大多数情况下,采用GPL v2
MODULE_LICENSE("GPL v2");
模块参数
模块参数是模块被加载时,可以传递给它的值,对应于模块内部的局部变量
模块导出符号
模块可以导出符号(symbol),对应函数或变量,如果导出,则其它模块就可以使用了
加载函数
形式被固定为 module_init(函数名);
,返回整型值,若初始化成功,则返回0,失败返回错误码
在内核中,也可以通过request_module(模块名)
函数灵活地加载其它内核模块
一般以__init
标识对初始化函数做额外声明,原型如下
#define __init __attribute__ ((__section__ (".init.text"))) __cold
指定该函数,在链接的时候,放到init.text
段,初始化的时候,调用这些函数,初始化完成后,释放内存
数据也可以用__initdata
进行标识,链接时,放到init.data
区段,同样在初始化完成后,释放其内存
static int __init hello_init(void){...}
static int a __initdata=1;
卸载函数
形式被固定为module_exit(函数名)
,不返回任何值,卸载函数利用__exit
进行修饰
同样,只是在卸载阶段起作用的变量,也可以利用__exitdata
进行修饰
模块参数
用户态通过main函数即可完成参数传递,在内核态中,可以使用module_param(参数名,参数类型,参数权限)
为模块定义参数,例如:
static int a=10;
module_param(a, int, 0644);
调用形式为
insmod 模块名 参数名=参数值
insmod book.ko book_name=‘nihao’ book_num=100
也可以设置参数数组,形式为module_param_array(数组名,数组类型,数组长度,参数权限)
如果调用的时候,参数缺省,则使用内部缺省值
如果是内置模块,则无法通过insmod加载模块,但是可以通过bootloader,在bootargs中设置模块名.参数名=值
的形式,给内置模块传递参数
参数加载后,在/sys/module/模块名/的目录下,将出现parameters目录,里面可以查看参数信息
参数类型
- byte
- short
- ushort
- int
- uint
- long
- ulong
- charp:字符指针
- bool
- invbool:布尔的反
权限类型
相关宏定义在src/include/stat.h
S_IRUGO=(S_IRUSR|S_IRGRP|S_IROTH)
S_IRUSR:用户读 00400
S_IRGRP:用户组读 00040
S_IROTH: 其他读 00004
因此,权限可以用宏或者八进制表示法
导出符号
符号包括函数和变量,/proc/kallsyms
文件对应内核符号表,记录了符号以及符号所在的内存地址
模块可以使用以下两种方法导出符号到内核符号表,导出的符号可以被其它模块使用,但是使用前需要声明
EXPORT_SYMBOL(符号名); //所有模块都能使用
EXPORT_SYMBOL_GPL(符号名); //GPL许可的模块能使用
模块的声明与描述
作者
MODULE_AUTHOR(作者名字);
描述
MODULE_DESCRIPTION(“描述内容”);
版本
MODULE_VERSION(“版本号”);
设备表
对于USB、PCI等设备驱动,通常会创建设备表,表明支持的设备
MODULE_DEVICE_TABLE(type, name);
别名
MODULE_ALIAS(“别名”);
来源:CSDN
作者:龚立新
链接:https://blog.csdn.net/whitefish520/article/details/103896560