3. 构建最小根文件系统:BusyBox、initramfs 与 rootfs.ext4

根文件系统是内核启动后挂载的第一个文件系统,它提供了 /sbin/init、Shell、基础命令以及必要的设备节点。在 QEMU 调试场景中,我们通常使用两种形态:initramfs(内存中的临时根文件系统)和 rootfs.ext4(磁盘镜像中的持久根文件系统)。本章将使用 BusyBox 构建这两种形态,并配置内核启动参数使其正确挂载。

核心目标: 使用 BusyBox 编译出最小化的用户态工具集,打包为 initramfs 或写入 ext4 镜像,最终通过 QEMU 启动并进入 Shell。

3.1 构建流程总览

下图展示了从 BusyBox 源码到 QEMU 启动的完整构建与部署链路:

BusyBox 构建与根文件系统部署流程 BusyBox 源码 make menuconfig make & make install _install 目录 选择形态 cpio 打包 initramfs dd + mkfs.ext4 QEMU 内核启动验证

3.2 使用 BusyBox 构建用户态工具集

3.2.1 下载与配置

从 busybox.net 获取稳定版本(本文以 1.36.1 为例):

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1

执行 make menuconfig 进行配置,关键选项如下表:

配置路径推荐值说明
Settings → Build static binary (no shared libs)选中静态编译,避免依赖动态库,简化部署
Settings → Cross compiler prefixarm-linux-gnueabi-交叉编译时指定,本地编译留空
Settings → Destination path for 'make install'./_install安装到本地 _install 目录
Linux Module Utilities → Simplified modutils选中支持内核模块加载(调试驱动时必需)
调试建议: 静态编译的 BusyBox 二进制体积约 800KB–1.2MB,虽然比动态版大,但可以避免在 initramfs 中复制 libc,显著降低根文件系统的构建复杂度。

3.2.2 编译与安装

# 本地编译(x86_64 调试用)
make -j$(nproc)
make install

# 交叉编译(ARM 目标)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j$(nproc)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install

安装完成后,_install 目录结构如下:

_install/
├── bin/
│   ├── sh -> busybox
│   ├── ls -> busybox
│   ├── mount -> busybox
│   └── ... (所有命令均为指向 busybox 的符号链接)
├── sbin/
│   └── init -> ../bin/busybox
├── usr/
│   ├── bin/
│   └── sbin/
└── linuxrc -> bin/busybox

3.3 构建 initramfs

initramfs 是一个 cpio 归档,内核在初始化阶段将其解压到 tmpfs 中作为临时根文件系统。构建步骤如下:

3.3.1 创建必要目录与设备节点

cd _install
mkdir -p proc sys dev etc/init.d

# 创建控制台设备节点(必须,否则无法进入 Shell)
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3

3.3.2 编写 init 脚本

创建 etc/init.d/rcS 作为启动脚本:

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp

# 打印内核版本信息
cat /proc/version

# 启动 Shell
exec /bin/sh

赋予执行权限:chmod +x etc/init.d/rcS

创建 etc/inittab(BusyBox init 默认读取):

::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh

3.3.3 打包为 cpio 归档

find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz

生成的 initramfs.cpio.gz 可直接作为内核的 initramfs 源。

3.4 制作 rootfs.ext4 磁盘镜像

当需要持久化存储或测试块设备驱动时,使用 ext4 镜像更合适。

3.4.1 创建空白镜像文件

dd if=/dev/zero of=rootfs.ext4 bs=1M count=64
mkfs.ext4 -F rootfs.ext4

参数说明:

  • bs=1M count=64:创建 64MB 的镜像文件,适合最小系统
  • -F:强制格式化,忽略非块设备警告

3.4.2 挂载并复制文件

mkdir -p /mnt/rootfs
sudo mount -o loop rootfs.ext4 /mnt/rootfs
sudo cp -a _install/* /mnt/rootfs/

# 创建必要目录
sudo mkdir -p /mnt/rootfs/{proc,sys,dev,etc/init.d}

# 创建设备节点
sudo mknod /mnt/rootfs/dev/console c 5 1
sudo mknod /mnt/rootfs/dev/null c 1 3

# 复制 init 脚本
sudo cp etc/init.d/rcS /mnt/rootfs/etc/init.d/
sudo chmod +x /mnt/rootfs/etc/init.d/rcS

sudo umount /mnt/rootfs

3.5 内核启动参数设置

内核通过 initrd 或 root= 参数指定根文件系统来源。下表总结了两种形态的 QEMU 启动参数:

根文件系统形态内核启动参数QEMU 命令行示例
initramfs rdinit=/sbin/init
(默认即可,无需 root=)
-kernel bzImage \
-initrd initramfs.cpio.gz \
-append "console=ttyS0"
rootfs.ext4 root=/dev/vda rw
rootfstype=ext4
-kernel bzImage \
-drive file=rootfs.ext4,format=raw,if=virtio \
-append "root=/dev/vda rw console=ttyS0"
常见陷阱:
  • 使用 initramfs 时,如果内核没有内嵌 initramfs,必须通过 -initrd 参数显式指定 cpio 归档。
  • 使用 ext4 镜像时,root=/dev/vda 对应 virtio 块设备;若使用 -hda 则设备名为 /dev/sda。
  • 忘记创建 /dev/console 会导致内核 panic,无法进入 Shell。

3.6 启动验证与常见问题

3.6.1 验证步骤

  1. 启动 QEMU 后观察内核日志,确认 VFS: Mounted root (ext4 filesystem) on device 254:0. 或 Unpacking initramfs... 信息。
  2. 进入 Shell 后执行 ls /bin 确认 BusyBox 命令可用。
  3. 执行 cat /proc/mounts 查看已挂载的文件系统。

3.6.2 常见异常与对策

异常现象根因解决方案
Kernel panic - not syncing: VFS: Unable to mount root fs内核找不到根文件系统检查 -initrd 路径或 root= 设备名是否正确
Failed to execute /sbin/init (error -8)init 文件格式错误或缺少执行权限确认 BusyBox 静态编译,chmod +x _install/sbin/init
sh: can't access tty; job control turned off缺少 /dev/console 或 console 参数添加 mknod dev/console c 5 1,QEMU 加 -serial stdio
init: must be run on PID 1 (error -1)内核参数 init= 指定了非 init 程序使用 rdinit=/sbin/init 或 init=/sbin/init

3.7 两种形态的对比与选型

initramfs vs rootfs.ext4 对比 initramfs(内存根文件系统) • 启动极快,完全在内存中运行 • 适合早期内核调试、驱动测试 • 修改后需重新打包 cpio • 不支持持久化存储 rootfs.ext4(磁盘根文件系统) • 可持久化保存日志、配置 • 适合块设备驱动、文件系统测试 • 修改后直接挂载更新,无需重打包 • 启动略慢,依赖磁盘驱动
选型建议:
  • 调试内核早期启动、内存管理、进程调度 → 使用 initramfs,减少变量。
  • 调试块设备驱动、文件系统、存储栈 → 使用 rootfs.ext4,模拟真实存储路径。
  • 生产环境最小系统 → 通常将 initramfs 作为过渡,最终挂载磁盘上的 rootfs。