内核模块是Linux内核向外部提供的一个接口,其全称是动态可加载内核模块(Loadabkle Kernel Module,LKM)。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大优点是效率高,因为所有的内 容都集成在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。
一、什么是模块
模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或内核中其他上层功能。
二、编写一个简单的模块
模块和内核都在内核空间运行, 模块编程在一定意义上说就是内核编程。因为内核版本的每次变化,其中的某些函数名也会相应地发生变化,因此模块编程与内核版本密切相关。
第一个内核模块:
内核版本:2.6.31-4
在RedFlag 6.0测试通过
/*
* hellomod.c
* 第一个内核模块
* author:cm
* date:2010-3-28
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init lkp_init(void)
{
printk("<1>Hello,Kernel! from the kernel space...\n");
return 0;
}
static void __exit lkp_cleanup(void)
{
printk("<1>Goodbye,Kernel! leaving the space...\n");
}
module_init(lkp_init);
module_exit(lkp_cleanup);
MODULE_LICENSE("GPL");
说明:
8~10行 一些必要的头文件
所有模块都要使用头文件module.h,此文件必须包含进来。
头文件kernel.h包含了常用的内核函数。
头文件init.h包含了宏_init和_exit,它们允许释放内核占用的内存。
12~16行
这是模块的初始化函数,它必需包含诸如要编译的代码、初始化数据结构等内容
printk()函数 该函数是由内核定义的,功能与C库中的printf()类似,它把要打印的信息输出到终端或系统日志。字符串中的<1>是输出的级别,表示立即在终端输出。
18~21行
这是模块的退出和清理函数。此处可以做所有终止该驱动程序时相关的清理工作。
23~24行
函数module_init()和module_exit()是模块编程中最基本也是必须的两个函数。module_init()向内核注册模块所提供的新功能,而module_exit()注销由模块提供的功能。
module_init() 是驱动程序初始化的入口点。对于内置模块,内核在引导时调用该入口点;对于可加载模块则在该模块插入内核时才调用,在卸载模块时调用module_exit()函数。
25行
GNU公共许可证 (必须)
编译
编译工具:gcc make
Makefile文件:
- #Makefile2.6
- obj-m += hellomod.o #产生hellomod模块的目标文件
- CURRENT_PATH := $(shell pwd) #模块所在的当前路径
- LINUX_KERNEL := $(shell uname -r) #内核版本
- #内核源码的绝对路径 (RedFlag 6.0)
- LINUX_KERNEL_PATH := /usr/src/kernels/2.6.31-4-i686
- all:
- make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #编译模块
- clean:
- rm -rf *.mod.c *.o *.ko *.markers *.symvers *.order #清理
执行make命令,会自动生成模块相关文件(如 .o .ko文件)
插入模块到内核
[root@localhost module]# insmod hellomod.ko
成功插入后,可以通过dmesg命令查看这个模块所执行的显示内容
[root@localhost module]# dmesg
...
Hello,Kernel! from the kernel space...
卸载模块
[root@localhost module]# rmmod hellomod
再次执行dmesg 显示
Hello,Kernel! from the kernel space...
Goodbye,Kernel! leaving the space...
注:查看(dmesg)其实是看日志,只要是看日志的方法应该都是可以的比如:tail /var/log/messages