关闭

嵌入式 Linux操作系统内存磁盘初始化技术详细解析

877人阅读 评论(0) 收藏 举报
分类:

Linux内存初始化技术(initrd)用于支持两阶段的系统引导过程,是在系统启动过程中被挂载的临时root文件系统(译者注:这里的root 文件系统是指的根文件系统)。initrd包含很多可执行程序和驱动,并允许在临时的内存磁盘根文件系统被卸载,内存被释放后挂载真实的root文件系统。在许多嵌入式linux文件系统中,initrd是最终的根文件系统。这篇文章主要讲解了linux2.6内核的initrd技术,包括在内核中的创建及使用。

 

什么是内存磁盘初始化?

 

Initrd挂载优先级高于真实根文件系统,它被邦定在内核上,做为内核启动过程的一部分被加载(load)。然后,做为两阶段引导过程的第一部分,内核挂载(mount)initrd,用于获得并加载真实有效的文件系统。

 

为了达到这个目的,initrd包含有最起码的目录与程序,例如insmod,来安装内核模块到内核中。对于桌面或服务器linux,initrd 是临时文件系统,它的生存周期很短,仅仅是做为到达真实根文件系统的桥梁。但对于没有存储设备的嵌入式系统来说,它才是永久性的根文件系统。本篇文章对这两方面均有涉及。

 

深入分析initrd

 

Initrd 包含有必须的程序和系统文件,用于支持系统的启动的第二阶段过程。创建初始化内存的方法,是随着你所使用的系统版本而改变的。从Fedora Core3以后,initrd就由回送设备(loop device)建立。什么是回送设备?它是一个设备驱动,允许你将一个文件挂载为块设备,并对其文件系统做出描述。也许loop device并不存在与你的内核中,但是你能够通过内核的配置工具(make menuconfig)打开它。路径是:

Device Drivers-》Block Devices-》LoopBack Device support。

 

下面为检查命令:

# 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

#

现在,你可以通过查看/mnt/initrd的子目录来查看initrd的内容。需要注意的是,即使你的initrd镜像文件并不是以.gz做为后缀名,但是你同样可以通过增加此后缀名来让gunzip打开它。

 

从Fedora Core3开始,默认的initrd镜像就是一个压缩的gpio归档文件。除了用挂载文件的方式以外,你同样可以通过cpio归档的方式来将其挂载成使用了回送设备的压缩镜像。你可以通过以下的指令来检查这个cpio归档文件的内容:

# 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

 

你看到的结果将是一个小型根文件系统,如下所示:

 

# 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

#

 

一些小的,但是很有必要的程序组合能在./bin目录下得到,包括nash(它不是一个shell,而是一个脚本解释工具),用于加载内核模块的insmod,以及lvm等。

 

上面所示目录中,相对比较有趣的是root目录下的初始化文件。这些文件,和传统的linux启动过程中一样,是在initrd镜像被解压缩到RAM中时生成的。待会我们将继续探讨这个问题。

 

创建initrd的工具

 

现在,让我们回到一开始的讨论:initrd的镜像是如何被创建的?在传统的linux系统中,initrd是在linux build的时候被创建的。像mkinitrd这样的许许多多的工具,都能够用于通过必须的库和模块来自动构建一个用于过渡到真实根文件系统的 initrd。事实上,mkinitrd工具是一个脚本文件,因此,我们能够很清楚得看到,这个过程是如何进行的。同样的,YAIRD (Yet Another Mkinitrd)工具,也允许我们自定制每一个initrd被构建的阶段。

 

自己动手,打造自定义的初始化内存盘

 

由于很多基于linux的嵌入式系统都没有硬盘驱动器,initrd也可以做为永久性的根文件系统。下面我就将告诉你们,如何创建一个initrd 镜像。我使用的是标准linux桌面系统,因此大家即使没有嵌入式目标设备也可以照着做。除了交叉编译以外,嵌入式目标文件的构建过程是相同的。

 

#!/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

 

想创建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 ()又被调用。这个函数负责分配空间给内存盘,并进行校验计算,解压缩,最后将内存盘镜像加载到内存中。此时,你就已经拥有了一个适合于挂载的,在块设备中的initrd镜像。

 

现在,通过调用init/do_mounts.c:mount_root()将这个块设备做为root挂载。ok,根设备就被创建了,接下来调用的函数是init/do_mounts.c:mount_block_root(),此函数又调用fs/namespace.c: sys_mount()来挂载真实的根文件系统并对其进行chdir操作。

 

最后,会返回到启动函数中,并调用init/main.c:run_init_process。调用的结果是,初始化进程开始(在这里是通过/linuxrc)。linuxrc可以是一个可执行程序,也可以是脚本(只要脚本解释器能够正常解释它)。

 

函数调用的层次关系可以从下表中看出。并不是所有与复制、挂载初始化内存盘的函数都被列举出来,这里仅仅是大概的,对整体基本流程的回顾:

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

 

