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 版本同理)。
构建流程
关键完整代码
以下脚本完成:解压源码、配置、交叉编译、安装到 _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"
运行与验证
- 赋予执行权限并运行:
chmod +x build_rootfs.sh && ./build_rootfs.sh。 - 成功标志:脚本末尾打印两个产物路径,且
out/initramfs.cpio.gz、out/rootfs.ext4均存在且非空。 - 检查 BusyBox 架构:
file busybox-1.36.1/busybox应显示ELF 64-bit LSB ... UCB RISC-V。 - 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 即通过。 - 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 数。