Initramfs 原理和实践
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...”。
参考
Initramfs 原理和实践的更多相关文章
- Atitit 管理原理与实践attilax总结
Atitit 管理原理与实践attilax总结 1. 管理学分类1 2. 我要学的管理学科2 3. 管理学原理2 4. 管理心理学2 5. 现代管理理论与方法2 6. <领导科学与艺术4 7. ...
- Atitit.ide技术原理与实践attilax总结
Atitit.ide技术原理与实践attilax总结 1.1. 语法着色1 1.2. 智能提示1 1.3. 类成员outline..func list1 1.4. 类型推导(type inferenc ...
- Atitit.异步编程技术原理与实践attilax总结
Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...
- Atitit.软件兼容性原理与实践 v5 qa2.docx
Atitit.软件兼容性原理与实践 v5 qa2.docx 1. Keyword2 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法,新人新办法,只新增,少修改 ...
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...
- Atitit.gui api自动化调用技术原理与实践
Atitit.gui api自动化调用技术原理与实践 gui接口实现分类(h5,win gui, paint opengl,,swing,,.net winform,)1 Solu cate1 Sol ...
- Atitit.提升语言可读性原理与实践
Atitit.提升语言可读性原理与实践 表1-1 语言评价标准和影响它们的语言特性1 1.3.1.2 正交性2 1.3.2.2 对抽象的支持3 1.3.2.3 表达性3 .6 语言设计中的权 ...
- Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2
Atitit 网络爬虫与数据采集器的原理与实践attilax著 v2 1. 数据采集1 1.1. http lib1 1.2. HTML Parsers,1 1.3. 第8章 web爬取199 1 2 ...
- Atitit.软件兼容性原理与实践 v3 q326.docx
Atitit.软件兼容性原理与实践 v3 q326.docx 1. 架构兼容性1 2. Api兼容性1 2.1. 新api vs 修改旧的api1 3. Web方面的兼容性(js,html)1 3 ...
随机推荐
- javascript里你绝对用的上的字符分割函数--原创
// 在数组内字符为未知情况下,合并和分割的解决方案 var data = [['your name', 'myvalue'], ['myr name', 'thivalue']]; function ...
- 简单几招,解决jQuery.getJSON的缓存问题
今天做测试工作,发现了一个令我费解的问题,jquery的getJson方法在firefox上运行可以得到返回的结果,但是在ie8上测试,竟发现没有发送请求,故不能取到任何返回的结果,经历了一翻周折,找 ...
- 使iis支持asp.net扩展
打开控制面板 - 程序和功能,点击左边 “打开或关闭 Windows 功能”. 在弹出的对话框中,展开 “Internet信息服务”,展开“万维网服务”,展开“应用程序开发功能”,勾选“ASP”和“A ...
- 【leetcode 简单】 第八十一题 4的幂
给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方. 示例 1: 输入: 16 输出: true 示例 2: 输入: 5 输出: false 进阶: 你能不使用循环或者递 ...
- php登陆界面刷新验证码 javascript 的写法
<script type="text/javascript"> function refreshVerify(){ var imgId = document.getEl ...
- 移动开发关于APN的知识整理
APN(Access Point Name),即"接入点名称",用来标识GPRS的业务种类,是通过手机上网时必须配置的一个参数,其决定了手机通过哪种接入方式来访问网络. 一.类别 ...
- Lucene7.1.0版本的索引创建与查询以及维护,包括新版本的一些新特性探索!
一 吐槽 lucene版本更新实在太快了,往往旧版本都还没学会,新的就出来,而且每个版本改动都特别大,尤其是4.7,6,6,7.1.......ε=(´ο`*)))唉,但不可否认,新版本确实要比旧版本 ...
- 在Eclipse使用Gradle
1.Gradle安装 1.Grandle官网下载Gradle,地址:http://www.gradle.org/downloads 2.设置环境变量,需要设置如下2个环境变量 2.1添加GRADLE_ ...
- C# byte[] 转换16进制字符串
1.byte[] 转换16进制字符串 1.1 BitConverter方式 var str = DateTime.Now.ToString(); var encode = Encoding.UTF8; ...
- js写的一些通用方法
Js获取当前浏览器支持的transform兼容写法 // 获取当前浏览器支持的transform兼容写法 function getTransfrom() { var transform = '', / ...