无盘启动的应用

 

同很多嵌入式系统的启动一样,本地磁盘(软驱或者光驱)对于启动内核和内存盘根文件系统来说,并不是必须的。DHCP工具能被用于确认网络参数,例如大家熟悉的IP抵制和子网掩码等。此外,TFTP能被用于将内核镜像以及初始化内存盘镜像传送到本地设备。一旦传输完成,linux内核就能被启动以及挂载 initrd,和本地镜像启动的过程一样。

 

让你的initrd尽可能小

 

当你在构建嵌入式系统时,总是希望initrd的镜像尽可能小,恩,这里将提供一些小技巧。首先就是使用BusyBox。前面已经提到过,BusyBox包含了很多较大的工具,通常体积都以MB计算,但是它成功得将自己的体积控制在几百KB的范围内。

 

在本例中,BusyBox镜像使用的是静态链接,因此不需要提供任何库文件。但是,如果你需要得到标准的C库文件来满足自己的二进制程序,除了大体积的 glibc库,你有其他更好的选择。第一个,小体积的uClibc库,是专门用于有空间限制的,标准C库的缩水版本。另一个适用于有空间限制环境的库是 dietlib。记住,你需要在自己的嵌入式系统中,用这些库重新编译你的二进制程序。虽然使用它们会带来一些附加的工作,但是,是值得的。

 

总结

初始化内存盘技术被创建的最初目的,是为了让内核通过一个临时的根文件系统来过渡到最终的根文件系统。initrd对于嵌入式linux系统同样是很有用处的:它能做为一个非持续性的根文件系统挂载到内存盘中。


简介: 引导 Linux® 系统的过程包括很多阶段。不管您是引导一个标准的 x86 桌面系统,还是引导一台嵌入式的 PowerPC® 机器,很多流程都惊人地相似。本文将探索 Linux 的引导过程,从最初的引导到启动第一个用户空间应用程序。在本文介绍的过程中,您将学习到各种与引导有关的主题,例如引导加载程序、内核解压、初始 RAM 磁盘以及 Linux 引导的其他一些元素。

发布日期: 2006 年 7 月 26 日 
级别: 初级 
访问情况 : 33138 次浏览 
评论: (查看 添加评论 - 登录)

平均分 5 星 共 92 个评分 平均分 (92个评分)
为本文评分

 

早期时,启动一台计算机意味着要给计算机喂一条包含引导程序的纸带,或者手工使用前端面板地址/数据/控制开关来加载引导程序。尽管目前的计算机已经装备了很多工具来简化引导过程,但是这一切并没有对整个过程进行必要的简化。

让我们先从高级的视角来查看 Linux 引导过程,这样就可以看到整个过程的全貌了。然后将回顾一下在各个步骤到底发生了什么。在整个过程中,参考一下内核源代码可以帮助我们更好地了解内核源代码树,并在以后对其进行深入分析。

概述

图 1 是我们在 20,000 英尺的高度看到的视图。


图 1. Linux 引导过程在 20,000 英尺处的视图
Linux 引导过程在 20,000 英尺处的视图 

当系统首次引导时,或系统被重置时,处理器会执行一个位于已知位置处的代码。在个人计算机(PC)中,这个位置在基本输入/输出系统(BIOS)中,它保存在主板上的闪存中。嵌入式系统中的中央处理单元(CPU)会调用这个重置向量来启动一个位于闪存/ROM 中的已知地址处的程序。在这两种情况下,结果都是相同的。因为 PC 提供了很多灵活性,BIOS 必须确定要使用哪个设备来引导系统。稍后我们将详细介绍这个过程。

当找到一个引导设备之后,第一阶段的引导加载程序就被装入 RAM 并执行。这个引导加载程序在大小上小于 512 字节(一个扇区),其作用是加载第二阶段的引导加载程序。

当第二阶段的引导加载程序被装入 RAM 并执行时,通常会显示一个动画屏幕,并将 Linux 和一个可选的初始 RAM 磁盘(临时根文件系统)加载到内存中。在加载映像时,第二阶段的引导加载程序就会将控制权交给内核映像,然后内核就可以进行解压和初始化了。在这个阶段中,第二阶段的引导加载程序会检测系统硬件、枚举系统链接的硬件设备、挂载根设备,然后加载必要的内核模块。完成这些操作之后启动第一个用户空间程序(init),并执行高级系统初始化工作。

这就是 Linux 引导的整个过程。现在让我们深入挖掘一下这个过程,并深入研究一下 Linux 引导过程的一些详细信息。

回页首

系统启动

