编写一个简单的可加载内核模块

前言:本文主要介绍了LKM的基本概念和如果配置编译环境,编译加载一个简单的LKM。适合linux初学者。

什么是可加载内核模块

可加载内核模块(Loadable Kernel Module,LKM允许在不重编译内核和重启系统的条件下对类Unix系统的系统内核进行修改和扩展.大多数的Unix派生系统,包括Linux,BSD,OSX等都支持这个特性.

本文着重描述编译执行一个”hello world”LKM的过程.相关的代码可以在这里下载.下面的命令和代码都在Ubuntu 11.10和12.10上测试通过了.在其他的Linux发行版上也许需要做一些细微的修改.

编写LKM的基本流程

1, 安装module-assistant包
2, 创建主文件hello.c和Makefile
3, 编译hello.c
4, 将编译好的模块插入到当前内核中
5, 测试完成后移除相关的内核模块

安装内核头文件等准备工作

Debian和Ubuntu都提供了moddule-assistant的包,包括了编写LKM需要的所有包.可以通过一下方式安装:

sudo -i
apt-get install module-assistant
m-a prepare

module-assistant做的事情并没有多么高端.它仅仅是一个安装内核源码包的工具.下面的命令也可以安装我们编译需要的l依赖包:

sudo apt-get install build-essential linux-headers-$(uname -r)

创建LKM源码文件和Makefile

这是一个hello world的源码…在本文提供的压缩包里有.作用是加载内核模块和卸载内核模块的时候输出一个hello world

// Defining __KERNEL__ and MODULE allows us to access kernel-level code not usually available to userspace programs. #undef __KERNEL__ #define __KERNEL__ #undef MODULE #define MODULE // Linux Kernel/LKM headers: module.h is needed by all modules and kernel.h is needed for KERN_INFO. #include <linux/module.h> // included for all kernel modules #include <linux/kernel.h> // included for KERN_INFO #include <linux/init.h> // included for __init and __exit macros static int __init hello_init(void) { printk(KERN_INFO "Hello world!\n"); return 0; // Non-zero return means that the module couldn't be loaded. } static void __exit hello_cleanup(void) { printk(KERN_INFO "Cleaning up module.\n"); } module_init(hello_init); module_exit(hello_cleanup);

Makefile的代码:

obj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd) all: $(MAKE) -C $(KDIR) M=$(PWD) modules
 
clean: $(MAKE) -C $(KDIR) M=$(PWD) clean

编译源码

到工作目录下执行make就可以了

$ make
make -C /lib/modules/3.0.0-17-generic/build M=/var/www/lkm modules
make[1]: Entering directory `/usr/src/linux-headers-3.0.0-17-generic' CC [M] /var/www/lkm/hello.o Building modules, stage 2. MODPOST 1 modules
CC /var/www/lkm/hello.mod.o
LD [M] /var/www/lkm/hello.ko

加载编译好的内核模块到内核

使用insmod命令:

sudo insmod hello.ko

我们使用了printk()函数.会在syslog中打印.用tail /var/log/syslog查看

$ tail /var/log/syslog <snip> Apr 20 16:27:39 laptop kernel: [19486.347191] Hello world!

有一些发行版,内核信息会记录到别的文件,比如/var/log/messages.这个也要看syslog的配置.

卸载模块

使用rmmod 命令

sudo rmmod hello

查看syslog,可以看到模块卸载时候的输出:

$ tail /var/log/syslog <snip> Apr 20 16:29:23 laptop kernel: [19486.347191] Cleaning up module.

恭喜!你已经成功创建并使用了一个可加载内核模块.

你可能感兴趣的:(编写一个简单的可加载内核模块)