我们的目的是要编译个hello.ko的文件,然后安装到内核中。
先来看下需要的代码,hello.c文件如下
#include <linux/module.h> #include <linux/init.h> static int hello_init(void) { printk(KERN_WARNING"Hello world!\n"); return 0; } static void hello_exit(void) { printk(KERN_INFO"Goodbye world!\n"); } module_init(hello_init); module_exit(hello_exit);
函数说明:
模块加载函数(必需)
安装模块时被系统自动调用的函数,通过module_init宏来指定。
模块卸载函数(必需)
卸载模块时被系统自动调用的函数,通过module_exit宏来指定。
1、Printk的打印级别如下:
级别 | 描述 |
KERN_EMERG |
紧急情况,系统可能会崩溃 |
KERN_ALERT |
必须立即响应 |
KERN_CRIT |
临界情况 |
KERN_ERR |
错误信息 |
KERN_WARNING |
警告信息 |
KERN_NOTICE |
普通的但可能需要注意的信息 |
KERN_INFO |
提示性信息 |
KERN_DEBUG |
调试信息 |
如果没有指定消息的级别,printk()会使用默认的DEFAULT_MESSAGE_LOGLEVEL(通常是KERN_WARNING)。
2、控制台的日志级别(console_loglevel)
当printk指定的消息级别小于指定的控制台日志级别时,消息的内容就会显示在该控制台上。控制台的日志级别定义在include/linux/kernel.h文件中,默认为DEFAULT_CONSOLE_LOGLEVEL(值等于7),也就是说默认情况下,比KERN_DEBUG级别高的printk()消息内容都可以在控制台上显示。
我们可以执行下面的命令使任何级别的printk()消息都被打印在终端上
$ echo 8 > /proc/sys/kernel/printk
3、printk()的变体
内核在include/linux/kernel.h文件中提供了两个printk()的变体pr_debug和pr_info,它们的定义为:
235 #define pr_debug(fmt,arg...) /
236 printk(KERN_DEBUG fmt,##arg)
244 #define pr_info(fmt,arg...) /
245 printk(KERN_INFO fmt,##arg)
4、 printk()不是万能的
printk()虽然很好用,但它并不是万能的,在系统启动时,终端还没有初始化之前,它并不能被使用,不过如果不是在调试系统的启动过程的话,这并不能算是个问题。
其实内核提供了一个printk()的变体early_printk(),专门用于在系统启动的初期在终端上打印消息,它与printk()的区别仅仅在于名字的不同以及它能够更早地工作。
Makefile文件如下ifneq ($(KERNELRELEASE),) obj-m := hello.o else KERNELDIR ?= /home/grb/grb/arm/linux-2.6.38/ PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *~ *.order endif
还有一种makefile的形式如下,可以做参考用
obj-m :=hello.o KERNELDIR ?= /home/grb/grb/arm/linux-2.6.38/ PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *~ *.order
命令说明:
加载 insmod (insmod hello.ko)
卸载 rmmod (rmmod hello)
查看 lsmod
加载 modprobe (modprobe hello)
Modprobe 如同insmod,也是加载一个模块到内核,他的不同之处在于他会根据文件/lib/modules/<$version>/modules.dep来查看要加载的模块。看他是否还依赖于其他模块,如果是,modprobe会首先找到这些模块,把它们先加载到内核。
所有前期工作都准备好之后,便可以直接make了,如下
这样就可以看到我们编译出来的hello.ko文件了。接下来就是安装测试了。将这个hello.ko文件拷贝到我们的开发板上,运行如下:
由结果可以看出,我们hello的内核模块是正常的了。