系统启动阶段依赖于引导 Linux 系统上的硬件。在嵌入式平台中,当系统加电或重置时,会使用一个启动环境。这方面的例子包括 U-Boot、RedBoot 和 Lucent 的 MicroMonitor。嵌入式平台通常都是与引导监视器搭配销售的。这些程序位于目标硬件上的闪存中的某一段特殊区域,它们提供了将 Linux 内核映像下载到闪存并继续执行的方法。除了可以存储并引导 Linux 映像之外,这些引导监视器还执行一定级别的系统测试和硬件初始化过程。在嵌入式平台中,这些引导监视器通常会涉及第一阶段和第二阶段的引导加载程序。

提取 MBR 的信息

要查看 MBR 的内容,请使用下面的命令:

# dd if=/dev/hda of=mbr.bin bs=512 count=1 #od -xa mbr.bin

这个 dd 命令需要以 root 用户的身份运行,它从 /dev/hda(第一个 IDE 盘) 上读取前 512 个字节的内容,并将其写入 mbr.bin 文件中。od 命令会以十六进制和 ASCII 码格式打印这个二进制文件的内容。

在 PC 中,引导 Linux 是从 BIOS 中的地址 0xFFFF0 处开始的。BIOS 的第一个步骤是加电自检(POST)。POST 的工作是对硬件进行检测。BIOS 的第二个步骤是进行本地设备的枚举和初始化。

给定 BIOS 功能的不同用法之后,BIOS 由两部分组成:POST 代码和运行时服务。当 POST 完成之后,它被从内存中清理了出来,但是 BIOS 运行时服务依然保留在内存中,目标操作系统可以使用这些服务。

要引导一个操作系统,BIOS 运行时会按照 CMOS 的设置定义的顺序来搜索处于活动状态并且可以引导的设备。引导设备可以是软盘、CD-ROM、硬盘上的某个分区、网络上的某个设备,甚至是 USB 闪存。

通常,Linux 都是从硬盘上引导的,其中主引导记录(MBR)中包含主引导加载程序。MBR 是一个 512 字节大小的扇区,位于磁盘上的第一个扇区中(0 道 0 柱面 1 扇区)。当 MBR 被加载到 RAM 中之后,BIOS 就会将控制权交给 MBR。

回页首

第一阶段引导加载程序

MBR 中的主引导加载程序是一个 512 字节大小的映像,其中包含程序代码和一个小分区表(参见图 2)。前 446 个字节是主引导加载程序,其中包含可执行代码和错误消息文本。接下来的 64 个字节是分区表,其中包含 4 个分区的记录(每个记录的大小是 16 个字节)。MBR 以两个特殊数字的字节(0xAA55)结束。这个数字会用来进行 MBR 的有效性检查。


图 2. MBR 剖析
MBR 剖析 

主引导加载程序的工作是查找并加载次引导加载程序(第二阶段)。它是通过在分区表中查找一个活动分区来实现这种功能的。当找到一个活动分区时,它会扫描分区表中的其他分区,以确保它们都不是活动的。当这个过程验证完成之后,就将活动分区的引导记录从这个设备中读入 RAM 中并执行它。

回页首

第二阶段引导加载程序

次引导加载程序(第二阶段引导加载程序)可以更形象地称为内核加载程序。这个阶段的任务是加载 Linux 内核和可选的初始 RAM 磁盘。

GRUB 阶段引导加载程序

/boot/grub 目录中包含了 stage1、stage1.5  stage2 引导加载程序,以及很多其他加载程序(例如,CR-ROM 使用的是 iso9660_stage_1_5)。

在 x86 PC 环境中,第一阶段和第二阶段的引导加载程序一起称为 Linux Loader(LILO)或 GRand Unified Bootloader(GRUB)。由于 LILO 有一些缺点,而 GRUB 克服了这些缺点,因此下面让我们就来看一下 GRUB。(有关 GRUB、LILO 和相关主题的更多内容,请参阅本文后面的 参考资料 部分的内容。)

关于 GRUB,很好的一件事情是它包含了有关 Linux 文件系统的知识。GRUB 不像 LILO 一样使用裸扇区,而是可以从 ext2 或 ext3 文件系统中加载 Linux 内核。它是通过将两阶段的引导加载程序转换成三阶段的引导加载程序来实现这项功能的。阶段 1 (MBR)引导了一个阶段 1.5 的引导加载程序,它可以理解包含 Linux 内核映像的特殊文件系统。这方面的例子包括 reiserfs_stage1_5(要从 Reiser 日志文件系统上进行加载)或 e2fs_stage1_5(要从 ext2 或 ext3 文件系统上进行加载)。当阶段 1.5 的引导加载程序被加载并运行时,阶段 2 的引导加载程序就可以进行加载了。

当阶段 2 加载之后,GRUB 就可以在请求时显示可用内核列表(在 /etc/grub.conf 中进行定义,同时还有几个软符号链接/etc/grub/menu.lst  /etc/grub.conf)。我们可以选择内核甚至修改附加内核参数。另外,我们也可以使用一个命令行的 shell 对引导过程进行高级手工控制。

将第二阶段的引导加载程序加载到内存中之后,就可以对文件系统进行查询了,并将默认的内核映像和 initrd 映像加载到内存中。当这些映像文件准备好之后,阶段 2 的引导加载程序就可以调用内核映像了。

回页首

内核

GRUB 中的手工引导

在 GRUB 命令行中,我们可以使用 initrd 映像引导一个特定的内核,方法如下:

grub> kernel /bzImage-2.6.14.2
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub> initrd /initrd-2.6.14.2.img
[Linux-initrd @ 0x5f13000, 0xcc199 bytes]
grub> boot
Uncompressing Linux... Ok, booting the kernel.

如果您不知道要引导的内核的名称,只需使用斜线(/)然后按下 Tab 键即可。GRUB 会显示内核和 initrd 映像列表。

当内核映像被加载到内存中,并且阶段 2 的引导加载程序释放控制权之后,内核阶段就开始了。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像。通常它是一个 zImage(压缩映像,小于 512KB)或一个 bzImage(较大的压缩映像,大于 512KB),它是提前使用 zlib 进行压缩过的。在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始 RAM 磁盘映像,就会将它移动到内存中,并标明以后使用。然后该例程会调用内核,并开始启动内核引导的过程。

当 bzImage(用于 i386 映像)被调用时,我们从./arch/i386/boot/head.S  start 汇编例程开始执行(主要流程图请参看图 3)。这个例程会执行一些基本的硬件设置,并调用./arch/i386/boot/compressed/head.S 中的 startup_32 例程。此例程会设置一个基本的环境(堆栈等),并清除 Block Started by Symbol(BSS)。然后调用一个叫做 decompress_kernel 的 C 函数(在 ./arch/i386/boot/compressed/misc.c 中)来解压内核。当内核被解压到内存中之后,就可以调用它了。这是另外一个 startup_32 函数,但是这个函数在 ./arch/i386/kernel/head.S 中。

在这个新的 startup_32 函数(也称为清除程序或进程 0)中,会对页表进行初始化,并启用内存分页功能。然后会为任何可选的浮点单元(FPU)检测 CPU 的类型,并将其存储起来供以后使用。然后调用 start_kernel 函数(在 init/main.c 中),它会将您带入与体系结构无关的 Linux 内核部分。实际上,这就是 Linux 内核的 main 函数。


图 3. Linux 内核 i386 引导的主要函数流程 
Linux 内核 i386 引导的主要函数流程  

通过调用 start_kernel,会调用一系列初始化函数来设置中断,执行进一步的内存配置,并加载初始 RAM 磁盘。最后,要调用kernel_thread(在 arch/i386/kernel/process.c 中)来启动 init 函数,这是第一个用户空间进程(user-space process)。最后,启动空任务,现在调度器就可以接管控制权了(在调用 cpu_idle 之后)。通过启用中断,抢占式的调度器就可以周期性地接管控制权,从而提供多任务处理能力。

在内核引导过程中,初始 RAM 磁盘(initrd)是由阶段 2 引导加载程序加载到内存中的,它会被复制到 RAM 中并挂载到系统上。这个 initrd 会作为 RAM 中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导。由于与外围设备进行交互所需要的模块可能是 initrd 的一部分,因此内核可以非常小,但是仍然需要支持大量可能的硬件配置。在内核引导之后,就可以正式装备根文件系统了(通过 pivot_root):此时会将 initrd 根文件系统卸载掉,并挂载真正的根文件系统。

decompress_kernel 输出

函数 decompress_kernel 就是显示我们通常看到的解压消息的地方:

Uncompressing Linux... Ok, booting the kernel.

initrd 函数让我们可以创建一个小型的 Linux 内核,其中包括作为可加载模块编译的驱动程序。这些可加载的模块为内核提供了访问磁盘和磁盘上的文件系统的方法,并为其他硬件提供了驱动程序。由于根文件系统是磁盘上的一个文件系统,因此 initrd 函数会提供一种启动方法来获得对磁盘的访问,并挂载真正的根文件系统。在一个没有硬盘的嵌入式环境中,initrd 可以是最终的根文件系统,或者也可以通过网络文件系统(NFS)来挂载最终的根文件系统。

回页首

Init

当内核被引导并进行初始化之后,内核就可以启动自己的第一个用户空间应用程序了。这是第一个调用的使用标准 C 库编译的程序。在此之前,还没有执行任何标准的 C 应用程序。

在桌面 Linux 系统上,第一个启动的程序通常是 /sbin/init。但是这不是一定的。很少有嵌入式系统会需要使用 init 所提供的丰富初始化功能(这是通过 /etc/inittab 进行配置的)。在很多情况下,我们可以调用一个简单的 shell 脚本来启动必需的嵌入式应用程序。

回页首

结束语

