Linux内核模块开发
内核模块的特点
1.不被编译进内核文件bzImage中
2.可以根据需求,在内核运行期间动态地安装或卸载
内核模块设计
1.内核模块程序的入口和出口是通过一个宏定义的module_init(entry func)、module_exit(end func)来决定的。
2.思维导图
3.Makefile
a)内核模块的编译是依赖于内核源码的,/lib/modules/$(shell uname -r)/build是链接到/usr/src/kernels/2.6.32-279.el6.i686上的
b)内核中的Makefile文件的首字母必须大写,否则会出错;
c)使用make -C $(内核源码位置) M=$(PWD) modules来进入内核源码地址进行make modules进行内核模块的编译,其中obj-m是个makefile变量,是一串.o文件的表 列。-C表示到 $(内核源码位置)执行make,M也是makefile变量,表示的是当前内核模块程序所在的路径;
d)当有多个.c文件合成一个模块时时,需要使用一个xxx-objs来表示,xxx-objs是makefile变量,之后再通过obj-m := xxx.o来定义makefile变量名
4.安装和卸载内核模块
a)安装内核模块:insmod
b)卸载内核模块:rmmod
c)查看内核模块:lsmod
5.模块申明
a)MODULE_LICENSE(“遵守的协议”):申明该模块遵守的许可证协议:“GPL”等
b)MODULE_AUTHOR(“作者”):申明模块的作者
c)MODULE_DESCRIPTION(“模板功能”):申明模块的功能
d)MODULE_VERSION(“v1.0”):申明模块的版本
6.模块参数
通过宏module_param指定保存模块参数的变量,模块参数用于在加载模块时传递参数给模块module_param(name, type, perm);
name:变量的名称
type:变量类型,bool:布尔型,int:整型;charp:字符串型
perm:访问权限,S_IRUGO:可被读权限, S_IWUSR:可被写权限
使用模块参数只需要在insmod的时候在后加上模块参数name=xx即可
在内核模块中定义一个字符型指针不需要主动分配内存,内核会自动分配内存的。
7.符号导出(相当于将一个函数声明为extern,允许其他文件使用)
内核符号的导出使用宏
EXPORT_SYMBOL(符号名)
EXPORT_SYMBOL_GPL(符号名):用于支持GPL协议的模块
8.内核模块与应用程序的对比:
a)应用程序是从头到尾执行任务,执行结束后从内存中消失
b)内核模块的初始化函数结束时,模块仍然存在于内存中,直到卸载函数被调用,模块才从内存中消失
Tips:
1. obj-y是个makefile变量,表示要编译进内核的文件
2. printk用于内核态,printf用于用户态,在printk中<0>~<7>优先级依次下降,如果printk的优先级小于控制台的优先级,则printk不能再控制台上打印出来,不申明优先级的情况下,默认等级是4即有问题的警告
a)KERN_EMERG “<0>”
用于紧急消息,常常是那些崩溃前的消息
b)KERN_ALERT“<1>”
需要立刻行动的消息
c)KERN_CRIT “<2>”
严重情况
d)KERN_ERR “<3>”
错误情况
e)KERN_WARNING “<4>”
有问题的警告
f)KERN_NOTICE “<5>”
正常情况,但是仍需要值得需要
g)KERN_INFO “<6>”
信息型消息
h)KERN_DEBUG“<7>”
用作调试信息
3. 每次insmod后如果想再次运行内核模块,可以使用rmmod之后再使用insmod
遇到的问题:
1.在运行make命令时,总是提示“/lib/modules/$(shell uname -r)/build”No such direction or 。。。;
解决方案:/lib/modules/$(shell uname -r)/下建立一个与/usr/src/kernels/$(shell uname -r)/的软链接,即ln -s /usr/srckernels/$(shell uname -r) /lib/modules/$(shell uname -r)后顺利解决,原因是因为/lib/modules/$(shell uname -r)下的build是指向/usr/src/kernels/$(shell uname -r)的,当我们运行make -C $(内核源码位置) M=$(shell pwd) modules 时,其实是到/usr/src/kernels/$(shell uname -r)/的路径下去执行的。