BusyBox 中文文档 下载 App

从零构建自定义根文件系统 BusyBox + Linux Kernel

目标

从一份 Linux 内核 + 一个 BusyBox 二进制,构建出一个可启动的最小根文件系统(initramfs),启动后能拿到 shell。这个过程不依赖任何构建系统,全部手动完成,理解原理的最佳方式。

整体步骤

Linux 内核  →  BusyBox 二进制  →  根文件系统目录结构  →  cpio 打包  →  initramfs

1. 准备工作目录

mkdir -p rootfs/{bin,sbin,etc,dev,proc,sys,tmp,var,usr/bin,usr/sbin,root}

这个目录结构就是最终根文件系统的文件布局。

2. 交叉编译 BusyBox

如果主机和目标架构相同(都是 x86_64),直接本机编译就行:

cd busybox-1.36.1
make defconfig
# 确保静态编译开启:
# make menuconfig -> Build Options -> Build BusyBox as a static binary = Y
make -j$(nproc)
# 检查产物
ls -la busybox
# 预期:~1.1MB(musl 静态编译)

如果是交叉编译,加上 CROSS_COMPILE 前缀:

make CROSS_COMPILE=arm-linux-gnueabihf- defconfig
make CROSS_COMPILE=arm-linux-gnueabihf- -j$(nproc)
# 验证架构
file busybox
# busybox: ELF 32-bit LSB executable, ARM, version 1

3. make install 到根文件系统

# 先确保 make install 的目标目录干净
rm -rf rootfs/*

# 安装 BusyBox
make CONFIG_PREFIX=../rootfs install
# 这会把 busybox 二进制和所有 Applet 符号链接放到 rootfs/ 下

# 验证
ls -la rootfs/bin/
# 应该看到 busybox + 一堆符号链接(ls -> busybox, cat -> busybox, ...)

4. 创建设备节点

在没有 devtmpfs 的情况下手动创建(内核配置里开启了 CONFIG_DEVTMPFS 的话可以跳过):

cd rootfs
mknod -m 600 dev/console c 5 1      # 控制台
mknod -m 666 dev/null c 1 3         # null
mknod -m 666 dev/zero c 1 5         # zero
mknod -m 666 dev/random c 1 8       # random
mknod -m 666 dev/urandom c 1 9       # urandom
mknod -m 666 dev/tty c 5 0          # tty
mknod -m 666 dev/tty0 c 4 0         # tty0(vga)
mknod -m 666 dev/ttyS0 c 4 64       # 串口 0

如果内核开了 devtmpfs,启动时会自动创建大部分设备节点,手动只需要 console 和 null。

5. 准备配置文件

# /etc/inittab — 最简单的配置
cat > etc/inittab << 'EOF'
::sysinit:/etc/init.d/rcS
tty1::respawn:/sbin/getty 115200 tty1
ttyS0::respawn:/sbin/getty 115200 ttyS0
::ctrlaltdel:/sbin/reboot
EOF

# /etc/init.d/rcS — 启动脚本
mkdir -p etc/init.d
cat > etc/init.d/rcS << 'EOF'
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
hostname "my-busybox-system"
echo "BusyBox system boot complete!"
EOF
chmod +x etc/init.d/rcS

# /etc/fstab(可选)
cat > etc/fstab << 'EOF'
proc  /proc  proc  defaults  0  0
sysfs /sys   sysfs defaults  0  0
EOF

6. 打包成 initramfs

cd rootfs
# 创建 cpio 归档(newc 格式是内核支持的)
find . | cpio -o -H newc | gzip > ../initramfs.cpio.gz
cd ..

# 检查产物大小
ls -la initramfs.cpio.gz
# 预期:500KB-1.2MB(取决于 BusyBox 编译选项)

7. 准备内核

从 kernel.org 下载 Linux 内核源码,编译:

tar xjf linux-6.1.tar.xz
cd linux-6.1
# 用 defconfig 起步
make defconfig
# 确保开启 initramfs 支持:
# make menuconfig -> General setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support = Y
make -j$(nproc)
# 产物在 arch/x86/boot/bzImage

8. 打包成可启动镜像

最简单的方式是用 QEMU 测试:

qemu-system-x86_64 \
  -kernel bzImage \
  -initrd initramfs.cpio.gz \
  -append "console=ttyS0 root=/dev/ram0 init=/init" \
  -nographic

如果一切顺利,你会看到内核启动日志,然后 BusyBox init 执行 rcS,最后进入登录 shell(ttyS0)。

故障排查

内核 panic:VFS Unable to mount root fs

BusyBox init 没启动

shell 启动后没反应