与 Linux 本身非常类似,Linux 的引导过程也非常灵活,可以支持众多的处理器和硬件平台。最初,加载引导加载程序提供了一种简单的方法,不用任何花架子就可以引导 Linux。LILO 引导加载程序对引导能力进行了扩充,但是它却缺少文件系统的感知能力。最新一代的引导加载程序,例如 GRUB,允许 Linux 从一些文件系统(从 Minix 到 Reise)上进行引导。


参考资料

学习

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文 

  • Boot Records Revealed 是有关 MBR 和各种引导加载程序很好的资源。这个资源不仅仅是有关 MBR 的资料的汇编,还讨论了 GRUB、LILO 和各种 Windows® 引导加载程序的问题。 

  • 请查看 Disk Geometry 页面来理解磁盘及其结构。您会发现有关磁盘的有用属性。 

  • live CD 是一个可以从 CD 或 DVD 上引导的操作系统,它不需要使用硬盘。 

  • “引导加载程序之争:了解 LILO 和 GRUB”(developerWorks,2005 年 8 月)详细介绍了 LILO 和 GRUB 引导加载程序。 

  • 在 developerWorks 上的 LPI 考试准备 系列教程中,我们可以学习有关引导 Linux 系统的详细介绍,以及在准备参加系统管理员认证考试时需要准备的 Linux 基础知识。 

  • LILO 是 GRUB 的先驱,但是我们可能发现它依然可以引导 Linux。 

  • mkintrd 命令用来创建初始的 RAM 磁盘映像。这个命令可以用来构建初始的根文件系统,它可以用来引导允许提前加载访问真正根文件系统所需要的块设备的配置。 

  •  Debian Linux Kernel Project 中,我们可以找到更多有关 Linux 内核、引导和嵌入式开发的信息。 

  •  developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多资源。 

  • 随时关注 developerWorks 技术事件和网络广播。 

获得产品和技术

  • MicroMonitor 为各种小型的目标设备提供了引导环境。我们可以使用这个监视器在嵌入式环境中引导 Linux。它已经移植到 ARM、 XScale、MIPS、PowerPC、Coldfire 和 Hitachi 的 Super-H 上了。 

  • GNU GRUB 是一个具有众多选项和灵活性的引导 shell。 

  • LinuxBIOS 是 BIOS 的一个替代品。LinuxBIOS 不但可以引导 Linux,而且它本身就是一个压缩的 Linux 内核。 

  • OpenBIOS 是另一个可移植的 BIOS 项目,可以在很多体系结构上进行操作,例如 x86、Alpha 和 AMD64。 

  •  kernel.org 上可以找到最新的内核树。 

  • 使用 IBM 试用版软件 改进您的下一个开发项目,从 developerWorks 上可以直接下载这些软件。 

讨论

  • 通过参与 developerWorks blogs 加入 developerWorks 社区。 

 

 

什么是初始 RAM 磁盘?

初始 RAM 磁盘(initrd)是在实际根文件系统可用之前挂载到系统中的一个初始根文件系统。initrd 与内核绑定在一起,并作为内核引导过程的一部分进行加载。内核然后会将这个 initrd 文件作为其两阶段引导过程的一部分来加载模块,这样才能稍后使用真正的文件系统,并挂载实际的根文件系统。

initrd 中包含了实现这个目标所需要的目录和可执行程序的最小集合,例如将内核模块加载到内核中所使用的 insmod 工具。

在桌面或服务器 Linux 系统中,initrd 是一个临时的文件系统。其生存周期很短,只会用作到真实文件系统的一个桥梁。在没有存储设备的嵌入式系统中,initrd 是永久的根文件系统。本文将对这两种情况进行探索。

回页首

initrd 剖析

initrd 映像中包含了支持 Linux 系统两阶段引导过程所需要的必要可执行程序和系统文件。

根据我们运行的 Linux 的版本不同,创建初始 RAM 磁盘的方法也可能会有所不同。在 Fedora Core 3 之前,initrd 是使用 loop 设备来构建的。loop 设备 是一个设备驱动程序,利用它可以将文件作为一个块设备挂载到系统中,然后就可以查看这个文件系统中的内容了。在您的内核中可能并没有 loop 设备,不过这可以通过内核配置工具(make menuconfig)选择 Device Drivers > Block Devices > Loopback Device Support 来启用。我们可以按照下面的方法来查看 loop 设备的内容(initrd 文件的名字可能会稍有不同):


清单 1. 查看 initrd 的内容(适用于 FC3 之前的版本)

# 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 #

现在我们就可以查看 /mnt/initrd 子目录中的内容了,这就代表了 initrd 文件的内容。注意,即使您的 initrd 映像文件不是以 .gz 结尾,它也可能是一个压缩文件,您可以给这个文件添加上 .gz 后缀,然后再使用 gunzip 对其进行解压。

