一、关于内核模块
如果将所有的组件全部编入内核映像太浪费内存空间。比方说USB驱动,我只需要它运行1分钟,那么在剩余内核运行的59分钟都没有使用到它,但是他却一直占用着系统资源,显然这很不科学,所以就有了今天的题目——内核模块设计。
内核模块特点:
1、不被编译进内核文件
2、在内核运行期间可动态的运行或卸载。
3、命令:insmod安装、lsmod查看已安装模块、rmmod卸载内核模块。
例:内核模块:helloworld.ko,安装:insmod helloworld.ko、卸载:rmmod helloworld(注意卸载时不加.ko)
二、Linux内核模块设计
1、内核模块的编写
首先看一段内核模块范例代码
#include <linux/init.h> #include <linux/module.h> static int hello_init() { printk("Helloworld\n"); return 0; } static void hello_exit() { printk("Good Bye\n"); } module_init(hello_init); module_exit(hello_exit);
可以看到这段c程序没有main函数。main函数对一段应用程序来说是一个入口,那么没有main函数就没有入口了吗?显然不是。内核模块有三个要素, 头文件、module_init、module_exit。头文件很简单不用说,module_init就是这段程序的入口。当insmod这个内核模块 时,系统就会调用module_init宏指明的函数,也就是这里的hello_init函数。同样,module_exit就是这段程序的出口,当 rmmod这个模块的时候,系统就会调用module_exit宏指明的函数,也就是这里的hello_exit函数。有了这三要素,内核模块就算是编写 好了。
这里打印信息用到了printk函数,注意在内核中打印信息使用printk而不是printf,其中KERN_WARNING是内核打印的优先级,内核打印函数共有8个优先级,具体如下:
图片来自网络。
关于printk函数
2、内核模块的编译
内核模块的编译通过编写makefile来完成,其格式比较固定。
obj-m :=hello.o KDIR := /home/bumblebee/exercise/arm4/lesson3/linux-mini2440 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.o *.ko *.order *.symvers
(1)、当内核模块只需要一个c文件生成时采用如图第一行所示的编写方式,若由多个c文件生成则采用以下方式。
helloworld-objs :=file1.o file2.o file3.o
(2)、KDIR用来保存内核代码的路径,由于内核模块的编译是依赖于内核的信息的,所以需要将内核代码的路径用这个变量保存。
(3)、-C指明要进入-C后面的路径(内核路径)编译模块,M指明了模块文件的路径。
(4)、最后编写clean伪指令,清除产生的中间文件和.ko文件。
(5)、rmmod的时候要在/lib/modules目录下面有和内核模块的内核版本一致的目录名经常用(uname -r)来获取内核版本。
命令:mkdir -p /lib/modules/$(uname -r)。