- 一、简介
- 二、一个简单的内核模块代码
- 三、模块内常用符号说明
- 四、内核模块加载
- 1、模块加载函数
- 2、模块加载
- 3、查看设备上当前模块的信息
- 4、查看模块依赖
- 五、内核模块卸载
- 1、模块卸载函数
- 2、模块卸载
- 六、模块参数
- 七、导出符号
- 八、编译
linux内核架构庞大功能众多,包含非常多的组件。并不是所有功能都是用户需要的,也不可能稍微修改一些功能就重新全编linux内核。
-
当前linux使用模块(module)的机制解决这个问题
- 1、module可以单独编译
- 2、module可以在内核启动后动态加载或卸载
#include
#include
#include
static int __init module_init_test(void)
{
pr_info("module init test!");
/* do something about module init */
pr_info("module init end!");
return 0;
}
static void __exit module_exit_test(void)
{
pr_info("module exit test!");
/* do something about module exit */
pr_info("module exit end!");
return;
}
module_init(module_init_test);
module_exit(module_exit_test);
MODULE_AUTHOR("zhuang da shuai ge");
MODULE_DESCRIPTION("just a test module");
MODULE_LICENSE("GPL");
三、模块内常用符号说明
module_init(); /* 模块加载 */ /* 第四章说明 */
module_exit(); /* 模块卸载 */ /* 第五章说明 */
module_param(); /* 模块参数 */ /* 第六章说明 */
EXPORT_SYMBOL(); /* 导出符号 */ /* 第七章说明 */
EXPORT_SYMBOL_GPL(); /* 导出符号 */ /* 第七章说明 */
模块声明相关:
MODULE_AUTHOR("***"); /* 作者 */
MODULE_LICENSE("GPL"); /* 许可证说明 */
MODULE_DESCRIPTION("***"); /* 模块信息 */
MODULE_ALIAS("***"); /* 模块别名 */
MODULE_VERSION("***"); /* 模块版本 */
等
四、内核模块加载
1、模块加载函数
代码中static int __init module_init_test(void)
就是一个模块加载函数,一般以__init
标识,使用module_init(module_init_test)
指定。
模块加载时,实际就是运行此函数。返回整形值,正常返回0,其它异常返回值在
中有定义,函数最好按照规范定义返回。
模块加载有insmod和modprobe两种方式:
insmode ./test.ko
modprobe test
例如:
~# insmod test.ko
~# dmesg -c
[148348.202699] module init test!
[148348.202699] module init end!
两种模块加载的方法实际都是运行模块加载函数。modprobe
功能更加强大,会自动加载模块的依赖。
在linux环境下,使用lsmod
可以查看设备上当前已经加载的模块,该命令实际上是解析/proc/modules
.
~# lsmod |grep test
test 16384 0
~# cat /proc/modules |grep test
test 16384 0 - Live 0xffffffffc0336000 (OE)
另外,已加载的模块的信息,也存在/sys/module目录下。
使用modeinfo <模块名> 可以查看模块信息。
~# modinfo test
filename: /lib/modules/4.19.0-12-2-amd64/extra/test.ko
license: GPL
description: just a test module
author: zhuang da shuai ge
depends:
retpoline: Y
name: test
vermagic: 4.19.0-12-2-amd64 SMP mod_unload modversions
4、查看模块依赖
参考以前写的文章:查看内核模块依赖关系和动态库依赖关系
五、内核模块卸载 1、模块卸载函数代码中static void __exit module_exit_test(void)
就是一个模块卸载函数,一般以__exit
标识,使用module_exit(module_exit_test)
指定。
模块卸载时,实际就是调用此函数。
rmmod test
modprobe -f test (卸载模块和其依赖)
模块卸载可直接用rmmod
,也可以用modprobe r 模块名
方式,使用modprobe r
会同时卸载相关依赖。
~# rmmod test
~# dmesg -c
[ 4175.680292] module exit test!
[ 4175.680292] module exit end!
六、模块参数
使用module_param(参数名,参数类型,参数读写权限)
定义模块的参数。例如:
static int test_param = 10;
module_param(test_param, int, S_IGUGO);
如此定义后,加载内核模块时,用户可直接传递模块参数的值:
modprobe(insmod) 模块名 参数名=参数值
modprobe(insmod) test test_param=11
如此加载模块,test_param值则被定义为11。若加载模块时不传递参数值,则test_param为默认值10。
七、导出符号/proc/kallsyms文件中记录了内核符号表,记录符号以及符号所在的内存地址。在这个符号表中的接口,可被其它模块调用。
模块中可用如下宏将符号导出到内核符号表中,导出的符号可被其它模块使用:
EXPORT_SYMBOL();
EXPORT_SYMBOL_GPL();
八、编译
obj-m := modulename.o
模块包含多个文件时:
obj-m := modulename.o
modulename-objs := test1.o test2.o
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)