Linux 内核模块开发
1、 什么是内核模块?
避免内核镜像太大,占用太多的内存资源,所以可以编译进内核模块中去。
特点:动态的加载与卸载;不会被编译进内核镜像文件。
2、 学习方法。
范例程序->思维导图(指导性,纲领性,很重要)->自己动手编写程序。
3、 范例分析
#include <linux/init.h>//必须包含的两个头文件
#include <linux/module.h>
int static hello_init(void)//注意加载函数返回值是int型
{
printk(KERN_WARNING"Hello, world !\n");
return 0;
}
void static hello_exit(void)//卸载函数返回值是void型
{
printk (KERN_INFO "Goodbye, world\n");
}
module_init(hello_init);//是一个宏,在这里调用加载函数
module_exit(hello_exit);//是一个宏,在这里调用卸载函数
4、与应用程序的区别
A、没有main函数,但是内核模块有入口函数和出口函数,或者叫加载函数和卸载函数。
内核模块安装的时候调用加载函数,卸载的时候调用卸载函数。
B、应用程序从头到尾执行程序,执行完从内存中消失,内核模块初始化结束时模块仍然存在于内存中,直到卸载函数被调用,模块才从内存中消失。
5、 内核模块的Makefile
内核模块的Makefile的首字母M必须大写,
一个obj-m后面加几个*.o文件,就生成几个内核模块,不能连续写几个obj-m,因为后面生成的内核模块会把前面的生成的内核模块覆盖掉。
当一个*.c文件调用其他文件*.c的函数时,得声明。
注意有多个*.c文件时的makefile的编写,
6、安装于卸载
当有用户使用该模块时,不能卸载该模块,用lsmod查看当前模块。
卸载模块命令rmmod 模块名字,
安装模块命令insmod模块名字.ko
6、 可选项
模块申明,让程序更加符合一些规范协议,eg:GPL,更加符合可读性,
申明模块遵守的协议MODILE_LICENSE(“遵守的协议”)
申明模块作者MODULE_AUTHOR(“作者”)
申明模块功能MODULE_DESCRIPTION(“功能”)
申明模块版本MODULE_VERSION(“版本”)
模块参数,在应用程序中int main(intargc, char** argv)argc表示命令行输入的参数个数,argv中保存输入的参数。通过宏module_param指定保存模块参数的变量。模块参数用于在加载模块时传递参数给模块。
module_param(name,type,perm)
name:变量的名称
type:变量类型,bool:布尔型 int:整型 charp:字符串型
perm是访问权限。S_IRUGO:读权限 S_IWUSR:写权限
例:
int a = 3;
char *st;//不需要去分配空间,系统会自动分配空间
module_param(a,int,S_IRUGO);
module_param(st,charp,S_IRUGO);//charp表示字符串
在insmod的时候后面可以带参数,例如:insmod test.ko a=1 str=sfdsf.
符号打出:函数,变量就是符号,模块的里面的符号要被别的模块使用,就得必须通过申明来输出这些符号到Linux系统中去被其他的模块调用,
申明函数EXPORT_SYMBOL(符号名),该函数写在定义函数或变量的文件里面。
EXPORT_SYMBOL_GPL(符号名) 该函数只能用于包含GPL许可证的模块。
7、 内核打印
Printk函数,通过优先级来对消息进行分类。控制是否打印到屏幕。
在<linux/kernel.h>中定义了8种记录级别。按照优先级递减的顺序分别是:
KERN_EMERG “<0>”用于紧急消息,常常是那些崩溃前的消息。
KERN_ALERT “<1>”需要立刻行动的消息。
KERN_CRIT “<2>”严重情况。
KERN_ERR “<3>”错误情况。
KERN_WARNING“<4>”有问题的警告
KERN_NOTICE “<5>”正常情况,但是仍然值得注意
KERN_INFO “<6>”信息型消息
KERN_DEBUG “<7>”用作调试消息
没有指定优先级的printk默认使用DEFAULT_MESSAGE_LOGLEVEL优先级,它是一个在kernel/printk.c中定义的整数。
#define DEFAULT_MESSAGE_LOGLEVEL 4 /*KERN_WARNING */