(原创)Linux 内核编译CentOS4.6+Linux2.6.9-67.EL
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 RPM,SPRAMS文件夹中存放着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目录下生成两个文件夹SOURCES和SPECS
# cd /usr/src/redhat/;ls
SOURCES SPECS
- SOURCES。SOURCES 存储源代码。
- SPECS。SPECS 包含spec 文件。
SOURCES目录下主要linux内核源码包linux-2.6.9.tar.bz2和1000多个patch文件及.config文件。
SPECS目录下包含kernel-2.6.spec文件
Spec文件可看作rpm工作的脚本文件。
它包含了软件包的诸多信息,如软件包的名字、版本、类别、说明摘要、创建时要执行什么指令、安装时要执行什么操作、以及软件包所要包含的文件列表等等。
它主要包括
- 文件头 包括软件包名,版本,开发者等
- %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目录下生成完整的内核源码树。
三、配置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选项,给自己编译的内核盖个戳。
把当前内核的配置文件拷贝到linux目下下重命名为.config
# cp /boot/config-`uname –r` .config
.config文件本应该用make menuconfig来生成,在本实验中,直接把当前内核的配置信息复制过来。就省去了make menuconfig的麻烦。
# make menuconfig
此处只是一个流程,选择默认,退出。
四、编译内核及内核模块
# make
这是最主要的一步。Makefile的编译流程,
- 使用命令行或者图形界面配置工具,对内核进行裁减,生成.config配置文件
- 保存内核版本信息到 include/linux/version.h
- 产生符号链接 include/asm,指向实际目录 include/asm-$(ARCH)
- 为最终目标文件的生成进行必要的准备工作
- 递归进入 /init 、/core、 /drivers、 /net、 /lib等目录和其中的子目录来编译生成所有的目标文件
- 链接上述过程产生的目标文件生成vmlinux,vmlinux存放在内核代码树的根目录下
- 最后根据 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内核不使用符号名,而是通过变量或函数的地址来识别变量或函数名. 符号表是所有符号连同它们的地址的列表。
关于initrd-2.6.9-lunix1.0.img文件
在/boot/grub/menu.lst中除了配置root,kernel还要配置initrd。Initrd指定系统启动访问真正的根文件系统前,访问的ramdisk映象。
initrd***.img把一段程序打包到img里,然后在开机的时候在内存里开辟一段区域,一般是2m,释放到那里运行,都是一些初始化的程序,比如sisc_mod、ext3、sd_mod等模块和insmod、nash等命令。不同内核,初始化的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,找到任何一个就执行它。整个的初始化从它开始。用file和cat命令查看一下
#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)设置为默认启动项。
重新启动reboot
启动菜单,多了2.6.9-lunix1.0
用自行编译的内核启动,输入uname –r显示
*1 显示操作过程中详细信息
*2 将新编译内核树中的模块(.ko)文件拷贝到/lib/modules/<version>下,并做模块相关性处理(depmod);此时不会做insmod操作