本文介绍的方法,旨在利用基于 BusyBox 制作的简易文件系统来快速启动内核并进入一个 shell 环境,以此来验证内核的功能和稳定性。其优点在于制作简单,资源占用小,验证环境的启动时间短(仅需启动内核,省去了各种用户态应用及框架的启动过程);缺点是可拓展性较差,难以支撑一些需要用到用户态工具的复杂内核功能的验证。
本文主要以 ARM64 为例讲解整个过程。实际操作中,应结合实际使用的体系结构与工具链对步骤细节进行调整。介绍的验证环境有基于 initrd 和基于 SD 卡两种,可以根据实际情况选择。
BusyBox 编译
1# BusyBox 源代码下载,解压
2# https://busybox.net/downloads/
3
4cd path/to/busybox
5
6# 配置
7make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
8# 选中以下配置:
9# Build Settings --->
10# [*] Build static binary (no shared libs)
11
12# 编译
13make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j32
14
15# 安装
16make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install
17
18# 编译生成的文件在:./_install
制作根文件系统
1mkdir rootfs
2pushd rootfs
3
4cp -r /path/to/busybox/_install/* .
5mkdir -p usr lib root proc sys etc/init.d dev/pts
6cat > etc/init.d/rcS <<- EOF
7 mount -t proc none /proc
8 mount -t sysfs none /sys
9 /sbin/mdev -s
10 mount -t devpts devpts /dev/pts
11
12 # QEMU_HOST_IP=10.0.2.2
13 ip addr add 10.0.2.3/24 dev eth0
14 ip link set eth0 up
15EOF
16chmod 755 etc/init.d/rcS
17
18pushd dev
19mknod -m 666 tty1 c 4 1
20mknod -m 666 tty2 c 4 2
21mknod -m 666 tty3 c 4 3
22mknod -m 666 tty4 c 4 4
23mknod -m 666 console c 5 1
24mknod -m 666 null c 1 3
25popd # dev
26
27# linuxrc, a symlink to bin/busybox, is one of the outcome of BusyBox
28# compilation. Take it as init to let the kernel run it after kernel's
29# initialization.
30mv linuxrc init
以 initrd 为根文件系统,制作 initrd 镜像:
1find . | cpio -H newc -o --quiet | gzip -c --quiet > ../image.cpio.gz
2popd # rootfs
以 SD 卡设备为根文件系统,制作 ext3 文件系统镜像:
1popd # rootfs
2
3dd if=/dev/zero of=rootfs.sd bs=1M count=32
4mkfs.ext3 rootfs.sd
5sudo mount -t ext3 -o loop rootfs.sd /mnt
6sudo cp -r rootfs/* /mnt
7sudo umount /mnt
内核编译
initrd 是基于内存的文件系统,以 initrd 为根文件系统不需要设备驱动,因此也就不需要编译内核模块。
1make distclean
2make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
3make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j8
其他体系结构的内核编译命令,供参考:
1# arm
2make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
3make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- Image -j8
4
5# x86
6make x86_64_defconfig
7make bzImage -j32
而对于根文件系统为 SD 卡设备的场景,则稍微复杂一点。由于不同开发板关于 SD 卡设备的属性不同,在编译内核时需要选择与硬件向匹配的 config,并且编译 dtb。以 arm 的 vexpress 平台为例:
1make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig
2make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j32
3make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- modules
4make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs
启动 QEMU 虚拟机
如这篇 QEMU Wiki 所述,如果你无意模拟特定的运行环境或外围设备,仅仅只是想跑一下 Linux 内核,那你直接用这个平台就好:
1-M virt
查看该平台上可以模拟的 CPU 型号:
1qemu-system-aarch64 -M virt -cpu help
这里我们就用这个平台,并指定 CPU 为 cortex-a57
(可通过不指定来选择默认 CPU 型号)。
1qemu-system-aarch64 \
2 -M virt \
3 -cpu cortex-a57 \
4 -m 1024M \
5 -kernel arch/arm64/boot/Image \
6 -initrd ../image.cpio.gz \
7 -nographic \
8 -append "console=ttyAMA0"
其他体系结构,供参考:
1# arm
2qemu-system-arm \
3 -M virt \
4 -kernel arch/arm/boot/zImage \
5 -initrd image.cpio.gz \
6 -nographic \
7 -append "console=ttyAMA0"
8
9# x86
10qemu-system-x86_64 \
11 -m 1024M \
12 -kernel arch/x86_64/boot/bzImage \
13 -initrd ../image64.cpio.gz \
14 -nographic \
15 -append "console=ttyS0"
若是想模拟从 SD 卡启动,则需要使用一个带 SD 卡设备的平台,指定相应的 dtb 文件(-dtb
)和模拟 SD 卡内容的文件系统镜像(-sd
),并在内核启动参数中指明根文件系统所处的硬件设备(root=/dev/...
)。以 arm 的 vexpress 平台为例:
1qemu-system-arm \\
2 -M vexpress-a9 \\
3 -m 1024M \\
4 -nographic \\
5 -kernel arch/arm/boot/zImage \\
6 -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb \\
7 -sd /home/rootfs.sd \\
8 -append "root=/dev/mmcblk0 rw console=ttyAMA0"
参考资料
- linuxrc of BusyBox:
- virt machine of QEMU:
- GDB & QEMU: