Linux initial RAM disk(initrd)介绍

     initrd是为了支持linux启动的两个阶段,而设计的临时根文件系统。通常,initrd内包含多种可执行文件和驱动库,用于实现最后挂载真实的根文件系统,并在之后卸载临时的initrd根文件系统并释放相应的内存。在很多嵌入式的Linux系统中,没有使用其他真实的根文件系统,而采用initrd做为最后使用的根文件系统。

    initrd被绑定到内核,并伴随内核启动过程被加载。initrd内部包含了必要的可执行文件和系统文件以支持Linux第二阶段的启动过程。

创建initial RAM disk的两种方式

    linux内核版本不同,创建initial RAM disk的方式不一样,早期采用loop device构造,loop device允许挂载文件为块设备。在这种模式的系统内核下,可以采用以下方式打开initrd,并观察内部的文件。


 
# mkdir temp ; cd temp
# cp /boot/initrd.img.gz .
# gunzip initrd.img.gz
# mount -t ext -o loop initrd.img /mnt/initrd
# ls -la /mnt/initrd

    新版本的内容一般采用压缩的cpio打包文件创建initrd镜像,替代原来采用loop device挂载文件作为压缩镜像的模式。在这种模式的系统中,可以用以下的命令查看initrd的内容。


 
# mkdir temp ; cd temp
# cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz
# gunzip initrd-2.6.14.2.img.gz
# cpio -i --make-directories < initrd-2.6.14.2.img

    从上面的命令,可以看到,initrd内部包含一个小型但又是必不可少的文件系统。


 
# ls -la
#
drwxr-xr-x 10 root root 4096 May 7 02:48 .
drwxr-x--- 15 root root 4096 May 7 00:54 ..
drwxr-xr-x 2 root root 4096 May 7 02:48 bin
drwxr-xr-x 2 root root 4096 May 7 02:48 dev
drwxr-xr-x 4 root root 4096 May 7 02:48 etc
-rwxr-xr-x 1 root root 812 May 7 02:48 init
-rw-r--r-- 1 root root 1723392 May 7 02:45 initrd-2.6.14.2.img
drwxr-xr-x 2 root root 4096 May 7 02:48 lib
drwxr-xr-x 2 root root 4096 May 7 02:48 loopfs
drwxr-xr-x 2 root root 4096 May 7 02:48 proc
lrwxrwxrwx 1 root root 3 May 7 02:48 sbin -> bin
drwxr-xr-x 2 root root 4096 May 7 02:48 sys
drwxr-xr-x 2 root root 4096 May 7 02:48 sysroot

创建一个简单的initrd

    传统的Linux系统,initrd镜像在Linux系统构建过程中创建,使用像mkinitrd等工具。mkinitrd实际上是个shell脚本程序。下面介绍一下mkinitrd是如何创建initrd的。

mkinitrd文件内容


 
#!/bin/bash

# Housekeeping...
rm -f /tmp/ramdisk.img
rm -f /tmp/ramdisk.img.gz

# Ramdisk Constants
RDSIZE=4000
BLKSIZE=1024

# Create an empty ramdisk image
dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE

# Make it an ext2 mountable file system
/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE

# Mount it so that we can populate
mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0

# Populate the filesystem (subdirectories)
mkdir /mnt/initrd/bin
mkdir /mnt/initrd/sys
mkdir /mnt/initrd/dev
mkdir /mnt/initrd/proc

# Grab busybox and create the symbolic links
pushd /mnt/initrd/bin
cp /usr/local/src/busybox-1.1.1/busybox .
ln -s busybox ash
ln -s busybox mount
ln -s busybox echo
ln -s busybox ls
ln -s busybox cat
ln -s busybox ps
ln -s busybox dmesg
ln -s busybox sysctl
popd

# Grab the necessary dev files
cp -a /dev/console /mnt/initrd/dev
cp -a /dev/ramdisk /mnt/initrd/dev
cp -a /dev/ram0 /mnt/initrd/dev
cp -a /dev/null /mnt/initrd/dev
cp -a /dev/tty1 /mnt/initrd/dev
cp -a /dev/tty2 /mnt/initrd/dev

