一、内核模块基础知识
1. 模块的基础操作
以下操作以C语言经过make编译生成的hello-1.ko模块作为示例
-
lsmod或cat /proc/modules
显示当前被内核加载的模块
-
modinfo hello-1.ko
查看内核模块的信息,包括开发人员信息,依赖信息
-
insmod ./hello-1.ko
将新编译的模块插入到内核中,一次只能接一个
-
rmmod hello-1.ko
从内核中删除模块
-
dmesg | tail或tail /var/log/messages
查看printk出的结果,它会写入到系统日志中去。推荐使用dmesg | tail,可能一下就可以了,如果使用tail /var/log/messages报错说没有那个文件,请看本文结尾——二、问题汇总。
2. 内核模块编译
首先,创建一个Makefile文件(注意,命名就是Makefile,没有后缀的普通文件,不可变),然后直接套用一个模板,往里写入:
obj-m += hello-1.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
注意: Makefile文件对格式要求很严,如果复制我的模板过去,all和clean中的内容,本来是缩进(Tab)的,会被解释程多个空格,你可以在vim编辑中发现异常,该部分代码变红了,你可以删除这多个空格,然后按Tab缩进。
其中需要改动的就是,obj-m +=hello-1.o,用于更换编译对象(这里编译的对象是hello-1.c文件,下一张图我的编译对象是lab3^.c),剩下的all和clean中的代码不需要改动。
然后当前目录下就有.c,和没有后缀名的普通文件Makefile了,直接在命令行输入make即可编译。编译之后,可以看到当前目录下,生成了一大堆文件,其中的.ko文件就是模块了(内核2.6引入了一种新的文件命名约定:内核模块现在具有的.ko扩展名代替旧的.o扩展名,方便与传统的目标文件区分)
3. 模块部分书写(C语言)
-
init_module()和cleanup_module()是Linux2.4之前的,之后可以重命名,通过module_init()和module_exit()和module_exit()宏完成的,自由度更高,这些宏,在linux/init.h定义,需要包括头文件
#include <linux/init.h>
-
MODULE_DESCRIPTION(),宏,在linux/module.h中定义
用于描述模块的功能,MODULE_AUTHOR()声明模块的作者
-
MODULE_AUTHOR(),宏,在linux/module.h中定义
声明模块的作者
-
MODULE_SUPPORTED_DEVICE(),宏,在linux/module.h中定义
声明模块的作者
3.1 变量
module_param()宏,定义在linux/moduleparam.h中,变量必须先声明为全局变量,才能作为参数
-
参数
变量名称,它在sysfs中对应的文件的类型和权限,总共三个参数
变量为字符串的情况举例
static char *mystring = "blash"
module_param(mystring, charp, 0000);
-
module_param_array()和module_param_string()
相比于module_param()在第二和第三个参数之间,多了一个地址变量,用于储存在装载模块时,用户初始化变量的个数,也可以忽略计数传递参数NULL
3.2 多文件组合模块
先写两个.c文件,例如,start.c和stop.c文件,然后在Makefile文件中写入
obj-m +=startstop.o
startstop-objs := start.o stop.o
在make之后,会生成startstop.ko模块
二、问题汇总
-
无法查看/var/log/messages系统日志,提示没有哪个目录
-
vim /etc/rsyslog.d/50-default.conf
对于Linux命令不太熟悉的同学,也可以使用gedit编辑,权限不够提高权限, sudo gedit /etc/rsyslog.d/50- default.conf,或者切换root用户,su root,输入密码,gedit /etc/rsyslog.d/50-default.conf
-
将其中以Some “catch-all” log files开头,mail,news.none结尾的部分去掉注释符
-
重启rsyslog服务,restart rsyslog,如果说找不到这个job,可以重启
-
然后tail -f /var/log/messages就可以看到系统日志了
-
-
编译之后发现如下警告,warning:ISO C90 forbids mixed declaratios and code …
- 在内核模块编程中,应该把变量声明int id1=1,id2=2放在最前面去,即变量的声明应该放在语句之前。