4. BusyBox 根文件系统构建与打包

任务说明

本案例交叉编译 BusyBox,搭建最小根文件系统目录树,并打包为 initramfs(cpio.gz)或 ext4 镜像。目标平台以 RISC-V 64 位为例,工具链前缀 riscv64-linux-gnu-,内核启动时可通过 init=/bin/sh 或 BusyBox 的 init 进入 shell。

环境与依赖

  • 交叉工具链:riscv64-linux-gnu-gcc(或 riscv64-unknown-linux-gnu-,按实际前缀替换)。
  • 构建工具:make、gcc、cpio、gzip;ext4 镜像需 genext2fs 或 mkfs.ext4 + loop 挂载。
  • BusyBox 源码:busybox-1.36.1.tar.bz2(其他 1.3x 版本同理)。

构建流程

BusyBox 源码 make defconfig CROSS_COMPILE 静态编译 make install _install/ 拷贝到 rootfs 建目录/设备节点 initramfs find|cpio|gzip ext4 镜像 genext2fs/mkfs

关键完整代码

以下脚本完成:解压源码、配置、交叉编译、安装到 _install、组装 rootfs 目录树、生成 initramfs 与 ext4 镜像。保存为 build_rootfs.sh,与 BusyBox 源码包放在同一目录执行。

#!/bin/bash
set -e
CROSS=riscv64-linux-gnu-
ARCH=riscv
BB=busybox-1.36.1
ROOTFS=$PWD/rootfs
OUT=$PWD/out
mkdir -p "$OUT"

# 1. 解压并配置 BusyBox
[ -d "$BB" ] || tar xf ${BB}.tar.bz2
cd "$BB"
make ARCH=$ARCH CROSS_COMPILE=$CROSS defconfig
# 静态编译,避免依赖目标机动态库
sed -i 's/^# CONFIG_STATIC.*/CONFIG_STATIC=y/' .config
make ARCH=$ARCH CROSS_COMPILE=$CROSS olddefconfig
make ARCH=$ARCH CROSS_COMPILE=$CROSS -j$(nproc)
make ARCH=$ARCH CROSS_COMPILE=$CROSS install
cd ..

# 2. 组装最小根文件系统目录
rm -rf "$ROOTFS"
mkdir -p "$ROOTFS"/{bin,sbin,etc,proc,sys,dev,tmp,root,usr/bin,usr/sbin}
cp -a "$BB"/_install/* "$ROOTFS"/
# 设备节点(initramfs 中 devtmpfs 会自动挂载,这里保留 console/null 兜底)
mknod -m 622 "$ROOTFS"/dev/console c 5 1 2>/dev/null || true
mknod -m 666 "$ROOTFS"/dev/null    c 1 3 2>/dev/null || true

# 3. init 脚本:挂载伪文件系统并启动 shell
cat > "$ROOTFS"/init <<'EOF'
#!/bin/sh
mount -t proc  none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev 2>/dev/null
exec /bin/sh
EOF
chmod +x "$ROOTFS"/init

# 4. 打包 initramfs (cpio.gz)
cd "$ROOTFS"
find . | cpio -o -H newc | gzip -9 > "$OUT"/initramfs.cpio.gz
cd ..

# 5. 打包 ext4 镜像 (16MB)
dd if=/dev/zero of="$OUT"/rootfs.ext4 bs=1M count=16 status=none
mkfs.ext4 -q -d "$ROOTFS" "$OUT"/rootfs.ext4

echo "生成: $OUT/initramfs.cpio.gz  $OUT/rootfs.ext4"

运行与验证

  1. 赋予执行权限并运行:chmod +x build_rootfs.sh && ./build_rootfs.sh。
  2. 成功标志:脚本末尾打印两个产物路径,且 out/initramfs.cpio.gz、out/rootfs.ext4 均存在且非空。
  3. 检查 BusyBox 架构:file busybox-1.36.1/busybox 应显示 ELF 64-bit LSB ... UCB RISC-V。
  4. QEMU 快速验证 initramfs:
    qemu-system-riscv64 -M virt -kernel Image -initrd out/initramfs.cpio.gz -append "console=ttyS0 init=/init" -nographic
    进入 shell 后执行 ls /bin、mount,能看到 BusyBox 命令与已挂载的 proc/sys/dev 即通过。
  5. ext4 镜像验证:qemu-system-riscv64 -M virt -kernel Image -drive file=out/rootfs.ext4,format=raw,if=virtio -append "root=/dev/vda rw console=ttyS0 init=/init" -nographic,能进入 shell 即通过。

常见问题

  • 工具链前缀不同:修改脚本首行 CROSS 变量即可。
  • 动态链接报错:确认 CONFIG_STATIC=y 生效,或把工具链 sysroot 的 lib/ 一并拷入 rootfs。
  • ext4 容量不足:增大 count=16 的 MB 数。