Linux 内核编译

来源:互联网 发布:电脑硬件检测软件 编辑:程序博客网 时间:2024/05/22 01:40

Linux 内核编译

环境 Vmware + CentOS4.6

一、下载Linux内核源码包

查看当前系统的linux内核版本

# uname –r

2.6.9-67.ELsmp

查看CentOS发行版版本

# cat /etc/redhat-release

CentOS release 4.6 (Final)

发行版版本信息一般保存在/etc/issue文件中,也可以用cat /etc/issue命令查看

Linux内核发布的网站是http://www.kernel.org,但需要打补丁。可到centos网站上,下载带CentOS补丁的rpm包。

rpm包有两种,

  • Source RPM.src.rpm)包含一个SPEC文件(.spec),源码包(.tar.gz, .tar.bz2),还有其它的一些源文件和补丁
  • Binary RPM.i386.rpm, .i686.rpm, .sparc64.rpm),包括一些已编译文件,文档,配置文件和pre/post install/uninstall的脚本。

此处要编译源文件,下载前者。

CentOS网站上找到相应的内核版本kernel-`uname -r`.src.rpm

RPMS文件夹中放着Binary RPMSPRAMS文件夹中存放着Source RPM文件。

下载http://vault.centos.org/4.6/apt/i386/SRPMS.os/kernel-2.6.9-67.EL.src.rpm到本地系统中。

二、安装Linux内核源码树

安装rpm

# rpm -ivh kernel-2.6.9-67.EL.src.rpm

-i安装,-v显示安装包的真实名称*1-h显示安装进度

主要是一个解压的过程。

/usr/src/redhat目录下生成两个文件夹SOURCESSPECS

# cd /usr/src/redhat/;ls

SOURCES  SPECS

  • SOURCESSOURCES 存储源代码。
  • SPECSSPECS 包含spec 文件

SOURCES目录下主要linux内核源码包linux-2.6.9.tar.bz21000多个patch文件及.config文件。

SPECS目录下包含kernel-2.6.spec文件

 

Spec文件可看作rpm工作的脚本文件。

image

spec文件规范

它包含了软件包的诸多信息,如软件包的名字、版本、类别、说明摘要、创建时要执行什么指令、安装时要执行什么操作、以及软件包所要包含的文件列表等等。

它主要包括

  • 文件头 包括软件包名,版本,开发者等
  • %prep 这个段是预处理段,通常用来执行一些解开源程序包的命令,为下一步的编译安装作准备。
  • %build 本段是建立段,所要执行的命令为生成软件包服务,如make 命令。
  • %install 本段是安装段,其中的命令在安装软件包时将执行,如make install命令。
  • %files 本段是文件段,用于定义软件包所包含的文件
  • %changelog 修改日志段

# cd /usr/src/SPECS

# rpmbuild -bp --target=`uname –m` kernel-2.6.spec

-bp build through %prep (unpack sources and apply patches) from <specfile>,<specfile>文件的%prep段开始建立(解开源码包并打补丁)。

-bp命令只执行%prep段,解压源码包并打补丁。

执行完这一步后将会在/usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9目录下生成完整的内核源码树。

image

三、配置Linux内核

linux-2.6.9目录链接到/usr/src/linux

# cd /usr/src/

# ln -s /usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9/ linux

切换到linux目录下

# cd /usr/src/linux

# vi Makefile

修改Makefile文件,修改EXTRAVERSION选项,给自己编译的内核盖个戳。

image

把当前内核的配置文件拷贝到linux目下下重命名为.config

# cp /boot/config-`uname r` .config

.config文件本应该用make menuconfig来生成,在本实验中,直接把当前内核的配置信息复制过来。就省去了make menuconfig的麻烦。

# make menuconfig

此处只是一个流程,选择默认,退出。

image

四、编译内核及内核模块

# make

这是最主要的一步。Makefile的编译流程,

  • 使用命令行或者图形界面配置工具,对内核进行裁减,生成.config配置文件
  • 保存内核版本信息到 include/linux/version.h
  • 产生符号链接 include/asm,指向实际目录 include/asm-$(ARCH)
  • 为最终目标文件的生成进行必要的准备工作
  • 递归进入 /init /core /drivers /net /lib等目录和其中的子目录来编译生成所有的目标文件
  • 链接上述过程产生的目标文件生成vmlinuxvmlinux存放在内核代码树的根目录下
  • 最后根据 arch/$(ARCH)/Makefile文件定义的后期编译的处理规则建立最终的映象bootimage,包括创建引导记录、准备initrd映象和相关处理

五、安装内核

Insert内核模块,理解是,很多的insmod操作*2

# make modules_install

安装内核

# make install

boot目录下多出了以下文件