# Equate sbin with bin
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

    首先需要创建一个空的文件,使用/dev/zero作为输入创建ramdisk.img文件。RDSIZE=4000和BLKSIZE=1024指定了4000个1k大小的块进行填充文件。再把生成的空文件利用mke2fs命令创建一个空的ext2文件系统。利用loop device将该文件系统挂载到/mnt/initrd。在该挂载点下有个空的目录,现在就可以向其填充文件系统的内容了。

    接下来需要做的就是创建子目录,例如 /bin、/sys等。如果想让你的文件系统有意义,可以利用BusyBox,这个工具是个单一的镜像,内部包含了很多独立的工具,这些工具都是linux系统下常用的。BusyBox的优势是打包多个工具到一个文件,当需要共享其中的内容时,产生多个小镜像文件。可以通过创建符号链接将需要的小工具指向BusyBox实体。

    下一步就是需要创建一些特别的设备文件,你可以直接将本机的设备文件复制过去。

    倒数第二个阶段就是创建一个linuxrc文件,在内核挂载了RAM disk后,需要查找init文件并执行,如果没找到该文件,内核会调用linuxrc文件作为启动脚本执行。你可以在这个文件里面建立基本的系统环境,例如挂载proc文件系统,在该例子里,还挂载了sys文件系统,并向console打印消息,最后,调用ash,并能和根文件系统进行交互。

    最后,根文件创建系统结束,从/mnt/initrd卸载,并利用gzip文件压缩。将最后的文件复制到/boot子目录,这时便可以通过GNU的GRUB指定相应的文件加载并测试。

initrd的加载过程

    像GRUB等linux的启动引导程序能识别内核并加载和复制内核镜像以及相关的initrd到内存。这部分的源码在linux源码目录下的./init目录下。

    在内核和initrd文件被加载并复制到内存后,内核被调用,多个初始化过程被执行,具体可以看函数init/main.c:init(),这个函数实现了大量的子系统初始化过程。调用函数init/do_mounts.c:prepare_namespace()准备名字空间,例如挂载设备文件系统,RAID,设备,initrd等。加载initrd是通过函数init/do_mounts_initrd.c:initrd_load()函数实现的。该函数调用init/do_mounts_rd.c:rd_load_image(),它确定通过init/do_mounts_rd.c:identify_ramdisk_image()函数加载RAM。这个函数检查文件的魔术字并确定文件格式。函数返回到initrd_load_image,调用init/do_mounts_rd:crd_load(),该函数分配RAM盘的空间,计算CRC,解压并加载RAM disk镜像到内存。到这里,initrd镜像已经是一个可以挂载的块文件了。

    从函数init/do_mounts.c:mount_root()函数开始挂载块设备为root目录,根设备被创建,然后调用函数init/do_mounts.c:mount_block_root(), 在函数里调用了init/do_mounts.c:do_mount_root()子函数,接着调用fs/namespace.c:sys_mount() 挂载实际的根文件系统,并利用chdir切换到该目录,在这儿你可以看到熟悉的打印信息“VFS: Mounted root (ext2 file system).“。以下是具体的函数调用过程。


 
init/main.c:init
init/do_mounts.c:prepare_namespace
init/do_mounts_initrd.c:initrd_load
init/do_mounts_rd.c:rd_load_image
init/do_mounts_rd.c:identify_ramdisk_image
init/do_mounts_rd.c:crd_load
lib/inflate.c:gunzip
init/do_mounts.c:mount_root
init/do_mounts.c:mount_block_root
init/do_mounts.c:do_mount_root
fs/namespace.c:sys_mount
init/main.c:run_init_process
execve

============================

转载时请注明出处和作者联系方式

文章出处:http://www.mythfish.com/

作者联系方式:张天才 mythfish@gmail.com

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值