Linux系统启动时使用initramfs (initram file system), initramfs可以在启动早期提供一个用户态环境,借助它可以完成一些内核在启动阶段不易完成的工作。当然initramfs是可选的,Linux中的内核编译选项默认开启initrd。在下面的示例情况中你可能要考虑用initramfs。

  • 加载模块,比如第三方driver
  • 定制化启动过程 (比如打印welcome message等)
  • 制作一个非常小的rescue shell
  • 任何kernel不能做的,但在用户态可以做的 (比如执行某些命令)

一个initramfs至少要包含一个文件,文件名为/init。内核将这个文件执行起来的进程作为main init进程(pid 1)。当内核挂载initramfs后,文件系统的根分区还没有被mount, 这意味着你不能访问文件系统中的任何文件。如果你需要一个shell,必须把shell打包到initramfs中,如果你需要一个简单的工具,比如ls, 你也必须把它和它依赖的库或者模块打包到initramfs中。总之,initramfas是一个完全独立运行的体系。

另外initramfs打包的时候,要求打包成压缩的cpio档案。cpio档案可以嵌入到内核image中,也可以作为一个独立的文件在启动的过程中被GRUB load。

Linux的initramrd img

在/boot目录下的initrd.img-xxx (Ubuntu)或者initramfs-xxx.img (CentOS) 文件即为Linux用的initramfs文件。我们可以将其解压出来看看其目录结构,如下:

# ls -l /boot/
total
-rw-r--r-- root root Jul abi-4.4.--generic
-rw-r--r-- root root Aug abi-4.4.--generic
-rw-r--r-- root root Jul config-4.4.--generic
-rw-r--r-- root root Aug config-4.4.--generic
drwxr-xr-x root root Jul : grub
-rw-r--r-- root root Aug initrd.img-4.4.--generic
-rw-r--r-- root root Aug initrd.img-4.4.--generic
-rw------- root root Jul System.map-4.4.--generic
-rw------- root root Aug System.map-4.4.--generic
-rw------- root root Jul vmlinuz-4.4.--generic
-rw------- root root Aug vmlinuz-4.4.--generic
# initrd的文件类型是gzip压缩文件
# file /boot/initrd.img-4.4.--generic
/boot/initrd.img-4.4.--generic: gzip compressed data, from Unix, last modified: Thu Aug :: 2017
# cp /boot/initrd.img-4.4.--generic .
# 文件大小为22M
# ls -lh initrd.img-4.4.--generic
-rw-r--r-- root root 22M Jul : initrd.img-4.4.--generic
# 修改文件的后缀名,否则gzip工具无法识别
# mv initrd.img-4.4.--generic initrd.img-4.4.--generic.gz
# 用gzip解压缩
# gzip -d initrd.img-4.4.--generic.gz
# 解压后的大小为57M
# ls -lh initrd.img-4.4.--generic
-rw-r--r-- root root 57M Jul : initrd.img-4.4.--generic # 解压后的文件类型为cpio档案
# file initrd.img-4.4.--generic
initrd.img-4.4.--generic: ASCII cpio archive (SVR4 with no CRC) # 将文件从cpio档案中copy出来
# cpio -idmv < initrd.img-4.4.--generic
.
lib64
lib64/ld-linux-x86-.so.
...
lib/systemd
lib/systemd/systemd-udevd
blocks # 最终可以看到如下文件和目录结构,就是initramrd的结构
# ls
bin conf etc init initrd.img-4.4.--generic lib lib64 run sbin scripts

可以看到initramfs和跟分区文件系统的雏形很像,只是它的大小不大,少了很多工具和库。有些内核模块就在其中,比如:/lib/modules/4.4.0-93-generic/kernel/。

qemu中启动"Hello World" initramfs

在前文“在qemu环境中用gdb调试Linux内核”中,已经准备了一个Linux启动环境,但是缺少initramfs。我们可以做一个最简单的Hello World initramfs,来直观地理解initramfs。

Hello World的C程序如下,与普通的Hello World相比,加了一行while(1)。

#include <stdio.h>

void main()
{
printf("Hello World\n");
fflush(stdout);
/* 让程序打印完后继续维持在用户态 */
while(1);
}

编译helloworld.c程序

# gcc -static -o helloworld -m32 helloworld.c
  • -static: On systems that support dynamic linking, this prevents linking with the shared libraries. //不让gcc动态链接shared libraries
  • -m32: Generate code for a 32-bit or 64-bit environment //在前文“在qemu环境中用gdb调试Linux内核”中Linux内核被编译成了32位架构,所以这里在gcc的选项中也编译成32位可执行程序

在64位机器上编译成32位程序,可能会报错如下:

In file included from /usr/include/stdio.h:27:0,
from helloworld.c:2:
/usr/include/features.h:374:25: fatal error: sys/cdefs.h: No such file or directory
# include <sys/cdefs.h>
^
compilation terminated.

解决方案是安装libc6-dev-i386包。

# apt-get install libc6-dev-i386

打包initramfs文件

# echo helloworld | cpio -o --format=newc > hwinitramfs

