实验五:添加内核模块
实验目的:学习模块,它是Linux特有的一种机制。模块可以用来动态地增加内核的功能。
5.1 介绍
Linux模块(module)是一些可以作为独立程序来编译(使用适当的标志说明这是内核代码)的函数和数据类型的集合。在装载这些模块时,将它的代码链接到内核中。Linux模块可以在内核启动过程时装载――这称为静态装载。它们也可以在内核运行的过程中装载,这称为动态装载。
Linux模块可以单独编译成为目标代码,module是一个目标文件。它可以根据需要在系统启动后动态地加载到系统核心之中。当module不再被需要时,可以动态地卸载出系统核心。Linux中大多数设备驱动程序或文件系统都作成的module。超级用户可以通过insmod和rmmod命令显示地将module载入核心或从核心中将它卸载。
核心也可在需要时,请求守护进程(kerneld)装载和卸载module。通过动态地将代码载入核心可以减小核心代码的规模,使核心配置更为灵活。若在调试新核心代码时采用module技术,用户不必每次修改后都需重新编译核心和启动系统。
5.2 模块的组织结构
一旦Linux module载入核心后,它就成为核心代码的一部分。它与其它核心代码的地位是相同的。module在需要的时可通过内核符号表(symbol table)使用核心资源。核心将资源登记在符号表中,当module装载时,核心利用符号表来解决module中资源引用的问题。Linux中允许module堆栈(module stacking),既一个module可请求其他module为之提供服务。当module装载入系统核心时,系统修改核心中的符号表,将新装载module 提供的资源和符号加到核心符号表中。通过这种通信机制,新载入的module可以访问已装载的module提供的资源。通过/proc/ksyms文件可以查看内核符号表中各类符号及其地址。
若某个module空闲,用户便可将它卸载出核心。在卸载之前,系统释放分配给该module的系统资源,如核心内存,中断等。同时系统将该module提供的符号从内核符号表中删除。
由于module 中代码与核心中其他部分代码的地位是相同的,module的代码错误会导致系统崩溃。而且module一般需要调用核心的资源,所以必须注意module的版本和核心的版本的相配问题。一般在module的装入过程中检查module的版本信息。
模块链接到内核的过程见图5.1。
图5.1 将模块链接到内核
因为模块不和函数库连接,所以在源文件中不能包含通常的头文件(为用户态编程而准备)。内核模块只能使用作为内核一部分的函数。和内核相关的的所有内容都在内核源代码(通常位于/usr/src/linux-2.4)的include目录下。
一个内核模块必须至少有两个功能: init_module 在该模块被插入内核时被调用, cleanup_module 仅仅在它被清除前调用。 典型的, init_module 要么在内核里为什么东西登记一个指针,要么用它自己的代码代替内核的某个功能 (通常那个代码做一些事情然后调用原始的功能). cleanup_module 功能被假定撤消init_module 做的任何事情, 因此模块可以被安全地卸载。