从 Fedora Core 3 开始,默认的 initrd 映像变成了一个经过压缩的 cpio 归档文件。我们不用再使用 loop 设备来将 initrd 作为压缩映像进行挂载,而是可以将其作为 cpio 归档文件来使用。要查看 cpio 归档文件的内容,可以使用下面的命令:


清单 2. 查看 initrd 的内容(适用于 FC3 及其以后的版本)

# 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 #

结果会生成一个很小的根文件系统,如清单 3 所示。在 ./bin 目录中有一组很少但却非常必要的应用程序,包括 nash(即 not a shell,是一个脚本解释器)、insmod(用来加载内核模块)和 lvm(逻辑卷管理工具)。


清单 3. 默认的 Linux 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 #

清单 3 中比较有趣的是 init 文件就在根目录中。与传统的 Linux 引导过程类似,这个文件也是在将 initrd 映像解压到 RAM 磁盘中时被调用的。在本文稍后我们将来探索这个问题。

回页首

创建 initrd 所使用的工具

cpio 命令

使用 cpio 命令,我们可以对 cpio 文件进行操作。cpio 是一种文件格式,它简单地使用文件头将一组文件串接在一起。cpio 文件格式可以使用 ASCII 和二进制文件。为了保证可移植性,我们可以使用 ASCII 格式。为了减小文件大小,我们可以使用二进制的版本。

下面让我们回到最开始,来看一下 initrd 映像最初是如何构建的。对于传统的 Linux 系统来说,initrd 映像是在 Linux 构建过程中创建的。有很多工具,例如 mkinitrd,都可以用来使用必要的库和模块自动构建 initrd,从而用作与真实的根文件系统之间的桥梁。mkinitrd 工具实际上就是一个 shell 脚本,因此我们可以看到它究竟是如何来实现这个结果的。还有一个 YAIRD(即 Yet Another Mkinitrd)工具,可以对 initrd 构建过程的各个方面进行定制。

回页首

手工构建定制的初始 RAM 磁盘

由于在很多基于 Linux 的嵌入式系统上没有硬盘,因此 initrd 也会作为这种系统上的永久根文件系统使用。清单 4 显示了如何创建一个 initrd 映像文件。我使用了一个标准的 Linux 桌面,这样您即使没有嵌入式平台,也可以按照下面的步骤来执行了。除了交叉编译,其他概念(也适用于 initrd 的构建)对于嵌入式平台都是相同的。


清单 4. 创建定制 initrd 的工具(mkird) 

#!/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

initrd Linux 发行版

Minimax 是一个开放源码项目,其设计目标是成为一个全部封装在 initrd 中的 Linux 发行版。它的大小是 32MB,为了尽量小,它使用了 BusyBox 和 uClibc。除了非常小之外,它还使用了 2.6 版本的 Linux 内核,并提供了很多有用的工具。

为了创建 initrd,我们最开始创建了一个空文件,这使用了/dev/zero(一个由零组成的码流)作为输入,并将其写入到 ramdisk.img 文件中。所生成的文件大小是 4MB(4000 个 1K 大小的块)。然后使用 mke2fs 命令在这个空文件上创建了一个 ext2(即 second extended)文件系统。现在这个文件变成了一个 ext2 格式的文件系统,我们使用 loop 设备将这个文件挂载到 /mnt/initrd 上了。在这个挂载点上,我们现在就有了一个目录,它以 ext2 文件系统的形式呈现出来,我们可以对自己的 initrd 文件进行拼装了。接下来的脚本提供了这种功能。

下一个步骤是创建构成根文件系统所需要的子目录:/bin、/sys、/dev 和 /proc。这里只列出了所需要的目录(例如没有库),但是其中包含了很多功能。

ext2 文件系统的替代品

尽管 ext2 是一种通用的 Linux 文件系统格式,但是还有一些替代品可以减小 initrd 映像文件以及所挂载上来的文件系统的大小。这种文件系统的例子有 romfs(ROM 文件系统)、cramfs(压缩 ROM 文件系统)和 squashfs(高度压缩只读文件系统)。如果我们需要暂时将数据写入文件系统中,ext2 可以很好地实现这种功能。最后,e2compr 是 ext2 文件系统驱动程序的一个扩展,可以支持在线压缩。

为了可以使用根文件系统,我们使用了 BusyBox。这个工具是一个单一映像,其中包含了很多在 Linux 系统上通常可以找到的工具(例如 ash、awk、sed、insmod 等)。BusyBox 的优点是它将很多工具打包成一个文件,同时还可以共享它们的通用元素,这样可以极大地减少映像文件的大小。这对于嵌入式系统来说非常理想。将 BusyBox 映像从自己的源目录中拷贝到自己根目录下的 /bin 目录中。然后创建了很多符号链接,它们都指向 BusyBox 工具。BusyBox 会判断所调用的是哪个工具,并执行这个工具的功能。我们在这个目录中创建了几个链接来支持 init 脚本(每个命令都是一个指向 BusyBox 的链接。)

