Linux加载 hello world模块

一、、hello world模块

代码:

view sourceprint?
 
  #include     
  #include     
  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
#include

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代码:

view sourceprint?
 
    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也可以简单地写成这样:

view sourceprint?
1 obj-m:=hello.o

 

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

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

view sourceprint?
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.  
6 6.   MODPOST 1modules  
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执行。

执行效果:

view sourceprint?
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头文件)

view sourceprint?
01 # #include  
02 # #include  
03 # #include  
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)  
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 voidhello_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);
编译,加载执行结果:
view sourceprint?
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.  
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]: 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]

参数由加载的时候定义:
view sourceprint?
01 1. [birdb@wishmiss test]$ sudo insmod test.kowhom="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 willback later !xxx  
06  6. (0) Hello, xxx!  
07  7. (1) Hello, xxx!  
08  8. [birdb@wishmiss test]$sudo rmmodtest.ko   
09  9. [birdb@wishmiss test]$dmesg |tail -5  
10 10. (1) Hello, xxx!  
11 11. Goodbye, Linux.I will back later!xxx  
12 12. (0) Hello, xxx!  
13 13. (1) Hello, xxx!  
14 14. Goodbye, Linux.I will back later!xxx  
15 15. [birdb@wishmiss test]$

 

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

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


你可能感兴趣的:(linux)