pushd /mnt/initrd
ln -s bin sbin
popd
# Create the init file
cat >> /mnt/initrd/linuxrc << EOF
#!/bin/ash
echo
echo “Simple initrd is active”
echo
mount -t proc /proc /proc
mount -t sysfs none /sys
/bin/ash –login
EOF
chmod +x /mnt/initrd/linuxrc
# Finish up…
umount /mnt/initrd
gzip -9 /tmp/ramdisk.img
cp /tmp/ramdisk.img.gz /boot/ramdisk.img.gz
想创建initrd的话,你需要首先创建一个空文件,将/dev/zero(0字符流)做为ramdisk.img的输入。得到的文件大小大约是 4MB(有 4000个1K的块组成)。接下来,用mke2fs命令来创建一个使用这个空文件的ext2文件系统。现在,这个文件就是一个ext2文件系统。ok,接下来,以回路设备的形式挂载这个文件到/mnt/initrd,现在,你就在挂载点拥有一个代表着ext2文件系统的目录,并用与存放你的initrd。其他大多数的脚本语句都是用于实现这个功能。
下一步,就是创建一些必须的子目录,用于生成你的根文件系统: /bin, /sys, /dev, 和 /pro。这里只需要少数几个目录,例如,没有/lib。但是它们已经包含了大部分功能。
如果想让你的根文件系统发挥更大的作用,请使用 BusyBox。这个工具是一个包含了许多独立工具的镜像,这些独立的工具你都能在linux中找到( ash, a等等wk, sed, insmod)。BusyBox的优势在于,它把它们集合在了一起,并分享了公用的部分,从而极大缩小了镜像的体积。这对于嵌入式系统来讲,是非常理想的。请将BustBox镜像从它的源目录中复制出来,到你的/bin目录下,这样,很多指向BusyBox工具集的符号链接将被创建,BusyBox能确定哪一个工具将被使用,并自动引用它。这个/bin目录下被创建的链接的小型集合将用于对启动脚本的支持。
再下一步,就是一小部分特殊设备文件的创建。我从我的/dev文件夹中直接拷贝了出来,别忘了加上-a选项来保持它们原有的属性。
倒数第二步,就是生成linuxrc文件。在内核挂载了内存盘之后,它将搜索并执行相关的启动文件,如果没有找到,内核就将linuxrc文件做为其启动脚本。你最好在这个文件中对环境变量做一些基本设置,例如挂载/proc文件系统等。除了/proc外,我还挂载了/sys文件系统,将消息发送给终端。最后,我调用ash并通过它和根文件系统交互。最后记住,用chmod把linuxrc文件的属性改为可执行。
最后,你的根文件系统算是ok了。现在它并没有被挂载,用gzip将它压缩,并将压缩后的文件ramdisk.img.gz拷贝到/boot目录下,这样它就能被GRUB调用。
想要构建你的初始化ram盘的话,你只需要调用mkird,镜像就将自动创建并拷贝到/boot目录下。
测试自定义的初始化RAM盘
你拥有的新的initrd镜像是在/boot目录下,因此,下一步就是要用你默认的内核来测试它。ok,现在你可以先重新启动你的linux系统,当 GRUB引导画面出现时,按下C键,打开GRUB的命令行工具。现在,你就能通过GRUB确定启动专门的内核和initrd镜像。内核命令是允许你定制内核文件的,而initrd命令则允许你指定专门的initrd镜像文件。当它们都被指定之后,通过启动命令来启动内核,如下所示:
GNU GRUB version 0.95 (638K lower / 97216K upper memory)
[ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename. ESC at any time exits.]
grub> kernel /bzImage-2.6.1
[Linux-bzImage, setup=0×1400, size=0×29672e]
grub> initrd /ramdisk.img.gz
[Linux-initrd @ 0×5f2a000, 0xb5108 bytes]
grub> boot
Uncompressing Linux… OK, booting the kernel.
在内核启动之后,它开始检查initrd镜像是否可用,如果答案是确定的,那么就作为根文件系统加载并挂载它。下面就是这个特殊启动过程的结尾:
…
md: Autodetecting RAID arrays
md: autorun
md: … autorun DONE.
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 file system).
Freeing unused kernel memory: 208k freed
/ $ ls
bin etc linuxrc proc sys
dev lib lost+found sbin
/ $ cat /proc/1/cmdline
/bin/ash/linuxrc
/ $ cd bin
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps
/bin $ touch zfile
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps zfile
当启动之后,可以通过ash来进入命令模式。在本例中,我探究了根文件系统并向你演示了,你能通过新建文件来写入这个文件系统。只需要注意,第一步是要创建linuxrc。
通过初始化内存盘启动
现在,大家已经看到了如何构建并使用一个自定制的初始化内存盘,这一节则用于介绍,内核是如何辨认initrd并将其作为它的根文件系统挂载的。我将涉及一些boot chain中的主要的函数并对发生的事件做出解释。
像GRUB这样的boot loader,通常会确认即将加载的内核并复制该内核镜像与任何相关联的initrd到内存中,你可以在你linux内核源程序目录下的./init子目录中找到这些功能实现。
在内核与initrd镜像被解压缩和复制到内存后,内核被调用。此时,开始各种各样的初始化过程,最终,你会发现自己处于init/main.c: init () (subdir/file:function)。这个函数实现了很多的子系统初始化。在这里,要调用init/do_mounts.c: prepare_namespace(),用来准备命名
空间(挂载dev 文件系统, RAID, 或者md, devices, 以及, 最后的initrd)。通过对 init/do_mounts_initrd.c:initrd_load()的调用,最终完成对initrd的加载。
initrd_load ()调用init/do_mounts_rd.c:rd_load_image(),来决定是否通过调用init/do_mounts_rd.c: identify_ramdisk_image()来加载内存盘镜像。后面这个函数通过检查内核的编号来确定文件究竟是是minux,etc2, romfs,cramfs,还是gzip格式,直到返回initrd_load_image后,init/do_mounts_rd:crd_load ()又被调用。这个函数负责分配