下一个步骤是创建几个特殊的设备文件。我从自己当前的 /dev 子目录中直接拷贝了这些文件,这使用了 -a 选项(归档)来保留它们的属性。

倒数第二个步骤是生成 linuxrc 文件。在内核挂载 RAM 磁盘之后,它会查找 init 文件来执行。如果没有找到 init 文件,内核就会调用 linuxrc 文件作为自己的启动脚本。我们在这个文件中实现对环境的基本设置,例如挂载 /proc 文件系统。除了 /proc 之外,我还挂载了 /sys 文件系统,并向终端打印一条消息。最后,我们调用了 ash(一个 Bourne Shell 的克隆),这样就可以与根文件系统进行交互了。linuxrc 文件然后使用 chmod 命令修改成可执行的。

最后,我们的根文件系统就完成了。我们将其卸载掉,然后使用 gzip 对其进行压缩。所生成的文件(ramdisk.img.gz)被拷贝到 /boot 子目录中,这样就可以通过 GNU GRUB 对其进行加载了。

要构建初始 RAM 磁盘,我们可以简单地调用 mkird,这样就会自动创建这个映像文件,并将其拷贝到 /boot 目录中。

回页首

测试定制的初始 RAM 磁盘

Linux 内核中对 initrd 的支持

对于 Linux 内核来说,要支持初始 RAM 磁盘,内核必须要使用 CONFIG_BLK_DEV_RAM  CONFIG_BLK_DEV_INITRD选项进行编译。

新的 initrd 映像现在已经在 /boot 目录中了,因此下一个步骤是使用默认的内核来对其进行测试。现在我们可以重新启动 Linux 系统了。在出现 GRUB 界面时,按 C 键启动 GRUB 中的命令行工具。我们现在可以与 GRUB 进行交互,从而定义要加载哪个内核和 initrd 映像文件。kernel 命令让我们可以指定内核文件,initrd 命令可以用来指定 initrd 映像文件。在定义好这些参数之后,就可以使用 boot 命令来引导内核了,如清单 5 所示。


清单 5. 使用 GRUB 手工引导内核和 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=0x1400, size=0x29672e] grub> initrd /ramdisk.img.gz [Linux-initrd @ 0x5f2a000, 0xb5108 bytes] grub> boot Uncompressing Linux... OK, booting the kernel.

在内核启动之后,它会检查是否有 initrd 映像文件可用(稍后会更详细介绍),然后将其加载,并将其挂载成根文件系统。在清单 6 中我们可以看到这个 Linux 启动过程最后的样子。在启动之后,ash shell 就可以用来输入命令了。在这个例子中,我们将浏览一下根文件系统的内容,并查看一下虚拟 proc 文件系统中的内容。我们还展示了如何通过 touch 命令在文件系统中创建文件。注意所创建的第一个进程是 linuxrc(通常都是 init)。


清单 6. 使用简单的 initrd 引导 Linux 内核 

... 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 / $ lsbin 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

回页首

使用初始 RAM 磁盘来引导系统

现在我们已经了解了如何构建并使用定制的初始 RAM 磁盘,本节将探索内核是如何识别 initrd 并将其作为根文件系统进行挂载的。我们将介绍启动链中的几个主要函数,并解释一下到底在进行什么操作。

引导加载程序,例如 GRUB,定义了要加载的内核,并将这个内核映像以及相关的 initrd 拷贝到内存中。我们可以在 Linux 内核源代码目录中的 ./init 子目录中找到很多这种功能。

在内核和 initrd 映像被解压并拷贝到内存中之后,内核就会被调用了。它会执行不同的初始化操作,最终您会发现自己到了init/main.c:init()(subdir/file:function)函数中。这个函数执行了大量的子系统初始化操作。此处会执行一个对init/do_mounts.c:prepare_namespace() 的调用,这个函数用来准备名称空间(挂载 dev 文件系统、RAID 或 md、设备以及最后的 initrd)。加载 initrd 是通过调用 init/do_mounts_initrd.c:initrd_load() 实现的。

initrd_load() 函数调用了 init/do_mounts_rd.c:rd_load_image(),它通过调用 init/do_mounts_rd.c:identify_ramdisk_image()来确定要加载哪个 RAM 磁盘。这个函数会检查映像文件的 magic 号来确定它是 minux、etc2、romfs、cramfs 或 gzip 格式。在返回到 initrd_load_image 之前,它还会调用 init/do_mounts_rd:crd_load()。这个函数负责为 RAM 磁盘分配空间,并计算循环冗余校验码(CRC),然后对 RAM 磁盘映像进行解压,并将其加载到内存中。现在,我们在一个适合挂载的块设备中就有了这个 initrd 映像。

