新博客:http://sparkandshine.net/
分类: LINUX
2011-06-08 17:33:04
摘要:
有时需要编译低版本内核,但往往高版本Linux发行版无法编译低版本内核,所以采用相应发行版来编译相应版本内核。本文在Ubuntu 6.06LTS(2.6.15)编译2.6.16(为了修改O(1)调度)。并记录了全过程。
最近因实验需要,需修改O(1)调度算法,鉴于2.6.16以后(不包括2.6.16)的版本不采用O(1)调度而是公平调度,这就要求编译出2.6.16以前的内核。
第一次编译内核,生怕把原系统搞崩溃,遂采用VMware+SecureCRT。首先得解决VMware下Ubuntu与XP共享数据,方法有很多。我觉得SecureCRT更好用,为了让Ubuntu更好支持CRT,需要在Ubuntu安装openssh-server、lrzsz,如下:(这样就可以在CRT通过sz、rz与Ubuntu实现数据传输)
is a FREE version of the SSH connectivity tools that technical users of the Internet rely on.
is a unix communication package providing the XMODEM, YMODEM ZMODEM file transfer protocols.
一、过高版本内核无法编通低版本
最初的想法,是用实验室服务器Ubuntu 9.10(2.6.31)编译2.6.16,结果出现如下错误:
网上有解释,说编译工具版本太新不适合编译旧版本,删除现有工具,安装合适版本编译工具。(这点我理解并不深,如果你知道,请你务必告诉我)如何界定“合适”?这个好办,你解压待编译的内核源码,打开linux-2.6.16/Documentation/Changes文件,内有关于版本说明,如下:(可以比下图给出版本稍高点,总之,版本不能太高也不能太低)
那好,更换编译工具版本可以编译通过,但问题又来了。编译好的未必能运行的起来(我同学试过,把原的内核版本跑飞了),这点还是很容易理解,支持系统运行的一些接口在旧版本内核没有得到实现。
二、用稍低版本编译2.6.16
很自然就想到,用恰是2.6.16版本内核的Ubuntu或稍低版本编译2.6.16内核来完成该实验。我同学GOOGLE,找到Ubuntu 6.06LTS(内核版本2.6.15)。以下简述各步骤:(事实上linux-2.6.16/README文件已经告知)因为整个过程都需要管理者权限,通过命令sudo -s切换到root权限。
1、下载内核源码
地址并解压bzip2 -dc linux-2.6.16.tar.bz2 | tar xvf - (因Ubuntu 6.06没有默认安装gcc、make工具,直接通过apt-get install安装即可)
2、安装编译内核实用工具
在配置内核之前,需要安装若干编译内核实用工具,主要如下:
build-essential—— ubuntu提供了build-essential包让一次把相关软件安装(基本的编程库,gcc, make等)
查看哪些包被 build-essential依赖用命令:apt-cache depends build-essential
kernel-package ——系统里生成 kernel-image 的一些配置文件和工具
libncurses5-dev——meke menuconfig要调用的
libqt3-headers ——qt库,make xconfig要调用的
3、配置内核
有5种方式配置(README文件有说明),我采用make menuconfig,回车YES。如果需要对比更改后内核与更改前内核的一些性能指标(事实上,这点很常用),可以通过选择General setup——>Local version在内核版本后面加上自定义的版本字符串加已区分,比如在Local version分别设为original、modified。
4、编译内核
就一个命令:make(可以带-jN选项,使N个进程并行编译),在虚拟机下做奇慢无比,可以考虑晚上挂机编译。第二次编译就快很多了(Makefile的精髓)。如果需要清除所有旧的配置和旧的编译目标等文件,用make mrproper命令。
5、把模块编译进内核
用命令make modules_install把模块编译进内核,编译好的模块默认路径为/lib/modules/2.6.16(如果你前面配置了Local vision,会在版本号加上original、modified加以区分同一内核版本不同修改版本)
6、安装内核
通过命令make install把内核代码树中生成的内核镜像拷贝到系统/boot路径中,同时生成内核启动所需文件,但此时还没更新grub引导文件
7、制作内核引导文件
initrd.img.*为了在initramfs中添加指定kernel的驱动模块,内核模块需要创建initramfs的kernel版本号。(在Fedora下面一般是用mkinitrd,而在Ubuntu/Debian下是用mkintramfs)通过如下命令,mkinitramfs会把/lib/modules/2.6.16/目录下的一些启动时用到的模块加到initramfs中。
is a root filesystem which is embedded into the kernel and loaded at an early stage of the boot process.
附:
内核引导文件initrd.img简介initrd = init ramdisk,是一个启动时存在于内存的文件系统。 initrd的最初的目的是为了把kernel的启动分成两个阶段:在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的 方式放在 initrd中,这样就在启动过程中可以从initrd所mount的根文件系统中装载需要的模块。这样的一个好处就是在保持kernel不变的情况下, 通过修改initrd中的内容就可以灵活的支持不同的硬件。在启动完成的最后阶段,根文件系统可以重新mount到其他设备上。(此段引自)
8、更新grub引导文件
可以直接手动修改(vim /boot/grub/menu.lst),建议先用命令update-grub自动更新menu.lst再人工确认,主要得确认下图中initrd是否自动写入(我的就没补上)。若无,手动补上。
9、重启reboot
重启虚拟机,按ESC进入启动项选择:
选择所编译的版本进入系统,看是否能正常启动,并用uname –r观察内核版本。
三、常见问题
1、rebooot无法进入系统
提示Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0),这大多是menu.lst没设置好。
解决:
重启系统,选择没修改过的内核版本(如Ubuntu 6.06自带的2.6.15)进入系统,检查menu.lst文件(可以再update-grub下)
2、高版本内核无法编译低版本内核
正如上文所说,编译工具太新了,建议用适当的发行版编译内核。同理,如果低版本无法编译高版本,则需考虑是否应该升级相应工具。
最后,感谢小强同学悉心的指导。
主要参考:
[1].博文:《linux2.6.16内核在ubuntu下的编译和启动》
[3].Robert Love.Linux内核设计与实现.