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 67408
-rw-r--r-- 1 root root  1240067 Jul 13  2016 abi-4.4.0-31-generic
-rw-r--r-- 1 root root  1247269 Aug 15  2017 abi-4.4.0-93-generic
-rw-r--r-- 1 root root   189566 Jul 13  2016 config-4.4.0-31-generic
-rw-r--r-- 1 root root   190364 Aug 15  2017 config-4.4.0-93-generic
drwxr-xr-x 5 root root     4096 Jul  4 17:23 grub
-rw-r--r-- 1 root root 21977388 Aug 24  2017 initrd.img-4.4.0-31-generic
-rw-r--r-- 1 root root 22440248 Aug 24  2017 initrd.img-4.4.0-93-generic
-rw------- 1 root root  3879360 Jul 13  2016 System.map-4.4.0-31-generic
-rw------- 1 root root  3899015 Aug 15  2017 System.map-4.4.0-93-generic
-rw------- 1 root root  6937248 Jul 13  2016 vmlinuz-4.4.0-31-generic
-rw------- 1 root root  7000752 Aug 15  2017 vmlinuz-4.4.0-93-generic
# initrd的文件類型是gzip壓縮文件 #
file /boot/initrd.img-4.4.0-93-generic /boot/initrd.img-4.4.0-93-generic: gzip compressed data, from Unix, last modified: Thu Aug 24 20:51:59 2017
# cp /boot/initrd.img-4.4.0-93-generic .
# 文件大小為22M # ls -lh initrd.img-4.4.0-93-generic -rw-r--r-- 1 root root 22M Jul 5 15:46 initrd.img-4.4.0-93-generic
# 修改文件的后綴名,否則gzip工具無法識別 #
mv initrd.img-4.4.0-93-generic initrd.img-4.4.0-93-generic.gz # 用gzip解壓縮 # gzip -d initrd.img-4.4.0-93-generic.gz # 解壓后的大小為57M # ls -lh initrd.img-4.4.0-93-generic -rw-r--r-- 1 root root 57M Jul 5 15:46 initrd.img-4.4.0-93-generic

# 解壓后的文件類型為cpio檔案 #
file initrd.img-4.4.0-93-generic initrd.img-4.4.0-93-generic: ASCII cpio archive (SVR4 with no CRC)

# 將文件從cpio檔案中copy出來 # cpio
-idmv < initrd.img-4.4.0-93-generic . lib64 lib64/ld-linux-x86-64.so.2 ... lib/systemd lib/systemd/systemd-udevd 115997 blocks

# 最終可以看到如下文件和目錄結構,就是initramrd的結構 #
ls bin conf etc init initrd.img-4.4.0-93-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.6/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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM