Linux的INITRAMFS 与 INITRD

1. INITRAMFS 和 INITRD(INITRAMDISK) 是什么?

RAMFS 和 RAMDISK 都是内存文件系统,他们有着小巧快速的特点。INIT前缀表示其包含有效“init”可执行文件,可以作为启动的root文件系统。INITRAMDISK出现较早,在使用nor flash和2.4kernel盛行的时期很流行。RAMFS出现也很早,但INITRAMFS是2.6版本kernel添加的新功能,INITRAMFS更象是INITRAMDISK的一个简化版本。如今嵌入式设备大量使用nand flash,像INITRAMFS和INITRAMDISK已经不适合用来管理nand这种大容量并且需要校验机制的存储设备。
但,在某些场合,比如:
l 你需要做一个很简单快速的镜像文件
l 和Kernel编译出一个镜像文件
l 与板载nand文件系统完全无关的镜像文件
在这些情况下,INITRAMFS和INITRAMDISK都是不错的选择。

INITRAMFS 和 INITRAMDISK 有着相似的制作流程:
l 通过某种压缩算法,把目标root目录压缩成一个文件
l 再把压缩文件存储在某个位置,或者直接链接到kernel镜像中

INITRAMFS和INITRAMDISK在Kernel的启动过程中也有着相似的加载流程:
l 通过Command Line找到压缩的文件(initramfs与Command Line无关)
l 把压缩文件解压到内存中,并以指定的文件系统类型加载(mount)
l 如果加载的rootfs文件系统中有init文件,Linux启动进程就能直接跳转到init进程,然后便有了开机启动init脚本的执行,以及最终的shell console。
l 写入内存文件系统的更改,在重启系统后都不复存在,这是内存文件系统的特点。

INITRAMFS和INITRAMDISK之间也有区别。
ramdisk文件是一个块设备文件,文件系统一般为ext2。ramdisk加载后,从文件系统中读取数据,数据流依次通过了Kernel的“块设备管理读写“->”ext2文件系统“->"VFS"->最后传到用户空间。

而ramfs没有ext2文件系统,没有块设备处理,数据的终点就是“VFS Cache”(内存),同样一个读取流程,数据依次通过"VFS Cache(ramfs)”->VFS->用户。

由此可以看出initramfs比initrd更简单快速,而Kernel对initramfs的内部处理也更为简单上面提到的"VFS Cache"在Kernel中,通常以一个加载的rootfs文件系统来管理,此文件系统的类型为RAMFS(实际名称为ROOTFS)。INITRAMFS的处理过程把initramfs文件直接解压到此文件系统中,然后再将此rootfs文件系统直接呈给用户空间(执行用户init进程)。INITRAMDISK的解压加载过程同样要用到这个rootfs,它会把initramdisk文件解压到此文件系统中的'/dev/ram'块设备里,然后再加载'/dev/ram'块设备。

2. Linux 2.6.28对INITRAMFS的处理

以Samsung 6410测试平台(Kernel 2.6.28)为例,来体验initramfs制作、编译、kernel解析、加载、用户init调度的整个过程。

2.1 Initramfs文件的制作、编译过程

首先查看kernel/.config,这里没有看到对INITRAMFS功能的开关。这跟Kernel文档描述一致,因为Kernel处理INITRAMFS的负荷极小,所以Kernel始终包含处理INITRAMFS的功能。通过此文章后续的说明,你可以看到实际上Kernel一直包含一个RAMFS的rootfs,当此rootfs无效(为空或者没有有效的init文件),此rootfs就会被后续command-line所指定的文件系统所覆盖。
在Kernel menuconfig中,唯一需要指定的是‘CONFIG_INITRAMFS_SOURCE’,这里需要指定用于制作initramfs文件的目标root目录的绝对路径。
然后编译(cd Kernel; make V=1),以下是相关的编译日志:
'kernel/scripts/gen_initramfs_list.sh -o usr/initramfs_data.cpio.gz -u 0 -g 0 /XXX/root
'arm-none-linux-gnueabi-gcc -c -o usr/initramfs_data.o usr/initramfs_data.S' # initramfs_data.S: Include '.gz' as a global section 'init.ramfs'
'arm-none-linux-gnueabi-ld -EL -r -o usr/built-in.o usr/initramfs_data.o'
'arm-none-linux-gnueabi-ld -EL -r -o vmlinux.o -T arch/arm/kernel/vmlinux.lds ... usr/built-in.o ... '
以下是脚本“vmlinux.lds”中的相关内容:
.init : { /* Init code and data */
*(.init.text) *(.cpuinit.text) *(.meminit.text)
...
__initramfs_start = .;
usr/built-in.o(.init.ramfs)
__initramfs_end = .;
...
}
编译过程可以归纳成三步:
第一步,gen_initramfs_list.sh脚本以cpio格式对目标root目录压缩生成XXX.cpio.gz文件,这里为什么使用cpio而不是tar, 因为简单,这一点内核文档有说明。
第二步,initramfs_data.S只做一件事情,创建一个Section,包含XXX.cpio.gz文件。
第三步,编译并链接,‘arch/arm/kernel/vmlinux.lds’中,在init section中声明了两个全局变量“__initramfs_start”和"__initramfs_end"用于指向init.ramfs域的开始和结束。实际上,__initramfs_start就是内核空间全局的指针变量,指定XXX.cpio.gz开始地址,__initramfs_end指定结束地址。当然这两个全局变量只在init进程中有效。
编译过程完成,最终形成一个镜像文件zImage,在这个文件中,__initramfs_start和initramfs_end两个变量分别指向XXX.cpio.gz数据的起始和结束地址(结束地址+1)。

2.2 Kernel加载initramfs的过程
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值