在qemu中启动编译好的内核,把hwinitramfs指定为initrd,在-append参数中将init指定为helloworld。

# qemu -kernel linux-3.18./arch/x86/boot/bzImage -initrd hwinitramfs -append "console=ttyS0 rdinit=helloworld" -nographic

系统能成功启动到输出"Hello World",并且在用户态停住。结合前文“在qemu环境中用gdb调试Linux内核”,可以看到qemu虚机中运行的Linux系统已经成功挂载了initramfs, 在console日志中也能看到“Unpacking initramfs...”。

参考

Custom Initramfs

GNU CPIO Manual

Initramfs 原理和实践的更多相关文章

  1. Atitit 管理原理与实践attilax总结

    Atitit 管理原理与实践attilax总结 1. 管理学分类1 2. 我要学的管理学科2 3. 管理学原理2 4. 管理心理学2 5. 现代管理理论与方法2 6. <领导科学与艺术4 7. ...

  2. Atitit.ide技术原理与实践attilax总结

    Atitit.ide技术原理与实践attilax总结 1.1. 语法着色1 1.2. 智能提示1 1.3. 类成员outline..func list1 1.4. 类型推导(type inferenc ...

  3. Atitit.异步编程技术原理与实践attilax总结

    Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...

  4. Atitit.软件兼容性原理与实践 v5 qa2.docx

    Atitit.软件兼容性原理与实践   v5 qa2.docx 1. Keyword2 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法,新人新办法,只新增,少修改 ...

  5. Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法

    Atitit 表达式原理 语法分析 原理与实践 解析java的dsl  递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...

  6. Atitit.gui api自动化调用技术原理与实践

    Atitit.gui api自动化调用技术原理与实践 gui接口实现分类(h5,win gui, paint opengl,,swing,,.net winform,)1 Solu cate1 Sol ...

  7. Atitit.提升语言可读性原理与实践

    Atitit.提升语言可读性原理与实践 表1-1  语言评价标准和影响它们的语言特性1 1.3.1.2  正交性2 1.3.2.2  对抽象的支持3 1.3.2.3  表达性3 .6  语言设计中的权 ...

  8. Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2

    Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2 1. 数据采集1 1.1. http lib1 1.2. HTML Parsers,1 1.3. 第8章 web爬取199 1 2 ...

  9. Atitit.软件兼容性原理与实践 v3 q326.docx

    Atitit.软件兼容性原理与实践 v3 q326.docx 1. 架构兼容性1 2. Api兼容性1 2.1. 新api  vs  修改旧的api1 3. Web方面的兼容性(js,html)1 3 ...

随机推荐

  1. MySQL在net中Datatime转换

    <add name="adDb"         connectionString="Persist Security Info=False;database=ad ...

  2. [转载]Require.js Example – Setup Time 2 Minutes

    http://www.sitepoint.com/require-js-setup-time-2-minutes/ Setup Require.js in just 2 minutes. or dow ...

  3. 美轮美奂!9款设计独特的jQuery/CSS3全新应用插件(下拉菜单、动画、图表、导航等)

    今天要为大家分享9款设计非常独特的jQuery/CSS3全新应用插件,插件包含菜单.jQuery焦点图.jQuery表单.jQuery图片特效等.下面大家一起来看看吧. 1.jQuery水晶样式下拉导 ...

  4. Linux 下子进程与父进程的关系

    我们知道,Linux下父进程可以使用fork 函数创建子进程,但是当父进程先退出后,子进程会不会也退出呢? 通过下面这个小实验,我们能够很好的看出来: /******** basic.c ****** ...

  5. (转载) 天梯赛 L2-018. 多项式A除以B

    题目链接 题目描述 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给出一个非零多项式,先给出 ...

  6. translate 与 相对、绝对定位

    垂直水平居中是日常前端开发当中一个常见的需求,在支持 CSS3 属性的现代浏览器当中,有一个利用 CSS3 属性的垂直水平居中方法: position absolute; :; :; :transla ...

  7. os._exit(), sys.exit(), exit()

    1. sys.exit(n) 退出程序引发SystemExit异常, 可以捕获异常执行些清理工作. n默认值为0, 表示正常退出. 其他都是非正常退出. 还可以sys.exit("sorry ...

  8. Linux input子系统学习总结(一)---- 三个重要的结构体

    一 . 总体架构 图 上层是图形界面和应用程序,通过监听设备节点,获取用户相应的输入事件,根据输入事件来做出相应的反应:eventX (X从0开始)表示 按键事件,mice 表示鼠标事件 Input ...

  9. TableView 的那些坑

    1. 分割线填满cell宽度, 并且设置分割线的颜色 1.1 利用系统的分割线填充 1.1.1 tableView 设置如下属性 // 给tableView设置如下属性值 tableView.layo ...

  10. 使用Scrapy命令行工具【导出JSON文件】时编码设置

    Windows 10家庭中文版,Python 3.6.4,virtualenv 16.0.0,Scrapy 1.5.0, 使用scrapy命令行工具建立了爬虫项目(startproject),并使用s ...