编写模块
经过一个工作周的摸索,已经能够搭建起内核测试环境了。今天又把模块测试环境搭建好了。
搭建模块开发过程中也遇到了很多问题,这里做一个概览性的描述。
1. 内核源码准备
不同于运行在用户态的一般程序,编写 Linux 下的内核程序时,需要引入内核文件。故编写的第一步就是准备内核源码。这几年发行的 Distribution 往往都不在光盘提供,都需要单独下载。同样两大发行版安装源码的方式也有所不同。RedHat 系列需要下载相应的 src*.rpm 源码包进行安装后即可在 /usr/src 中看到源码压缩包。而 Debian 系列可以使用
apt-get install linux-source
获取源码,同样对应的源码包也存放在了 /usr/src 目录。下面的步骤两个版本上的操作就基本没有区别了。
1) 解压源码
tar -jxvf linux-source
2) 准备 .config 文件
关于这个文件的作用在这里也有过描述。随后拷贝 /boot/config-* 文件到 linux-source 目录中。
3) 执行 make oldconfig
make oldconfig
依据本机原有的 .config 文件对当前的源码进行配置设定。
4) make prepare
make prepare
5) make scripts
make scripts
6) 修改源码 Makefile 文件
修改 Makefile 前四行的内容,使其与 /lib/modules/`uname -r`/build/ 中的内容保持一致。
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 32
EXTRAVERSION = .15+drm33.5
2. 创建 /usr/src/linux 链接
通常默认情况下会使用 /usr/src/linux 作为源码的存放目录,但为了灵活起见,也为了多内核操作的方便,通常是创建一个链接指向 /usr/src/linux 目录。
ln -s /usr/src/linux-source /usr/src/linux
3. 第一个内核 demo
/* hello.c – Our First Driver code */#
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
static int __init ofd_init(void) /* Constructor */
{
printk(KERN_INFO "kysnail: hello registered");
return 0;
}
static void __exit ofd_exit(void) /* Destructor */
{
printk(KERN_INFO "kysnail: hello unregistered");
}
module_init(ofd_init);
module_exit(ofd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kysnail@gmail.com");
对应的 Makefile
# Makefile – makefile of our first driver
# if KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq (${KERNELRELEASE},)
hello-m := hello.o
# Otherwise we were called directly from the command line.
# Invoke the kernel build system.
else
KERNEL_SOURCE := /usr/src/linux
PWD := $(shell pwd)
default:
${MAKE} -C ${KERNEL_SOURCE} SUBDIRS=${PWD} modules
clean:
${MAKE} -C ${KERNEL_SOURCE} SUBDIRS=${PWD} clean
endif
4. 内核载入、卸载测试。
sudo insmod hello.ko
sudo rmmod hello
sudo lsmod | grep hello
tail -f /var/log/messages # 动态追踪 /var/log/messages 文件