现在使用一个 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() 来真正挂载根文件系统,然后 chdir 到这个文件系统中。这就是我们在清单 6 中所看到的熟悉消息VFS: Mounted root (ext2 file system). 的地方。

最后,返回到 init 函数中,并调用 init/main.c:run_init_process。这会导致调用 execve 来启动 init 进程(在本例中是/linuxrc)。linuxrc 可以是一个可执行程序,也可以是一个脚本(条件是它有脚本解释器可用)。

这些函数的调用层次结构如清单 7 所示。尽管此处并没有列出拷贝和挂载初始 RAM 磁盘所涉及的所有函数,但是这足以为我们提供一个整体流程的粗略框架。


清单 7. initrd 加载和挂载过程中所使用的主要函数的层次结构 

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

回页首

无盘引导

与嵌入式引导的情况类似,本地磁盘(软盘或 CD-ROM)对于引导内核和 ramdisk 根文件系统来说都不是必需的。DHCP(Dynamic Host Configuration Protocol)可以用来确定网络参数,例如 IP 地址和子网掩码。TFTP(Trivial File Transfer Protocol)可以用来将内核映像和初始 ramdisk 映像传输到本地设备上。传输完成之后,就可以引导 Linux 内核并挂载 initrd 了,这与本地映像引导的过程类似。

回页首

压缩 initrd

在构建嵌入式系统时,我们可能希望将 initrd 映像文件做得尽可能小,这其中有一些技巧需要考虑。首先是使用 BusyBox(本文中已经展示过了)。BusyBox 可以将数 MB 的工具压缩成几百 KB。

在这个例子中,BusyBox 映像是静态链接的,因此它不需要其他库。然而,如果我们需要标准的 C 库(我们自己定制的二进制可能需要这个库),除了巨大的 glibc 之外,我们还有其他选择。第一个较小的库是 uClibc,这是为对空间要求非常严格的系统准备的一个标准 C 库。另外一个适合空间紧张的环境的库是 dietlib。要记住我们需要使用这些库来重新编译想在嵌入式系统中重新编译的二进制文件,因此这需要额外再做一些工作(但是这是非常值得的)。

回页首

结束语

初始 RAM 磁盘最初是设计用来通过一个临时根文件系统来作为内核到最终的根文件系统之间的桥梁。initrd 对于在嵌入式系统中加载到 RAM 磁盘里的非持久性根文件系统来说也非常有用。


 

参考资料

学习

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文 

  • “Linux 引导过程内幕”(developerWorks,2006 年 5 月)探索了 Linux 从最初的 bootstrap 到启动第一个用户空间应用程序的过程。 

  • 在 “从 FireWire 设备引导 Linux”(developerWorks,2004 年 7 月)中,我们可以学习在各种平台的各种设备上如何(使用 initrd)启动 Linux。 

  • cpio 文件格式 既简单又简洁。因此 Fedora 团队选择使用它作为 initrd 的格式就没什么奇怪的了。 

  • mkinitrd 工具非常适合创建 initrd 映像文件。除了创建 initrd 映像之外,它还可以确定要为您的系统加载哪些模块,并将这些模块也全部加入到这个映像中。 

  • loop 设备 是一个非常有用的驱动程序,可以将映像文件作为文件系统挂载。 

  • Network Boot and Exotic Root HOWTO 不但介绍了从网络上引导 Linux 的过程,还介绍了诸如软盘引导、CD-ROM 引导和嵌入式环境中的内容。 

  •  developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多资源。 

  • 随时关注 developerWorks 技术事件和网络广播。 

获得产品和技术

  • cpio 文件格式(现在可以用作 Fedora Core 的一种 initrd 映像格式)具有很长的历史,可以在很多 UNIX 系统上使用。 

  • ash shell 是 Bourne Shell 的一个克隆(它们大部分是兼容的),它虽然很小,但是完全可以正常工作。它非常适合在对空间要求非常严格的嵌入式系统上用作脚本解释器。 

  • BusyBox 是一种缩减您下一个嵌入式 Linux 项目内存需求的好方法。 

  • 要进一步缩减 initrd 文件的大小,请考虑使用 glibc 的替代库,例如 uClibc  dietlib。如果您喜欢使用 C++,那么可以试用一下 uClibc++ 库的 Alpha 版本。 

  • Minimax 是一个完全封装在 initrd 映像文件中的 Linux 发行版! 

  • 订购免费的 SEK for Linux,这有两张 DVD,包括最新的 IBM for Linux 的试用软件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。 

  • 在您的下一个开发项目中采用 IBM 试用软件,这可以从 developerWorks 上直接下载。 

讨论

  • 通过参与 developerWorks blogs 加入 developerWorks 社区。 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1044790次
    • 积分:18255
    • 等级:
    • 排名:第522名
    • 原创:741篇
    • 转载:523篇
    • 译文:0篇
    • 评论:105条
    最新评论