LDD3学习笔记(一) --hello world模块

文章出处http://www.cnblogs.com/wishmiss/archive/2010/09/21/1832827.html

 

LDD3学习笔记(一) --hello world模块

一、设置系统。

我的系统环境:

系统:fedora12

内核:2.6.32.12-115.fc12.i686

把 kernel-headers   kernel-devel装上。kernel-headers-2.6.32.12-115.fc12.i686  kernel-devel-2.6.32.12-115.fc12.i686

说明:书上说构建一个内核源代码树,我不明白到底是什么意思。我把kernel-headers kernel-devel装上后,编译了两个模块,发现都可以通过。其实编写内核模块只需要kernel-headers 和kernel-devel应该就足够了,这个是我自己理解的,不知道正确与否,如理解不对,请指正。

说白了,编写内核模块必须要有内核头文件(不以C头文件)以及内核源码树下的各个kbiuld makefile文件,如果这些东西都有了,那就OK了。安装这些东西可能就是书上说的构建内核源代码树吧。

二、hello world模块

代码:

011. #include <linux/init.h>  
02 2. #include <linux/module.h>  
03 3. MODULE_LICENSE("Dual BSD/GPL");  
04 4. static int hello_init(void)  
05 5. {  
06 6.         printk(KERN_ALERT "Hello, Linux.I am coming!/n");  
07 7.         return 0;  
08 8. }  
09 9. static void hello_exit(void)  
1010. {  
1111.         printk(KERN_ALERT "Goodbye, Linux. I will back later./n");  
1212. }  
1313. module_init (hello_init);  
1414. module_exit (hello_exit);

 

说明:

#include <linux/init.h>
#include <linux/module.h>

init.h包含初始化和清除函数。module.h包含有可装载模块需要的大量符号和函数的定义。

尽管不是严格要求,但模块应该指定代码所使用的许可证。内核能够识别的许可证有:“GPL”、“GPL v2”、“GPL and additional rights"、“Dual BSD/GPL"、“GPL MPL/GPL”、“Proprietary”。在我们的模块里我们用“Dual BSD/GPL”

MODULE_LICENSE("Dual BSD/GPL");            // MODULE_LICENSE是一个宏,用来告诉内核模块采用许可证类型。

模块定义了两个函数:static int hello_init(void)  static void hello_exit(void)。模块被装载时调用hello_init,模块被移除时调用hello_exit。

这里用到了一个内核函数:prinfk。内核运行时不信赖于C库,内核模块只能调用内核导出的函数。

三、编译和装载

编译模块

makefile代码:

010. ifneq ($(KERNELRELEASE),)  
02 1.         obj-m := helloworld.o  
03 2. else  
04 3.         KERNELDIR ?=/lib/modules/$(shell uname -r)/build  
05 4.         PWD := $(shell pwd)  
06 5. default:  
07 6.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
08 7. endif  
09 8. .PHONY: clean  
10 9. clean:  
1110.         -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/build M=/home/birdb/LDD3/misc-modules/hello modules,紧接着执行展开后的表达式。-C改变路径到内核源代码,找到内核顶层Makefile,M变量就是模块源代码目录,主要是为了让内核顶层的Makefile包含模块源代码目录下的makefile,包含以后获取obj-m:=hello.o因为内核顶层Makefile定义了KERNELRELEASE。书上说模块源代码目录下的makefile被读取两次,第一次就是执行make的时候,第二次是被包含进内核顶层Makefile的时候。

makefile也可以简单地写成这样:

1obj-m:=hello.o

 

但是不能再简单地执行:make,而应该写成:make -C 内核源代码目录 M=`pwd` modules

在我的系统上运行的结果是:

