为linux建立最小的根文件系统
在编译内核时候,可以指定一个文件夹作为内核启动时候的根文件系统,linux中管这个文件系统叫做initramfs。
具体做法如下(以i386为例)
1.下载内核文件
wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.26.tar.bz2
2.解压内核
bzip2 -d linux-2.6.26.tar.bz2 生成一个linux-2.6.26.tar文件,然后
tar xvf linux-2.6.26.tar
解压后,将有个linux-2.6.26文件夹存在
3.准备一个iniramfs文件系统的文件夹
在linux-2.6.26文件夹下建立一个文件夹 myinitramfs
写一个测试用的hello world,起名为hello.c,如下:
#include <stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int i = 0;
while (1) {
printf("hello world (%d)\n",i);
}
return 0;
}
编译 gcc -static -o init hello.c
把init拷贝到myinitramfs文件夹下。
cp init myinitramfs/
由于需要显示文字,还需要在文件夹下准备console设备文件。
mkdir myinitramfs/dev
cp -a /dev/console myinitramfs/
4.编译内核
在linux-2.6.26文件下下,执行make help。
将看到很多帮助信息,其中有一项是 i386_defconfig
执行 make i386_defconfig,将生成一个.config文件。
为了把之前准备好的文件夹添加到内核配置文件中,还需要重新配置下config文件
make config
在 General Setup --->
Initial RAM filesystem and RAM disk (initramfs/initrd) support (BLK_DEV_INITRD) [Y/n/?]
Initramfs source file(s) (INITRAMFS_SOURCE) [myinitramfs]
处,输入准备好的文件夹.
配置好后,在.config文件中会有如下一条定义
CONFIG_INITRAMFS_SOURCE="myinitramfs"
保存.config
make 编译内核
5.用qemu测试内核和initramfs
qemu -kernel linux-2.6.26/arch/i386/boot/bzImage -initrd linux-2.6.26/usr/initramfs_data.cpio.gz /dev/zero
initramfs_data.cpio.gz 这个文件是内核自动生成的,具体名字可能不同的系统或者内核有差异,但是后缀应该是.cpio.gz
开工啦!
为了不看起来那么乏味,我们尝试通过一个看的着的例子来展示这个过程。
唔,我们还是把“hello world”作为第一个要放到initramfs中去的程序。事实上,rootfs和其它的root filesystem并没有什么区别,如果你喜欢,你可以放/etc和/usr和/tmp和。。。然后还可以mount /proc 和/sysfs过去。但是这里我们只需要放/init过去。程序的最后我们使用sleeping而不是exiting,这主要是考虑如果PID 1的程序退出,kernel会panic,这会干扰我们的视线。
#include int main(int argc, char *argv[]) { printf("Hello world\n"); sleep(999999999); }
然后呢,静态编译,然后我们就不用考虑拷贝需要的库过去了~
gcc -static hello.c -o hello
如果在命令行执行这个小程序,它会打印hello world,让后停在那里。你可以用ctrl-x让它退出。如果是initramfs执行这个程序,我们会看到在boot messages的最后,有个“hello world”被打印。
注意:如果是要放到你的开发板上去执行,记得使用你的交叉编译工具。打包的过程是和平台无关的,但是二进制文件需要用目标系统的compiler。
那么,我们该怎样把这个程序给kernel用内?好吧,有四种基本方法:第一种是把cpio.gz作为一个独立的包,然后告诉bootloader它在哪里;或者你可以用下面三种方法之一,把initramfs直接编译进kernel里去。
把cipo.gz作为独立的档案
很多人喜欢把它编译进内核里面去,如果你乐意,你也可以这么做。但是我们现在要用另一种方式。我们可以使能内核的initrd支持,然后用cpio.gz来代替ramdisk(initrd)。聪明的内核会为我们自动检测文件的类型,然后把我们的压缩包解压放进rootfs;它不是创建一个ram disk,这不会影响initramfs内存效率高这一优势。
因为external initramfs是在built-in initramfs之后执行的,所以如果两个档案内包含有同名的内容,独立档案会覆盖掉built-in填进去去的东西。这意味着,你不用修改kernel,就可以update或者是ucstomize你的rootfs而不用换掉你的内核。
另外一个好消息是,这样做你可以不用顾虑license的问题!你可以在rootfs里面运行non-GPL的程序,或者是给你的驱动提供non-GPL的firmware...额,编译进内核的话,算是内核的修改吧?制作自己的initramfs,只是算是使用,你不用公布你的源代码哦亲!
那么,怎么制作cpio.gz档案呢?一种方法是你用cpio和gzip命令自己来压缩。当然,你也可以用kernel build来做这个,如果你觉得不是那么麻烦的话。原意自己做的,只需要敲下面这些代码进去...
mkdir sub cp hello sub/init cd sub find . | cpio -o -H newc | gzip > ../initramfs_data.cpio.gz cd .. rm -rf sub
按照传统的使用initrd的方法,把上面生成的initramfs_data.cpio.gz放到该放的地方去(别问我要放哪里,我也还不知道),它就会在boot结束的地方为你打印一朵漂亮的“hello world”,然后等待一段时间并重启。
试试吧!
如果它没有工作,照例的你该查查initial ramdisk支持是不是有被选中,然后看看你的init 程序是不是静态链接的,再看看它是不是又执行权限,或者是名字是不是对的。你可以用下面的命令来解压任何的initramfs档案到当前文件夹:
zcat initramfs_data.cpio.gz | cpio -i -d -H newc --no-absolute-filenames
把initramfs编译到内核里面去
使用initramfs最简单的方式,莫过于用已经做好的cpio.gz把kernel里面那个空的给换掉。这是2.6 kernel天生支持的,所以,你不用做什么特殊的设置。
kernel的config option里面有一项CONFIG_INITRAMFS_SOURCE(I.E. General setup--->Initramfs source file(s) in menuconfig)。这个选项指向放着内核打包initramfs需要的所有文件。默认情况下,这个选项是留空的,所以内核编译出来之后initramfs也就是空的,也就是前面提到的rootfs什么都不做的情形。
CONFIG_INITRAMFS_SOURCE 可以是一个绝对路径,也可以是一个从kernel’s top build dir(你敲入build或者是make的地方)开始的相对路径。而指向的目标可以有以下三种:一个已经做好的cpio.gz,或者一个已经为制作cpio.gz准备好所有内容的文件夹,或者是一个text的配置文件。第三种方式是最灵活的,我们先依次来介绍这三种方法。
1)使用一个已经做好的cpio.gz档案
If you already have your own initramfs_data.cpio.gz file (because you created it yourself, or saved the cpio.gz file produced by a previous kernel build), you can point CONFIG_INITRAMFS_SOURCE at it and the kernel build will autodetect the file type and link it into the resulting kernel image.
You can also leave CONFIG_INITRAMFS_SOURCE empty, and instead copy your cpio.gz file to usr/initramfs_data.cpio.gz in your kernel's build directory. The kernel's makefile won't generate a new archive if it doesn't need to.
Either way, if you build a kernel like this you can boot it wit