一、、hello world模块
代码:
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("DualBSD/GPL");
static inthello_init(void)
{
printk(KERN_ALERT "Hello, Linux.I amcoming!\n");
return0;
}
static voidhello_exit(void)
{
printk(KERN_ALERT "Goodbye, Linux. I will backlater.\n");
}
module_init(hello_init);
module_exit (hello_exit);
说明:
#include <linux/init.h>
#include <linux/module.h>
init.h包含初始化和清除函数。module.h包含有可装载模块需要的大量符号和函数的定义。
尽管不是严格要求,但模块应该指定代码所使用的许可证。内核能够识别的许可证有:“GPL”、“GPL v2”、“GPL andadditional rights"、“Dual BSD/GPL"、“GPLMPL/GPL”、“Proprietary”。在我们的模块里我们用“Dual BSD/GPL”
MODULE_LICENSE("DualBSD/GPL"); // MODULE_LICENSE是一个宏,用来告诉内核模块采用许可证类型。
模块定义了两个函数:static int hello_init(void) staticvoid hello_exit(void)。模块被装载时调用hello_init,模块被移除时调用hello_exit。
这里用到了一个内核函数:prinfk。内核运行时不信赖于C库,内核模块只能调用内核导出的函数。
二、编译和装载
编译模块
makefile代码:
ifneq($(KERNELRELEASE),)
obj-m :=helloworld.o
else
KERNELDIR ?=/lib/modules/$(shell uname-r)/build
PWD := $(shellpwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD)modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
说明:
不同于一般的应用程序,我们编译模块的时候都用make来管理我们的编译过程。这个简单的makefile在我们执行make的时候都做了些什么呢?
当我们在模块源代码目录下执行make的时候,它读取当前目录下的makefile,执行else后面的语句,因为这个makefile里没有定义KERNELRELEASE这个变量。展开后是:make-C /lib/modules/2.6.32.12-115.fc12.i686/buildM=/home/birdb/LDD3/misc-modules/hellomodules,紧接着执行展开后的表达式。-C改变路径到内核源代码,找到内核顶层Makefile,M变量就是模块源代码目录,主要是为了让内核顶层的Makefile包含模块源代码目录下的makefile,包含以后获取obj-m:=hello.o因为内核顶层Makefile定义了KERNELRELEASE。书上说模块源代码目录下的makefile被读取两次,第一次就是执行make的时候,第二次是被包含进内核顶层Makefile的时候。
makefile也可以简单地写成这样:
但是不能再简单地执行:make,而应该写成:make -C 内核源代码目录 M=`pwd` modules
在我的系统上运行的结果是:
1 | 1. [birdb@wishmiss hello]$make |
2 | 2. make -C /lib/modules/2.6.32.12-115.fc12.i686/buildM=/home/birdb/LDD3/misc-modules/hellomodules |
3 | 3. make[1]: Entering directory`/usr/src/kernels/2.6.32.12-115.fc12.i686' |
4 | 4. CC[M] /home/birdb/LDD3/misc-modules/hello/helloworld.o |
5 | 5. Building modules,stage 2. |
7 | 7. CC /home/birdb/LDD3/misc-modules/hello/helloworld.mod.o |
8 | 8. LD[M] /home/birdb/LDD3/misc-modules/hello/helloworld.ko |
9 | 9. make[1]: Leaving directory`/usr/src/kernels/2.6.32.12-115.fc12.i686' |
编译成功,接下来就是加载模块。
加载和卸载模块
内核模块加载、卸载的命令分别是:insmod rmmod。加载还可以用modprobe,不过我不会用,也没研究。两个命令都需要用root执行。
执行效果:
1 | 1. [birdb@wishmiss hello]$ sudo insmod helloworld.ko;sudormmod helloworld.ko |
2 | 2. [birdb@wishmiss hello]$ dmesg |tail-2 |
3 | 3. Hello, Linux.I amcoming! |
4 | 4. Goodbye, Linux. I will backlater. |
5 | 5. [birdb@wishmiss hello]$ |
初始化和关闭、错误处理也比较重要,书本说得非常详细,请参考书本。
模块参数
测试程序:(加了moduleparam.h头文件)
01 | # #include<linux/init.h> |
02 | # #include<linux/module.h> |
03 | # #include<linux/moduleparam.h> |
04 | # MODULE_LICENSE("DualBSD/GPL"); |
05 | # static char *whom ="wishmiss"; |
06 | # static int howmany =3; |
07 | # module_param(howmany, int,S_IRUGO); |
08 | # module_param(whom, charp,S_IRUGO); |
09 | # static inthello_init(void) |
12 | # for (i = 0; i < howmany;i++) |
13 | # printk(KERN_ALERT "(%d) Hello, %s !\n", i,whom); |
16 | # static voidhello_exit(void) |
18 | # printk(KERN_ALERT "Goodbye, Linux.I will back later !%s",whom); |
20 | #module_init(hello_init); |
21 | #module_exit(hello_exit); |
编译,加载执行结果:
01 | 1. [birdb@wishmiss test]$make |
02 | 2. make -C/lib/modules/2.6.32.12-115.fc12.i686/buildM=/home/birdb/LDD3/misc-modules/hello/testmodules |
03 | 3. make[1]: Enteringdirectory`/usr/src/kernels/2.6.32.12-115.fc12.i686' |
04 | 4. CC [M] /home/birdb/LDD3/misc-modules/hello/test/test.o |
05 | 5. Building modules, stage2. |
07 | 7. CC /home/birdb/LDD3/misc-modules/hello/test/test.mod.o |
08 | 8. LD [M] /home/birdb/LDD3/misc-modules/hello/test/test.ko |
09 | 9. make[1]: Leavingdirectory`/usr/src/kernels/2.6.32.12-115.fc12.i686' |
10 | 10. [birdb@wishmiss test]$ sudo insmodtest.ko |
11 | 11. [birdb@wishmiss test]$ dmesg |tail-5 |
12 | 12. Hello, Linux.I amcoming! |
13 | 13. Goodbye, Linux. I will backlater. |
14 | 14. (0) Hello, wishmiss! |
15 | 15. (1) Hello, wishmiss! |
16 | 16. (2) Hello, wishmiss! |
17 | 17. [birdb@wishmiss test]$ sudo rmmodtest.ko |
18 | 18. [birdb@wishmiss test]$ dmesg |tail-5 |
19 | 19. Goodbye, Linux. I will backlater. |
20 | 20. (0) Hello, wishmiss! |
21 | 21. (1) Hello, wishmiss! |
22 | 22. (2) Hello, wishmiss! |
23 | 23. Goodbye, Linux.I will back later!wishmiss |
24 | 24. [birdb@wishmiss test] |
参数由加载的时候定义:
01 | 1. [birdb@wishmiss test]$ sudo insmod test.kowhom= "xxx" howmany=2 |
02 | 2. [birdb@wishmiss test]$dmesg |tail -5 |
05 | 5. Goodbye, Linux.I willback later !xxx |
08 | 8. [birdb@wishmiss test]$sudo rmmodtest.ko |
09 | 9. [birdb@wishmiss test]$dmesg |tail -5 |
11 | 11. Goodbye, Linux.I will back later!xxx |
14 | 14. Goodbye, Linux.I will back later!xxx |
15 | 15. [birdb@wishmiss test]$ |
具体的参数介绍请参考书本。
至此,第一个内核模块实验完成。