热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>内核研究>

Linux 初始 RAM 磁盘(initrd)概述

来源: 作者: 时间:2007-06-05 Tag: 点击:

引导加载程序,例如 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 磁盘里的非持久性根文件系统来说也非常有用。

原文链接:http://www-128.ibm.com/developerworks/cn/linux/l-initrd.html




相关文章:
精通initramfs构建step by step
Linux利用kexec迅速切换内核
进程上下文VS中断上下文
内核通知链 学习笔记
linux spi子系统驱动分析
menuconfig 配置选项
《Linux操作系统内核实习》之练习一
udev详解
什么叫微内核,宏内核?
Linux 信号signal处理机制
开发简单的 Linux2.6 内核模块
删除内核的perl脚本
Linux2.6内核usb gadget驱动移植
GCC hacks in the Linux kernel
iomem
kernel学习的想法
让自己的驱动支持udev
linux内核编译步骤
内核的等待队列
Linux内核wait_queue深入分析
升级和删除内核
SD卡驱动分析2
Linux Kernel VDSO本地权限提升漏洞
内核中的TCP的追踪分析-15-TCP(IPV4)的客户端与
linux 2.6内核可加载模块的编译
内核模块HelloWorld
在环回接口上发送一个数据报
ARP初始化
1分钟编译FreeBSD内核
linux设备模型之uart驱动架构分析