<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<atom:link href="http://gentoo-zh.org/extern.php?action=feed&amp;tid=854&amp;type=rss" rel="self" type="application/rss+xml" />
		<title><![CDATA[Gentoo中文社区 / Gentoo 之 Initial RAM filesystem and RAM disk]]></title>
		<link>http://www.gentoo-zh.org/viewtopic.php?id=854</link>
		<description><![CDATA[Gentoo 之 Initial RAM filesystem and RAM disk 最近发表的帖子。]]></description>
		<lastBuildDate>Tue, 02 Apr 2024 12:54:48 +0000</lastBuildDate>
		<generator>FluxBB</generator>
		<item>
			<title><![CDATA[Gentoo 之 Initial RAM filesystem and RAM disk]]></title>
			<link>http://www.gentoo-zh.org/viewtopic.php?pid=973#p973</link>
			<description><![CDATA[<p>一、简介</p><p>(1) initrd</p><p>在早期的linux系统中，一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备，因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式系统中可能将根文件系统保存到各种存储设备上，包括scsi、sata，u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。</p><p>&#160; 为了解决这一矛盾，于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录，这个目录中包含了启动阶段中必须的驱动模块，可执行文件和启动脚本。当系统启动的时候，bootloader会把initrd文件读到内存中，然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件，然后将解压后的initrd挂载为根目录，然后执行根目录中的/linuxrc脚本（cpio格式的initrd为/init,而image格式的initrd&lt;也称老式块设备的initrd或传统的文件镜像格式的initrd&gt;为/initrc），您就可以在这个脚本中加载realfs（真实文件系统）存放设备的驱动程序以及在/dev目录下建立必要的设备节点。这样，就可以mount真正的根目录，并切换到这个根目录中来。</p><p>(2) Initramfs</p><p>在linux2.5中出现了initramfs，它的作用和initrd类似，只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件)，该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上，其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压，然后使用它作为临时的根文件系统。</p><p>二、initramfs与initrd区别</p><p>(1) Linux内核只认cpio格式的initramfs文件包(因为unpack_to_rootfs只能解析cpio格式文件)，非cpio格式的 initramfs文件包将被系统抛弃，而initrd可以是cpio包也可以是传统的镜像(image)文件，实际使用中initrd都是传统镜像文件。<br />(2) initramfs在编译内核的同时被编译并与内核连接成一个文件，它被链接到地址__initramfs_start处，与内核同时被 bootloader加载到ram中，而initrd是另外单独编译生成的，是一个独立的文件，它由bootloader单独加载到ram中内核空间外的地址，比如加载的地址为addr(是物理地址而非虚拟地址)，大小为8MB，那么只要在命令行加入&quot;initrd=addr,8M&quot;命令，系统就可以找到 initrd(当然通过适当修改Linux的目录结构，makefile文件和相关代码，以上两种情况都是可以相通的)。<br />(3) initramfs被解析处理后原始的cpio包(压缩或非压缩)所占的空间(&amp;__initramfs_start - &amp;__initramfs_end)是作为系统的一部分直接保留在系统中，不会被释放掉，而对于initrd镜像文件，如果没有在命令行中设置&quot;keepinitd&quot;命令，那么initrd镜像文件被处理后其原始文件所占的空间(initrd_end - initrd_start)将被释放掉。<br />(4) initramfs可以独立ram disk单独存在，而要支持initrd必须要先支持ram disk，即要配置CONFIG_BLK_DEV_INITRD选项 -- 支持initrd，必须先要配置CONFIG_BLK_DEV_RAM -- 支持ram disk ，因为initrd image实际就是初始化好了的ramdisk镜像文件，最后都要解析、写入到ram disk设备/dev/ram或/dev/ram0中。注: 使用initramfs，命令行参数将不需要&quot;initrd=&quot;和&quot;root=&quot;命令<br />initramfs利弊:<br />------------------------------------------------------<br />由于initramfs使用cpio包格式，所以很容易将一个单一的文件、目录、node编译链接到系统中去，这样很简单的系统中使用起来很方便，不需要另外挂接文件系统。<br />但是因为cpio包实际是文件、目录、节点的描述语言包，为了描述一个文件、目录、节点，要增加很多额外的描述文字开销，特别是对于目录和节点，本身很小额外添加的描述文字却很多，这样使得cpio包比相应的image文件大很多。</p><br /><p>使用initramfs的内核配置(使用initramfs做根文件系统):<br />------------------------------------------------------<br />General setup&#160; ---&gt;<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support<br />(/rootfs_dir) Initramfs source file(s)&#160; &#160;//输入根文件系统的所在目录 <br />使用initramfs的内核启动参数不需要&quot;initrd=&quot;和&quot;root=&quot;参数,但是必须在initramfs中创建/init文件或者修改内核启动最后代码(init文件是软连接，指向什么? init -&gt; bin/busybox，否则内核启动将会失败)<br />链接入内核的initramfs文件在linux-2.6.24/usr/initramfs_data.cpio.gz<br />使用initrd的内核配置(使用网口将根文件系统下载到RAM -- tftp addr ramdisk.gz):<br />------------------------------------------------------<br />1. 配置initrd<br />General setup&#160; ---&gt;<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support<br />() Initramfs source file(s)&#160; &#160;//清空根文件系统的目录配置 <br />2. 配置ramdisk<br />Device Drivers&#160; ---&gt;&#160; &#160;<br />Block devices&#160; ---&gt;<br />&lt; &gt; RAM disk support<br />(16)&#160; Default number of RAM disks&#160; &#160;// 内核在/dev/目录下生成16个ram设备节点<br />(4096) Default RAM disk size (kbytes)<br />(1024) Default RAM disk block size (bytes)<br />使用 initrd的内 核启动参数:initrd=addr,0x400000 root=/dev/ram rw<br />注:<br />(1) addr是根文件系统的下载地址；<br />(2) 0x400000是根文件系统的大小，该大小需要和内核配置的ramdisk size 4096 kbytes相一致；<br />(3) /dev/ram是ramdisk的设备节点，rw表示根文件系统可读、可写；<br />根文件系统存放在FLASH分区：<br />------------------------------------------------------<br />1. 内核启动参数不需要&quot;initrd=&quot;(也可以写成&quot;noinitrd&quot;)；<br />root=/dev/mtdblock2 (/dev/mtdblock2 -- 根文件系统所烧写的FLASH分区)<br />2. 内核配置不需要ram disk；也不需要配置initramfs或者initrd<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support <br />注: boot的FLASH分区要和kernel的FLASH分区匹配(而非一致)，需要进一步解释。</p><br /><p>处理流程<br />linux内核支持两种格式的文件系统镜像：传统格式的文件系统镜像image-initrd和cpio-initrd格式的镜像。<br />下面分别说明：</p><p>cpio-initrd的处理流程：（执行流程可以对照下面博文的代码分析：linux的initrd机制和initramfs机制之根文件挂载流程：代码分析）<br />1．uboot把内核以及initrd文件加载到内存的特定位置。<br />2．内核判断initrd的文件格式，如果是cpio格式。<br />3．将initrd的内容释放到rootfs中。<br />4．执行initrd中的/init文件，执行到这一点，内核的工作全部结束，完全交给/init文件处理。<br />可见对于cpio-initrd格式的镜像，它执行的是init文件</p><p>image-initrd的处理流程<br />1．uboot把内核以及initrd文件加载到内存的特定位置。<br />2．内核判断initrd的文件格式，如果不是cpio格式，将其作为image-initrd处理。<br />3．内核将initrd的内容保存在rootfs下的/initrd.image文件中。<br />4．内核将/initrd.image的内容读入/dev/ram0设备中，也就是读入了一个内存盘中。<br />5．接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。<br />6．如果/dev/ram0被指定为真正的根文件系统，那么内核跳至最后一步正常启动。<br />7．执行initrd上的/linuxrc文件，linuxrc通常是一个脚本文件，负责加载内核访问根文件系统必须的驱动，以及加载根文件系统。<br />8．/linuxrc执行完毕，实际根文件系统被挂载，执行权转交给内核。<br />9．如果实际根文件系统存在/initrd目录，那么/dev/ram0将从/移动到/initrd。否则如果/initrd目录不存在，/dev/ram0将被卸载。<br />10．在实际根文件系统上进行正常启动过程，执行/sbin/init。<br />对于image-initrd格式的镜像，它执行的是linuxrc文件</p><p>三、两种格式镜像比较<br />1. cpio-initrd的制作方法比image-initrd简单。<br />2. cpio-initrd的内核处理流程相比image-initrd更简单，因为：<br />a. 根据上面的流程对比可知，cpio-initrd格式的镜像是释放到rootfs中的，不需要额外的文件系统支持，<br />&#160; &#160;而image-initrd格式的镜像先是被挂载成虚拟文件系统，而后被卸载，基于具体的文件系统<br />b. image-initrd内核在执行完/linuxrc进程后，还要返回执行内核进行一些收尾工作，<br />&#160; &#160;并且要负责执行真正的根文件系统的/sbin/init。</p><p>处理流程对比如下图所示：（来自网络）<br /><span class="postimg"><img src="https://www.batsom.net/usr/uploads/2024/04/4263602854.jpg" alt="FluxBB bbcode 测试" /></span></p><p>由对比可以看出cpio-initrd格式的镜像更具优势，这也是它逐渐代替image-initrd格式镜像的原因</p><p>四、initrd镜像的制作</p><p>cpio-initrd格式镜像制作：<br />进入到要制作的文件系统的根目录；</p><div class="codebox"><pre><code>bash# find . | cpio -c -o &gt; ../initrd.img
bash# gzip ../initrd.img</code></pre></div><p>image-initrd格式镜像制作：<br />进入到要制作的文件系统的根目录；</p><div class="codebox"><pre><code>bash# dd if=/dev/zero of=../initrd.img bs=512k count=5
bash# mkfs.ext2 -F -m0 ../initrd.img
bash# mount -t ext2 -o loop ../initrd.img /mnt
bash# cp -r * /mnt
bash# umount /mnt
bash# gzip -9 ../initrd.img</code></pre></div><p>对于image-initrd格式镜像的制作，往往采用制作工具，如genext2fs</p><p>五、image-initrd格式镜像实例解读<br />参见下一篇博文<br />一、initrd</p><p>ram disk中的file system叫做initrd，全名叫做initial ramdisk。<br />如何创建initial ramisk</p><div class="codebox"><pre><code>host &gt; dd if=/dev/zero of=/dev/ram0 bs=1k count=&lt;count&gt;
host &gt; mke2fs -vm0 /dev/ram0 &lt;count&gt;
host &gt; tune2fs -c 0 /dev/ram0
host &gt; dd if=/dev/ram0 bs=1k count=&lt;count&gt; | gzip -v9 &gt; ramdisk.gz</code></pre></div><p>这段代码就创建了大小为count的ramdisk<br />创建完之后还要添加哪些东西</p><p>还要添加一些必要的文件让他工作，可能是库，应用程序等。例如busybox。</p><div class="codebox"><pre><code>host $ mkdir mnt
host $ gunzip ramdisk.gz
host $ mount -o loop ramdisk mnt/
host $ ... copy stuff you want to have in ramdisk to mnt...
host $ umount mnt
host $ gzip -v9 ramdisk</code></pre></div><p>内核如何支持initial ramdisk</p><div class="codebox"><pre><code>#
# General setup
#
...
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=&quot;&quot;
...

#
# UBI - Unsorted block images
#
.../*****************initramfs 应该不需要配置下面的参数************************/
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024</code></pre></div><p>告诉uboot怎么找到她</p><div class="codebox"><pre><code>UBOOT # tftp 0x87000000 ramdisk.gz
UBOOT # erase 0x2200000 +0x&lt;filesize&gt;
UBOOT # cp.b 0x87000000 0x2200000 0x&lt;filesize&gt;

UBOOT # setenv bootargs ... root=/dev/ram0 rw initrd=0x87000000,8M
UBOOT # setenv bootcmd cp.b 0x2200000 0x87000000 0x&lt;filesize&gt;; bootm
UBOOT # saveenv</code></pre></div><p>注意： ramdisk 中要有ram0节点<br />最后启动内核<br />二、initramfs</p><p>initramfs相当于把initrd放进了内核，通过cpio（这是一个文件处理工具）实现。<br />如何创建<br />比initrd简单多了</p><div class="codebox"><pre><code>host &gt; mkdir target_fs

host &gt; ... copy stuff you want to have in initramfs to target_fs...</code></pre></div><p>注意：<br />1. initramfs中的cpio系统不能处理hard link，用soft link<br />2. 顶层必须有个init程序，这是kernel要用的，可以这么做</p><div class="codebox"><pre><code>/init -&gt; /bin/busybox</code></pre></div><p>接着</p><div class="codebox"><pre><code>host &gt; cd target_fs
host &gt; find . | cpio -H newc -o &gt; ../target_fs.cpio</code></pre></div><p>内核支持</p><div class="codebox"><pre><code>#
# General setup
#
...
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=&quot;&lt;path_to&gt;/target_fs&gt;&quot;
...

#
# UBI - Unsorted block images
#
...
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 </code></pre></div><p>然后执行make uImage的时候就被包含到kernel中了。<br />uboot支持</p><p>因为已经在kernel中了，不需要像initrd一样通过参数 root=/xxx rw initrd=xxx来告诉uboot了</p><p>三、比较<br />&#160; &#160; initrd方式中kernel和initial file system为独立的部分，互不影响，下载的时候镜像也小。<br />&#160; &#160; 创建修改initramfs比initrd容易。<br />&#160; &#160; 在烧写的时候，显然一个镜像更容易管理。</p><p>一、简介</p><p>(1) initrd</p><p>&#160; 在早期的linux系统中，一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备，因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式系统中可能将根文件系统保存到各种存储设备上，包括scsi、sata，u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。</p><p>&#160; 为了解决这一矛盾，于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录，这个目录中包含了启动阶段中必须的驱动模块，可执行文件和启动脚本。当系统启动的时候，bootloader会把initrd文件读到内存中，然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件，然后将解压后的initrd挂载为根目录，然后执行根目录中的/linuxrc脚本（cpio格式的initrd为/init,而image格式的initrd&lt;也称老式块设备的initrd或传统的文件镜像格式的initrd&gt;为/initrc），您就可以在这个脚本中加载realfs（真实文件系统）存放设备的驱动程序以及在/dev目录下建立必要的设备节点。这样，就可以mount真正的根目录，并切换到这个根目录中来。</p><p>(2) Initramfs</p><p>&#160; 在linux2.5中出现了initramfs，它的作用和initrd类似，只是和内核编译成一个文件(该initramfs是经过gzip压缩后的cpio格式的数据文件)，该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上，其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压，然后使用它作为临时的根文件系统。</p><p>二、initramfs与initrd区别</p><br /><p>(1) Linux内核只认cpio格式的initramfs文件包(因为unpack_to_rootfs只能解析cpio格式文件)，非cpio格式的 initramfs文件包将被系统抛弃，而initrd可以是cpio包也可以是传统的镜像(image)文件，实际使用中initrd都是传统镜像文件。<br />(2) initramfs在编译内核的同时被编译并与内核连接成一个文件，它被链接到地址__initramfs_start处，与内核同时被 bootloader加载到ram中，而initrd是另外单独编译生成的，是一个独立的文件，它由bootloader单独加载到ram中内核空间外的地址，比如加载的地址为addr(是物理地址而非虚拟地址)，大小为8MB，那么只要在命令行加入&quot;initrd=addr,8M&quot;命令，系统就可以找到 initrd(当然通过适当修改Linux的目录结构，makefile文件和相关代码，以上两种情况都是可以相通的)。<br />(3) initramfs被解析处理后原始的cpio包(压缩或非压缩)所占的空间(&amp;__initramfs_start - &amp;__initramfs_end)是作为系统的一部分直接保留在系统中，不会被释放掉，而对于initrd镜像文件，如果没有在命令行中设置&quot;keepinitd&quot;命令，那么initrd镜像文件被处理后其原始文件所占的空间(initrd_end - initrd_start)将被释放掉。<br />(4) initramfs可以独立ram disk单独存在，而要支持initrd必须要先支持ram disk，即要配置CONFIG_BLK_DEV_INITRD选项 -- 支持initrd，必须先要配置CONFIG_BLK_DEV_RAM -- 支持ram disk ，因为initrd image实际就是初始化好了的ramdisk镜像文件，最后都要解析、写入到ram disk设备/dev/ram或/dev/ram0中。注: 使用initramfs，命令行参数将不需要&quot;initrd=&quot;和&quot;root=&quot;命令<br />initramfs利弊:<br />------------------------------------------------------<br />由于initramfs使用cpio包格式，所以很容易将一个单一的文件、目录、node编译链接到系统中去，这样很简单的系统中使用起来很方便，不需要另外挂接文件系统。<br />但是因为cpio包实际是文件、目录、节点的描述语言包，为了描述一个文件、目录、节点，要增加很多额外的描述文字开销，特别是对于目录和节点，本身很小额外添加的描述文字却很多，这样使得cpio包比相应的image文件大很多。</p><br /><p>使用initramfs的内核配置(使用initramfs做根文件系统):<br />------------------------------------------------------<br />General setup&#160; ---&gt;<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support<br />(/rootfs_dir) Initramfs source file(s)&#160; &#160;//输入根文件系统的所在目录 <br />使用initramfs的内核启动参数不需要&quot;initrd=&quot;和&quot;root=&quot;参数,但是必须在initramfs中创建/init文件或者修改内核启动最后代码(init文件是软连接，指向什么? init -&gt; bin/busybox，否则内核启动将会失败)<br />链接入内核的initramfs文件在linux-2.6.24/usr/initramfs_data.cpio.gz<br />使用initrd的内核配置(使用网口将根文件系统下载到RAM -- tftp addr ramdisk.gz):<br />------------------------------------------------------<br />1. 配置initrd<br />General setup&#160; ---&gt;<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support<br />() Initramfs source file(s)&#160; &#160;//清空根文件系统的目录配置 <br />2. 配置ramdisk<br />Device Drivers&#160; ---&gt;&#160; &#160;<br />Block devices&#160; ---&gt;<br />&lt; &gt; RAM disk support<br />(16)&#160; Default number of RAM disks&#160; &#160;// 内核在/dev/目录下生成16个ram设备节点<br />(4096) Default RAM disk size (kbytes)<br />(1024) Default RAM disk block size (bytes)<br />使用 initrd的内 核启动参数:initrd=addr,0x400000 root=/dev/ram rw<br />注:<br />(1) addr是根文件系统的下载地址；<br />(2) 0x400000是根文件系统的大小，该大小需要和内核配置的ramdisk size 4096 kbytes相一致；<br />(3) /dev/ram是ramdisk的设备节点，rw表示根文件系统可读、可写；<br />根文件系统存放在FLASH分区：<br />------------------------------------------------------<br />1. 内核启动参数不需要&quot;initrd=&quot;(也可以写成&quot;noinitrd&quot;)；<br />root=/dev/mtdblock2 (/dev/mtdblock2 -- 根文件系统所烧写的FLASH分区)<br />2. 内核配置不需要ram disk；也不需要配置initramfs或者initrd<br />[ ] Initial RAM filesystem and RAM disk (initramfs/initrd) support <br />注: boot的FLASH分区要和kernel的FLASH分区匹配(而非一致)，需要进一步解释。</p>]]></description>
			<author><![CDATA[dummy@example.com (batsom)]]></author>
			<pubDate>Tue, 02 Apr 2024 12:54:48 +0000</pubDate>
			<guid>http://www.gentoo-zh.org/viewtopic.php?pid=973#p973</guid>
		</item>
	</channel>
</rss>
