Linux内核模块:初始化、加载/卸载、模块参数、导出符号、错误处理、模块装载竞争
2014-10-29 14:08
369 查看
一、代码
模块1导出了函数void output(void),模块2调用了模块1中的函数。(先加载模块1,再加载模块2)
模块1:
2.1 函数原型
static int __init init_marker(void)
{
}
static void __exit exit_marker(void)
{
}
初始化函数,在定义文件之外没有任何意义,所以应声明为static。
__init(__exit)表名该函数只在初始化期间使用。在模块装载之后,模块装载器会将初始化函数丢掉,这样可以将函数占用的内存释放出来。
2.2 关于模块的描述
MODULE_VERSION("1.0.0_0");
模块版本号
MODULE_LICENSE("GPL");
模块开源协议
MODULE_AUTHOR("gwy");
模块作者
MODULE_ALIAS("the alias of module name");
模块别名
MODULE_DESCRIPTION("the description about the use of the module");
模块描述
MODULE_PARM_DESC(int_var, "A integer variable");
参数描述
查看模块信息:
三、加载/卸载
insmod
rmmod
modprobe ( modprobe -r )
lsmod(通过读取/proc/modules虚拟文件来获取模块信息)
四、模块参数
4.1 参数
module_param(int_var, int, 0644);
定义模块参数。
module_param_named(str_var_alias, str_var, charp, 0644);
外部参数名称与内部变量名称不同。
module_param_string(str_var2_alias, str_var2, 10, 0644);
拷贝字符串到分配好的内存。(不同于charp,先分配内存,再拷贝)
module_param_array(int_arr, int, &narr, 0644);
定义模块数组类型参数。
module_param_array_named(int_arr2_alias, int_arr2, int, &narr2, 0644);
数组类型 外部参数名称与内部变量名称不同。
MODULE_PARM_DESC(int_var, "A integer variable");
参数描述。
4.2 支持的类型
bool
invbool
布尔值(true或false),关联的变量是int型。
charp
字符指针值。内核会为用户提供的字符串分配内存,并设置相应的指针。
int、short、long、uint、ushort、ulong
4.3 访问权限
module_param(int_var, int, 0644);
0644是访问权限,用数字表示,或者用S_IRUGO|S_IWUSR表示。
查看访问权限:/sys/module/test/parameters
4.4 查看模块的参数
modinfo查看,见2.2中图片。
五、导出符号表
模块层叠技术
5.1 导出函数
EXPORT_SYMBOL(func)
EXPORT_SYMBOL_GPL(func)
EXPORT_SYMBOL_GPL导出的模块只能被GPL许可的模块使用。
5.2 查看导出的符号
/proc/kallsyms
5.3 调用模块导出符号
需要在模块2的Makefile中添加:KBUILD_EXTRA_SYMBOLS = /opt/test-kernel/Module.symvers(模块1的路径,必须是绝对路径), 否则会报错。
参考资料:http://blog.csdn.net/hshl1214/article/details/8769112
六、错误处理
如果可以继续,通过降低功能继续运转。
如果不能继续,必须撤销所有已经注册的设备。
goto、cleanup/flag。
撤销顺序与加载顺序相反。
七、模块装载竞争
模块还没初始化完的时候,内核就有可能来调用我们的模块了。
模块1导出了函数void output(void),模块2调用了模块1中的函数。(先加载模块1,再加载模块2)
模块1:
#include <linux/module.h> #include <linux/kernel.h> // static int int_var = 0; module_param(int_var, int, 0644); MODULE_PARM_DESC(int_var, "A integer variable"); static char* str_var = "default"; module_param_named(str_var_alias, str_var, charp, 0644); MODULE_PARM_DESC(str_var_alias, "A string variable"); static char str_var2[10]; module_param_string(str_var2_alias, str_var2, 10, 0644); MODULE_PARM_DESC(str_var2_alias, "A string variable"); static int int_arr[10]; int narr; module_param_array(int_arr, int, &narr, 0644); MODULE_PARM_DESC(int_arr, "A integer array"); static int int_arr2[10]; int narr2; module_param_array_named(int_arr2_alias, int_arr2, int, &narr2, 0644); MODULE_PARM_DESC(int_arr2_alias, "A integer array"); // static void output(void) { printk("hello world!\n"); } EXPORT_SYMBOL_GPL(output); static int __init init_marker(void) { int i; printk("init marker.\n"); // printk("int_var:%d\n", int_var); printk("str_var:%s\n", str_var); printk("str_var2:%s\n", str_var2); for (i=0; i<narr; ++i) { printk("int_arr[%d]=%d\n", i, int_arr[i]); } for (i=0; i<narr2; ++i) { printk("int_arr2[%d]=%d\n", i, int_arr2[i]); } // output(); return 0; } static void __exit exit_marker(void) { printk("exit marker.\n"); } module_init(init_marker); module_exit(exit_marker); MODULE_VERSION("1.0.0_0"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("gwy"); MODULE_ALIAS("the alias of module name"); MODULE_DESCRIPTION("the description about the use of the module"); //MODULE_DEVICE_TABLE();模块2:
#include <linux/module.h> #include <linux/kernel.h> static void my(void) { extern void output(void); output(); printk("my\n"); } static int __init init_marker(void) { printk("init marker.\n"); my(); return 0; } static void __exit exit_marker(void) { printk("exit marker.\n"); } module_init(init_marker); module_exit(exit_marker); MODULE_VERSION("1.0.0_0"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("gwy"); MODULE_ALIAS("the alias of module name"); MODULE_DESCRIPTION("the description about the use of the module"); //MODULE_DEVICE_TABLE();二、初始化
2.1 函数原型
static int __init init_marker(void)
{
}
static void __exit exit_marker(void)
{
}
初始化函数,在定义文件之外没有任何意义,所以应声明为static。
__init(__exit)表名该函数只在初始化期间使用。在模块装载之后,模块装载器会将初始化函数丢掉,这样可以将函数占用的内存释放出来。
2.2 关于模块的描述
MODULE_VERSION("1.0.0_0");
模块版本号
MODULE_LICENSE("GPL");
模块开源协议
MODULE_AUTHOR("gwy");
模块作者
MODULE_ALIAS("the alias of module name");
模块别名
MODULE_DESCRIPTION("the description about the use of the module");
模块描述
MODULE_PARM_DESC(int_var, "A integer variable");
参数描述
查看模块信息:
三、加载/卸载
insmod
rmmod
modprobe ( modprobe -r )
lsmod(通过读取/proc/modules虚拟文件来获取模块信息)
四、模块参数
4.1 参数
module_param(int_var, int, 0644);
定义模块参数。
module_param_named(str_var_alias, str_var, charp, 0644);
外部参数名称与内部变量名称不同。
module_param_string(str_var2_alias, str_var2, 10, 0644);
拷贝字符串到分配好的内存。(不同于charp,先分配内存,再拷贝)
module_param_array(int_arr, int, &narr, 0644);
定义模块数组类型参数。
module_param_array_named(int_arr2_alias, int_arr2, int, &narr2, 0644);
数组类型 外部参数名称与内部变量名称不同。
MODULE_PARM_DESC(int_var, "A integer variable");
参数描述。
4.2 支持的类型
bool
invbool
布尔值(true或false),关联的变量是int型。
charp
字符指针值。内核会为用户提供的字符串分配内存,并设置相应的指针。
int、short、long、uint、ushort、ulong
4.3 访问权限
module_param(int_var, int, 0644);
0644是访问权限,用数字表示,或者用S_IRUGO|S_IWUSR表示。
查看访问权限:/sys/module/test/parameters
4.4 查看模块的参数
modinfo查看,见2.2中图片。
五、导出符号表
模块层叠技术
5.1 导出函数
EXPORT_SYMBOL(func)
EXPORT_SYMBOL_GPL(func)
EXPORT_SYMBOL_GPL导出的模块只能被GPL许可的模块使用。
5.2 查看导出的符号
/proc/kallsyms
5.3 调用模块导出符号
需要在模块2的Makefile中添加:KBUILD_EXTRA_SYMBOLS = /opt/test-kernel/Module.symvers(模块1的路径,必须是绝对路径), 否则会报错。
参考资料:http://blog.csdn.net/hshl1214/article/details/8769112
六、错误处理
如果可以继续,通过降低功能继续运转。
如果不能继续,必须撤销所有已经注册的设备。
goto、cleanup/flag。
撤销顺序与加载顺序相反。
七、模块装载竞争
模块还没初始化完的时候,内核就有可能来调用我们的模块了。
相关文章推荐
- 记linux内核处理bootargs到内核并加载模块时传入参数(module_param_named()等)
- Linux 驱动之模块参数和符号导出
- win 7、win8注册 卸载 报错: 模块XXX已加载 但对DllUnregisterServer的调用失败 处理方法
- 系统 应用程序 提示 初始化失败 或 无法加载模块 等错误
- Linux设备驱动程序学习笔记2——带参数的模块加载和卸载
- Linux 驱动之模块参数和符号导出
- win7 注册 卸载 报错: 模块 XXX 已加载 但对DllUnregisterServer 的调用失败 处理方法
- linux驱动入门——模块参数和导出符号
- Linux设备驱动程序学习笔记2——带参数的模块加载和卸载
- Linux 驱动之模块参数和符号导出
- 一个登陆页面,包含了初始化用户,输入检测,错误处理等
- ASP.Net处理QueryString函数汉字参数传递错误
- Linux内核模块编译、加载&卸载及查看运行结果
- direct=true 错误处理方法 (关于 Oracle 的数据导入导出及 Sql Loader (sqlldr) 的用法
- 执行PMCMD时加载libpmasrt.a 的错误处理
- 无法加载程序集错误处理
- Linux系统下导出ORACLE数据库出现Exporting questionable statistics.错误 处理
- Error loading opeating system 加载系统错误处理方法
- “无法加载安装程序库wbemupgd.dll,或是找不到函数OcEntry.请与您的系统管理员联系。特定错误码是 0x7e;" 然后是警告框: " 无法初始化应用程序。"
- Linux 2.6.x 内核模块加载错误 “Invalid module format” 解决办法