LDD3构建内核树

时间:2021-09-01 04:01:45
作者:胡乃全

写在前面

作者一直支持GPL的精神。允许任何人*使用、转载、复制和再分发,但必须保留作者署名,必须保证全文完整转载,包括完整的版权声明。

由于作者水平有限,因此不能保证文章内容准确无误,请批判阅读。如果你发现任何错误或对文章内容有任何建议,欢迎你与我联系:
Email:
 hunaiquan@126.com 

为什么要构建内核树

在《LDD3》的第二章P21,有以下一段话:

“不管内核来自哪里,想要为2.6.x内核构造模块,还必须在自己的系统中配置并构造好内核树。这一要求和先前版本的内核不同,先前的内核只要有一套内核头文件 就够了。但因为2.6内核的模块要和内核源代码树中的文件连接,通过这种方式,可得到一个更加健壮的模块装载器,但也需要这些目标文件存在于内核目录树 中。这样,读者首先要准备好一个内核源代码树。”

这段话说出了2.4和2.6两种版本的驱动模块的编写的一个不同之处。我使用到是ubnutu,所以下面我将以ubuntu为例来构建内核树。如果你安装到是ubuntu 10.04或者是11.04的话,默认已经安装来内核树,可以到  /lib/modules/$(uname -r)/build查看 。如果没有,就需要重新构建。

1.安装编译内核所需要的软件

$sudo apt-get install build-essential kernel-package libncurses5-dev

libncurses5这个软件包在使用menuconfig配置内核的时候会用到。


2.下载内核源码

先查看linux内核版本:$uname -r

然后用apt-cache search linux-source命令, 会列出一些可选源码包,对准你的内核版本号,选择“with Ubuntu patche”的那个,最后用apt-get install linux-source-2.6.38.8下载之(或者直接去www.kernel.org下载)。解压缩源码包:

[eric@eric-Computer:src$] sudo tar jxvf linux-source-2.6.38.tar.bz2 

进入解压后的源码目录:

[eric@eric-Computer:src$] cd linux-source-2.6.38/

3.配置内核

在编译之前我们需要Ubuntu原来内核的一个配置文件,这是我/usr/src目录下的文件预览:ls -al

drwxr-xr-x  4 root root     4096 2010-09-04 21:31 fglrx-8.723.1
drwxr-xr-x 24 root root     4096 2010-09-04 20:35 linux-headers-2.6.38-8
drwxr-xr-x  7 root root     4096 2010-09-04 20:35 linux-headers-2.6.38-8-generic
drwxr-xr-x 25 root root     4096 2010-09-16 21:39 linux-source-2.6.38.8
-rw-r--r--  1 root root 65846876 2010-09-01 22:41 linux-source-2.6.38-8.tar.bz2

如果你使用原先系统的配置(默认配置),可执行一下步骤:

[eric@eric-Computer:linux-source-2.6.38$] sudo make oldconfig

当然你也可以使用 自己喜欢的配置方式 如 menuconfig , xconfig

4.编译内核

接下来我们就要开始编译了。

[eric@eric-Computer:linux-source-2.6.38$] sudo make

(记住一定要是管理员帐号运行,这个过程很久,如果你的cpu是双核的可以在make后面加个参数,make -j4.)

[eric@eric-Computer:linux-source-2.6.38$] sudo make bzImage
(注意,I要大写。执行结束后,可以看到在当前目录下生成了一个新的文件: vmlinux, 其属性为-rwxr-xr-x。 )
# make install 

#make modules (编译 模块 )

#make modules_install  

(这条命令能在/lib/modules目录下产生一个目录)

重启电脑,grup menu中就出现了新内核选项

5.使用hello模块测试内核

如果一切顺利,编译过程中不出现什么错误的话,接下来我们就可以编写最简单的linux模块——helloworld了。

在某一目录下创建2个文件:hello.c和Makefile

hello.c 内容如下:

  1. /* 
  2.  * $Id: hello.c,v 1.5 2011/06/21 03:32:21 eric $ 
  3.  */ 
  4. #include <linux/init.h>
  5. #include <linux/module.h>
  6. MODULE_LICENSE("Dual BSD/GPL");

  7. static int hello_init(void)
  8. {
  9.         printk(KERN_ALERT "Hello, world\n");
  10.         return 0;
  11. }

  12. static void hello_exit(void)
  13. {
  14.         printk(KERN_ALERT "Goodbye, cruel world\n");
  15. }

  16. module_init(hello_init);
  17. module_exit(hello_exit);

Makefile内容如下:

  1. To build modules outside of the kernel tree, we run "make"
  2. in the kernel source tree; the Makefile these then includes this
  3. # Makefile once again.
  4. # This conditional selects whether we are being included from the
  5. # kernel Makefile or not.
  6. ifeq ($(KERNELRELEASE),)

  7.     # Assume the source tree is where the running kernel was built
  8.     # You should set KERNELDIR in the environment if it's elsewhere
  9.     KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  10.     # The current directory is passed to sub-makes as argument
  11.     PWD := $(shell pwd)

  12. modules:
  13.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

  14. modules_install:
  15.         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

  16. clean:
  17.         rm -rf *.*~ core .depend .*.cmd *.ko *.mod..tmp_versions

  18. .PHONY: modules modules_install clean

  19. else
  20.     # called from kernel build system: just declare what our modules are
  21.     obj-:= hello.o
  22. endif

需要注意的是Makefile的格式要正确。

然后编译:

$ make 

不出现错误的话,用ls -al查看该目录,会产生如下文件:
hello.c   hello.mod.c  hello.o   modules.order
hello.ko  hello.mod.o  Makefile  Module.symvers


现在我们就可以将编译好的模块hello加载到内核中去了

$ sudo insmod ./hello.ko   //这个命令把hello.ko加载到内核

$ sudo lsmod|grep hello   //lsmod 这个命令可以查看当前所有的驱动模块,结果应该显示hello 680 0

$ sudo rmmod hello         //这个命令是把hello这个模块移除掉


程序的输出结果可以在
/var/log/syslog文件中查看

Hello,World
Goodbye,cruel world

这是程序的输出。