一,什么是BabyLinux
二,为什么要做这样一个linux
三,什么人适合读这篇文档
四,应该具备的知识
五,linux系统引导过程简介
六,编译内核
七,编译busybox
八,制作根文件系统
九,制作ramdisk映象文件
十,内核与busybox的整合
十一,安装测试和内容调整
十二,babylinux中的BUG
十三,接下来要做的事情
十四,参考文献
一,什么是BabyLinux
BabyLinux 不是一个完整的发行版,他是利用原有的一套完整的linux系统的内核原代码和编译工具,利用busybox内建的强大功能,在一张软盘上做的一个很小的 linux系统.他具备一个linux系统的基本特征,支持linux系统最常用的一百多个命令,支持多种文件系统,支持网络等等,你可以把他当做一张 linux起动盘和修复盘来用,你也可以把他当做一个静态路由的路由器软件,当然,你也可以把他当做一个linux玩具,向你的朋友炫耀 linux可以做的多么小.我把他叫做BabyLinux因为他很小巧,小的很可爱,像一个刚刚出生的小baby.
二,为什么要作这样一个linux
先说说我一开始的想法,当我一开始接触linux的时候,看到书上说,linux通常安装只需要60M左右的空间,但是我发现装在我硬盘上的Redhat 6.0确要占据好几百M的空间.为什么我的linux这么大呢? 后来我发现,装在我机器上的那么多东西只有不到30%是我平时常用的,还有30%是我极少用到的,另外的40%基本上是不用的.于是,我和大多数初学者一样,开始抱怨,为什么linux不能做的精简一点呢?于是,我萌发了自己裁减系统的想法.可惜那个时候我还没有听说过有LFS和Debain.等到我积累了足够的linux知识后,我开始制作这样一个小系统.
制作这样一个小系统最大的意义在于,你可以通过制作系统了解linux的启动过程,学会 ramdisk的使用,让你在短时间内学到更多的linux知识. 当然,你会得到很大的乐趣.这个项目只是做一个具有基本特征的linux系统,如果你想自己做一个具有完整功能的linux,请阅读Linux From Scratch (LFS)文档.
三,什么人适合读这篇文档
如果你是一个linux爱好者,并且很想了解 linux的启动过程和系统的基本结构,而且是一个喜欢动手研究小玩意的人,那么这个文档可以满足你的需求. 如果你仅仅是用linux来做一些普通的日常工作,而不在乎你的linux到底怎么工作,那么这份文档也许不太适合你.另外,如果你是linux爱好者, 但是目前还是一个刚刚入门的newbi,我建议你先把linux命令学好.不过我想我会尽可能的把这份文档写详细一些,如果你有足够的毅力,或许一个 newbi也能成功做一个babylinux.或者,你遇到一件很不巧的事情,比如你的老婆来例假了,你的这个周末就泡汤了,那么阅读这篇文档并做一个 linux小玩具可以打发你的时间.
四,应该具备的知识
在做一个babylinux之前,你应当已经会应用linux最常用的命令.并且至少有一次成功编译并安装系统内核的经历,会通过编译源代码来安装软件. 如果你具备了这些条件,那么做这样一个小系统会很顺利,如果你还没有掌握这些知识,你可能会遇到一些困难.但是只要有毅力,也可以成功.你不需要具备编程的知识,因为我的目标是:让具有中等以上linux水平的爱好者可以通过阅读文档轻松完成这个项目.关于一张软盘上的linux还有一个很著名的 linux叫LOAP (Linux On A
Floppy) 但是他是由比较专业的人员需要编写很多程序完成的.而且没有关于他制作过程的文档.
五,linux系统引导过程简介
首先,主板的BIOS会读取硬盘的主引导记录(MBR),MBR中存放的是一段很小的程序,他的功能是从硬盘读取操作系统核心文件并运行,因为这个小程序太小了,因此通常这个小程序不具备直接引导系统内核的能力,他先去引导另一个稍微大一点的小程序,再由这个大一点的小程序去引导系统内核.在linux系统中这样的小程序有LILO和GRUB.在这个项目中,我决定用LILO来做系统引导程序.在软盘上启动linux系统的过程和在硬盘上启动的过程相似.
Linux系统内核被引导程序装入内核并运行后,linux内核会检测系统中的各种硬件.并做好各种硬件的初始化工作,使他们在系统正式运行后能正常工作.之后内核做的最后一个工作是运行
/sbin 下的init程序,init是英文单词initialization(初始化)的简称,init程序的工作是读取/etc/inittab文件中描述的指令,对系统的各种软硬件环境做最初化设定.最后运行mingetty等待用户输入用户名登录系统.所有的工作就这么简单,虽然linux启动的时候有很多内容,看上去十分高深,但是都不过是对这个过程的扩充.明白了这个道理,你可以写一些脚本程序让他在系统启动的特定时间运行完成任务.事实上系统内核并不关心/sbin下的init是不是真的init,只要是放在/sbin下名叫init的可执行程序他都可以执行.可以做以下实验:
编写一个非常简单的C程序:
main()
{
printf(“hello,world!\n”);
}
保存后以init.c保存他,并用gcc编译.
#gcc –-static -o init init.c
这里的--static 参数告诉gcc把这个程序静态联接,这样这个程序不倚赖任何库就能运行.把编译好的init程序拷贝到/sbin下,备份好原来的那个.重新启动系统最后系统的输出结果是: hello,world!
然后停在那里.做这个实验以前先确定你知道如何把系统恢复到原来的状态,有一个简单的方法,在内核启动前给他加上init=参数,比如你原先的init被你改成了init.bak 只要在启动的时候给内核加上init=/sbin/init.bak就可以用原来的init程序启动系统.
做完以上实验,就明白了内核和init程序之间的关系.此外,init程序不一定是一个二进制可执行程序,他可以是一个bash脚本,一个指向另一个程序的联接,他的位置也并不一定要在/sbin下,只要在启动内核时,给内核加上init参数就能被运行,比如,开始时给内核加上init= /bin/bash参数,内核在最后一步就直接运行bash给出提示符,不用登录系统就可以输入命令了.其功能类似单用户模式启动系统. /sbin/init 程序只是内核默认运行的第一个程序.
六,编译一个linux系统内核
1,编译前的规划和准备
在编译内核前,请先确定你的需求,把你的需求罗列成一张详细的表格.你需要让内核支持什么硬件,支持多少种分区类型和文件系统,支持哪些网卡,支持哪些网络协议.等等.请尽可能详细的罗列这些内容,但是你也不要太贪心,因为你所有能利用的空间只有1440K,如果你编译出一个大于1440K或很接近这个数字的内核,你的这个项目就不能完成了,你已经没有空间再放ramdisk映象文件,除非你原意再多出一张软盘,做一个两张软盘的小linux系统.对于声卡驱动之类,我劝你还是放弃吧,因为一个声卡驱动也许只让你的内核增大了十多K,但是你有了一个声卡驱动就务必要有一个播放器吧,否则声卡驱动就没有意义, 可一个播放器的大小可不是一张软盘可以装得下的.在我先前制作的babylinux内核有900多K,其中,文件系统部分站了大部分,因为我的目标是把他做成一个系统修复盘.因此我在内核中编译7种文件系统的支持,每减少一个文件系统就可以减小几十甚至200多K的内核大小.越是复杂,越是安全的文件系统,其支持模块也越大,比如在linux下FAT模块只有32K,VFAT只有17K,但是ext3的模块就有86K,JFS达到216K, reiserfs模块是224K,可以想像,编译一个支持7个文件系统的900多K的内核,文件系统部分就占了600K以上的空间,所以如果某一个文件系统是你根本不用的,那么还是不要编译进内核把,这样至少可以省下100多K的空间.对于其他的驱动,比如网卡,通常大小只有8,9K,最大的也不过10多 K,因此可以把常用的网卡芯片的驱动都编译进去.另外如果你想让你的babylinux支持U盘,那么scsi的驱动模块也是不可小看的,他通常要接近 150K,因为U盘是被当做scsi设备来驱动的.另外你还需要让你的内核支持即插即用,这些都是不小的空间开销,我的建议是你放弃一两个你不用的文件系统.总之,你最后编译出来的内核大小最好不要超过900K,否则你在busybox里只能编译进去很少的命令.
在我编译的busybox 中,我编译进去120多个命令,基本上把busybox支持的命令都包括进去了.加上小系统所必需的文件系统目录,/dev下的设备文件,以及/etc下几个必需的配置文件,做成ramdisk压缩后的大小是440多K, 加上900K左右的内核刚好可以放入一张1440K软盘,请注意,你应该留下至少50K的空间,因为我们要在软盘上创建一个ext2文件系统,而文件系统本生需要占据大概25K的磁盘空间.另外lilo的引导文件boot.b的大小是5.7K,还有装上lilo后自动产生的map文件也要10多K的空间, map文件的具体大小由内核安装的实际大小决定,通常不会超过30K.
综上所述,请遵循下面的公式:
内核大小+文件系统压缩印象文件+50K <= 1440K
另外一点需要说明的是:以上所罗列的文件系统模块大小是察看我现在使用的Redhat 9 的
/lib/modules下的模块文件得到的,实际编译进内核大小会小一点,因为我们用make bzImage
在内核源代码目录树下生成的内核是经过压缩过的.
如果你对以上说的内容不太明白也没有关系,我会在下面的内容中做详细的说明.
2,必需编译进内核的内容
首先,我们制作的这个小系统是基于一张软盘的,因此,你的内核必需支持软盘.另外对IDE硬盘和cdrom的支持也是不可少的,否则做出来的 babylinux就没有实用价值,因为他不能访问硬盘和光盘上的内容这样的linux虽然可以做的更小,但是制造一个完全没有用的东西是浪费时间.其他的包括framebuffer等,如果你需要支持在字符界面下以高分辨率显示,以看到更多的屏幕内容,那么就必需把framebuffer支持编译进内核,此外在高分辨率下使用的8x8字体也必需编译进去.否则即使你给内核传递了vga= 参数,内核会因为没有可用的小字体而自动转跳到低分辨率模式下,这是以前困扰我好几天想不明白的事情,后来通过反复试验才明白原来是缺少字体的文体.这里我先大致提一下需要注意的事情.在下一小节具体编译时,我会继续就某些细节问题说明.
3,关于内核的版本
我是在Redhat 9 linux系统下打造的babylinux小系统.使用的是Redhat 9 自带的2.4.20版的内核.
为什么我不用最新的2.6的内核?
一开始我也企图用最新的内核,但是通过试验我发现,在用最新的2.6.9内核的情况下,我编译一个all-no的(即所有内容都选N,不支持任何硬件,只有一个最基本的内核)最小化内核就要460K左右,如果我在这个基础上再加入几种文件系统和必要的驱动,那么内核的大小就不能装下一张1440K
的软盘,而我用2.4.20的内核编译一个最小化的内核只需要217K,的大小.如果优化了gcc参数他还能再小些.这样我就立即省下了200多K的空间, 在平时,200多K的内容微不足道,但是在babylinux里,这个数目是整个空间的 1/7,相当于一个reiserfs文件系统模块的大小.当然,我也尝试了2.2以及更老的内核,但是他们缺少我需要的东西,因此最后权衡下来用2.4的内核是比较合理的.如果你用的是2.6内核的FC系统,那么最好还是去下载一个2.4版的内核,www.kernel.org 有各个时期的内核可以下载.
4, 内核的配置
如果你对linux内核的配置和编译已经很熟悉了,请跳过这一段,直接看busybox的编译.
以root身份登录系统
进入/usr/src/linux目录
[root@gucuiwen root]# cd /usr/src/linux
如果你下载了一个2.4版本的内核,为了避免麻烦,请将他拷贝到/usr/src下,然后接压缩,再做一个指向他的名为linux的链接.虽然这并不是必需的,但是根据我以往的经验,如果我把linux源代码放在其他目录下解开并编译,偶然会有一些莫名其妙的小问题发生.
#cp linux-2.4.20.bz2 /usr/src/
#cd /usr/src
#tar xfvj linux-2.4.20.bz2
如果是tar.gz格式,可以这样解开
#tar xfvz linux-2.4.20.tar.gz
为了方便,做一个到目录linux-2.4.20的连接:
#ln -s linux-2.4.20 linux
进入linux源代码目录:
#cd linux
清理源代码树:
#make mrproper
运行配置程序:
#make xconfig
code maturity level options
先选择N,当我们配置好常规的东西,要加入framebuffer支持时再将这一项选择Y,因为在2.4.20中,framebuffer支持尚属于实验性代码.如果不在code maturity level options选择为Y,将不能配置framebuffer.
Loadable module support
选择N,为了简化系统的制作,我在这个项目中不选择可加载内核模块的支持.
processor type and features
processor family 中选择你需要的CPU类型,如果你想让老至386,新到P4的CPU都能运行babaylinux那么请选择386CPU,否则请按自己的实际情况选择.
其他选项都选择N.这些在babylinux中都是不需要的.
General setup
networking support 选择Y
PCI support 选择Y 除非你不用PCI设备,不过一般人都是需要的,因为现在网卡大部分是PCI的.