vmlinuz-2.6.9-lunix1.0是可引导的、压缩的内核。

System.map-2.6.9-lunix1.0内核符号表, Linux内核不使用符号名,而是通过变量或函数的地址来识别变量或函数名. 符号表是所有符号连同它们的地址的列表。

image

关于initrd-2.6.9-lunix1.0.img文件

/boot/grub/menu.lst中除了配置rootkernel还要配置initrdInitrd指定系统启动访问真正的根文件系统前,访问的ramdisk映象。

initrd***.img把一段程序打包到img里,然后在开机的时候在内存里开辟一段区域,一般是2m,释放到那里运行,都是一些初始化的程序,比如sisc_modext3sd_mod等模块和insmodnash等命令。不同内核,初始化的img可以相同,也可以不同,如果没有,可以在grub.conf里加上no initrd,它就跳过initrd的检测和执行了。

它的作用是在没有mount /分区以前,系统要执行一些操作,比如挂载scsi驱动,它就把initrd释放到内存里,作一个虚拟的/

现在解压initrd,并查看里面的文件

# mkdir initrd

# cd initrd/

# cp /boot/initrd-2.6.9-lunix1.0.img initrd.gz

# gunzip initrd.gz

# cpio -ivmd < initrd

# ls

bin  dev  etc  init  initrd  lib  loopfs  proc  sbin  sys  sysroot

initrd目录中就是系统启动时临时root的内容。目录下有一个init文件,该文件最为重要,它就是内核启动后执行的第一个脚本。实际上内核启动后寻找的就是/init ; bin/init ;/bin/init,找到任何一个就执行它。整个的初始化从它开始。用filecat命令查看一下

#file init

init: a /bin/nash script text executable

# cat init

#!/bin/nash

 

mount -t proc /proc /proc

setquiet

echo Mounted /proc filesystem

echo Mounting sysfs

mount -t sysfs none /sys

echo Creating /dev

mount -o mode=0755 -t tmpfs none /dev

mknod /dev/console c 5 1

mknod /dev/null c 1 3

mknod /dev/zero c 1 5

mkdir /dev/pts

mkdir /dev/shm

echo Starting udev

/sbin/udevstart

echo -n "/sbin/hotplug" > /proc/sys/kernel/hotplug

echo "Loading scsi_mod.ko module"

insmod /lib/scsi_mod.ko

echo "Loading sd_mod.ko module"

insmod /lib/sd_mod.ko

echo "Loading mptbase.ko module"

insmod /lib/mptbase.ko

echo "Loading mptscsi.ko module"

insmod /lib/mptscsi.ko

echo "Loading mptspi.ko module"

insmod /lib/mptspi.ko

echo "Loading mptsas.ko module"

insmod /lib/mptsas.ko

echo "Loading mptscsih.ko module"

insmod /lib/mptscsih.ko

echo "Loading libata.ko module"

insmod /lib/libata.ko

echo "Loading ata_piix.ko module"

insmod /lib/ata_piix.ko

echo "Loading jbd.ko module"

insmod /lib/jbd.ko

echo "Loading ext3.ko module"

insmod /lib/ext3.ko

/sbin/udevstart

echo Creating root device

mkrootdev /dev/root

umount /sys

echo Mounting root filesystem

mount -o defaults --ro -t ext3 /dev/root /sysroot

mount -t tmpfs --bind /dev /sysroot/dev

echo Switching to new root

switchroot /sysroot

umount /initrd/dev

第一行#!/bin/nash是一个redhat自己的微型解释器。不是bash

它的主要流程是

mount命令加载各种内核文件系统proc,sys

mknod创建系统启动所必须的/dev设备节点。

insmod开始安装scsi等设备。

udevstart 开始监听这些设备

 

mkrootdev 使它后面的参数/dev/root成为一个块节点从而使得根分区设备被挂载,其中根分区设备由grub.conf里面的kernel命令后面所带的参数root=决定。

 

mount -o defaults --ro -t ext3 /dev/root /sysroot

加载/dev/root/sysroot下。这时真正的root才被加载到了系统中。至此/sysroot下是真正的root分区。/initrd的内存盘。

switchroot 切换到新的root,卸载/dev,/proc,/sys文件系统,寻找新的init

六、启动新内核

查看/boot/grub/menu.lst文件,多了title CentOS(2.6.9-lunix1.0)设置为默认启动项。

image

重新启动reboot

 

启动菜单,多了2.6.9-lunix1.0

image

用自行编译的内核启动,输入uname –r显示

image

*1 显示操作过程中详细信息

*2 将新编译内核树中的模块(.ko)文件拷贝到/lib/modules/<version>下,并做模块相关性处理(depmod);此时不会做insmod操作