11. [birdb@wishmiss hello]$ make  
22. make -C /lib/modules/2.6.32.12-115.fc12.i686/build M=/home/birdb/LDD3/misc-modules/hello modules  
33. make[1]: Entering directory `/usr/src/kernels/2.6.32.12-115.fc12.i686'  
44.   CC [M]  /home/birdb/LDD3/misc-modules/hello/helloworld.o  
55.   Building modules, stage 2.  
66.   MODPOST 1 modules  
77.   CC      /home/birdb/LDD3/misc-modules/hello/helloworld.mod.o  
88.   LD [M]  /home/birdb/LDD3/misc-modules/hello/helloworld.ko  
99. make[1]: Leaving directory `/usr/src/kernels/2.6.32.12-115.fc12.i686'

 

编译成功,接下来就是加载模块。

加载和卸载模块

内核模块加载、卸载的命令分别是:insmod  rmmod。加载还可以用modprobe,不过我不会用,也没研究。两个命令都需要用root执行。

执行效果:

11. [birdb@wishmiss hello]$ sudo insmod helloworld.ko;sudo rmmod helloworld.ko  
22. [birdb@wishmiss hello]$ dmesg |tail -2  
33. Hello, Linux.I am coming!  
44. Goodbye, Linux. I will back later.  
55. [birdb@wishmiss hello]$

 

初始化和关闭、错误处理也比较重要,书本说得非常详细,请参考书本。

模块参数

测试程序:(加了moduleparam.h头文件)

01# #include <linux/init.h>  
02# #include <linux/module.h>  
03# #include <linux/moduleparam.h>  
04# MODULE_LICENSE("Dual BSD/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 int hello_init(void)  
10# {  
11#     int i;  
12#     for (i = 0; i < howmany; i++)  
13#         printk(KERN_ALERT "(%d) Hello, %s !/n", i, whom);  
14#     return 0;  
15# }  
16# static void hello_exit(void)  
17# {  
18#     printk(KERN_ALERT "Goodbye, Linux.I will back later !%s", whom);  
19# }  
20# module_init(hello_init);  
21# module_exit(hello_exit);
编译,加载执行结果:
011. [birdb@wishmiss test]$ make  
02 2. make -C /lib/modules/2.6.32.12-115.fc12.i686/build M=/home/birdb/LDD3/misc-modules/hello/test modules  
03 3. make[1]: Entering directory `/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, stage 2.  
06 6.   MODPOST 1 modules  
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]: Leaving directory `/usr/src/kernels/2.6.32.12-115.fc12.i686'  
1010. [birdb@wishmiss test]$ sudo insmod test.ko   
1111. [birdb@wishmiss test]$ dmesg |tail -5  
1212. Hello, Linux.I am coming!  
1313. Goodbye, Linux. I will back later.  
1414. (0) Hello, wishmiss !  
1515. (1) Hello, wishmiss !  
1616. (2) Hello, wishmiss !  
1717. [birdb@wishmiss test]$ sudo rmmod test.ko  
1818. [birdb@wishmiss test]$ dmesg |tail -5  
1919. Goodbye, Linux. I will back later.  
2020. (0) Hello, wishmiss !  
2121. (1) Hello, wishmiss !  
2222. (2) Hello, wishmiss !  
2323. Goodbye, Linux.I will back later !wishmiss  
2424. [birdb@wishmiss test]
参数由加载的时候定义:
011. [birdb@wishmiss test]$ sudo insmod test.ko whom="xxx"  howmany=2  
02 2. [birdb@wishmiss test]$ dmesg |tail -5  
03 3. (0) Hello, xxx !  
04 4. (1) Hello, xxx !  
05 5. Goodbye, Linux.I will back later !xxx  
06 6. (0) Hello, xxx !  
07 7. (1) Hello, xxx !  
08 8. [birdb@wishmiss test]$ sudo rmmod test.ko   
09 9. [birdb@wishmiss test]$ dmesg |tail -5  
1010. (1) Hello, xxx !  
1111. Goodbye, Linux.I will back later !xxx  
1212. (0) Hello, xxx !  
1313. (1) Hello, xxx !  
1414. Goodbye, Linux.I will back later !xxx  
1515. [birdb@wishmiss test]$

 

具体的参数介绍请参考书本。

至此,第一个内核模块实验完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值