从linux内核说起~模块篇(四)

这一节主要内容讲解linux内核的模块机制。主要参考经典书籍《linux device drivers》。

 

①    大多数小规模及中规模的应用程序从头到尾执行单个任务,而模块却只是预先注册自己一边服务于将来的某个请求,然后他的初始化函数就立即结束了。

模块仅仅被链接到内核,因此它能调用的函数仅仅是由内核导出的那些函数,而不存在任何可链接的函数库。所以源文件不能包含常用的头文件。内核模块只能使用作为内核一部分的函数。大多数相关的头文件保存在内核源码树的(/home/sml/linux2.6.37.4/)头文件声明里,include/linux和include/asm目录中。

②    最简单的模块构造(helloworld)

1.     在虚拟机上面创建hello.c和Makefile。

2.     Hello.c源代码如下:

#include <linux/module.h>

#include <linux/init.h>

#include <linux/sched.h>

#include <linux/kernel.h>

MODULE_LICENSE("GPL");

 

static int hello_init(void)

{

       printk(KERN_EMERG "hello world!\n");

       return 0 ;

}

 

static void hello_exit(void)

{

       printk(KERN_EMERG "crule world!\n");

}

module_init(hello_init);

module_exit(hello_exit);

3. makefile文件内容

obj-m := hello.o

4. 虚拟机上必须要有内核源码树,我的在/home/sml/linux2.6.37.4,因为我们构造的模块最终要运行的linux2.6.37.4内核上面,所以要在内核源码树下面编译模块。执行make -C/home/sml/linux2.6.37.4 M=$PWD modules.

root@sml-VirtualBox:/home/sml/nfs_server#make -C /home/sml/linux-2.6.37.4 M=$PWD modules

make:进入目录'/home/sml/linux-2.6.37.4'

  CC[M]  /home/sml/nfs_server/hello.o

  Buildingmodules, stage 2.

  MODPOST 1modules

  CC      /home/sml/nfs_server/hello.mod.o

  LD[M]  /home/sml/nfs_server/hello.ko

make:离开目录“/home/sml/linux-2.6.37.4”

执行完命令,生成hello.ko模块。

5. make-C /home/sml/linux2.6.37.4 M=$PWD modules解析。

前面讲到,模块依赖于内核导出的一些符号,主要的头文件声明在include/linux和include/asm目录下。所以编译模块肯定要依赖于内核源码树。-C 表示make切换到指定目录。M是makefile中的一个变量,指定为当前目录,也就是hello.c 的所在目录。Modules指向obj-m变量中设定的模块,就是hello模块。因为在hello.c的Makefile中没有指定内核源码树的目录,所以-C来告诉make内核源码树的路径。(这个地方理解的不是很透彻,但是我们要明白:内核模块的编译是依赖于内核源码树的。)。

6. 模块的装载和卸载

装载命令:insmod;卸载命令:rmmod;查看模块命令:lsmod;查看模块信息:modinfo;

我们把上面的编译的模块放在根文件系统上面,然后执行装载命令,即可看到我们要打印的信息。如何放在开发板的根文件系统上,请参见:NFS实现开发板和虚拟机之间的文件共享。Make工具的使用方法请参见:MAKE工具介绍

③    内核符号表(模块层叠技术)

Insmod使用公共内核符号表来解析模块中未定义的符号。公共内核符号表中包含了所有的全局内核项(变量和函数)的地址,这是实现模块化驱动程序的必须的。当模块被装入内核后,它所导出的任何符号都会成为内核符号表的一部分。新模块可以使用有我们自己的模块导出的符号。这样我们可以在其他模块上层叠新的模块(模块层叠技术)。符号导出实现模块之间的资源共享。驱动程序的模块层叠可以理解为抽象层为硬件驱动层提供符号,抽象层和硬件驱动层就相当于两个(或多个)模块。我们可以将模块划分为多个层,缩短开发时间。

符号导出方法:

                       EXPORT_SYMBOL(name);

                       EXPORT_SYMBOL_GPL(name);

④    初始化和关闭

module_init(hello_init);

module_exit(hello_exit);

初始化和关闭是强制性的,是模块被insmod和rmmod时执行的。

⑤    模块的参数

内核允许驱动程序指定参数,而这些参数可以在装载驱动程序模块时改变。驱动程序参数包括设备编号,以及一些其他的控制驱动程序操作方式的参数。如:

insmod hellop howmany=10 whom=”sml”

在模块中,参数的申请方法,包含头文件

#include <moduleparam.h>

格式为:

Module_param(name,type,s perm);

如:

Module_param(howmany,int,S_IRUGO);

S_IRUGO表示任何人可读取参数,但是不能更改;

S_IRUGO|S_IWUSR表示允许root用户修改该参数。大多数情况下,我们不应该让模块参数可写。

posted @ 2013-05-26 22:58  javawebsoa  Views(219)  Comments(0Edit  收藏  举报