1. 项目概述
最近在研究Linux内核开发,发现搭建一个完整的ARM64仿真环境对于内核学习和调试非常有帮助。本文将详细介绍如何在Ubuntu/Debian系统上使用QEMU搭建ARM64架构的Linux内核开发环境,包括交叉编译工具链安装、内核编译、BusyBox根文件系统构建以及QEMU启动配置的全过程。
这个环境特别适合以下几类开发者:
- 想学习Linux内核工作原理但手头没有ARM开发板的开发者
- 需要测试内核模块在不同架构上行为的工程师
- 准备进行嵌入式系统开发的初学者
2. 环境准备
2.1 QEMU安装
QEMU是我们整个实验环境的基础,它能够模拟ARM64架构的处理器和外围设备。在Ubuntu/Debian系统上安装非常简单:
bash复制sudo apt update
sudo apt install qemu-system-arm
安装完成后,可以通过以下命令验证版本:
bash复制qemu-system-arm --version
注意:虽然我们安装的是qemu-system-arm包,但它实际上包含了aarch64(ARM64)的模拟支持。这是因为在Debian/Ubuntu的包管理中,ARM64模拟器被包含在这个包中。
2.2 交叉编译器安装
由于我们的宿主机通常是x86架构,而目标系统是ARM64,所以需要安装交叉编译工具链:
bash复制sudo apt install gcc-aarch64-linux-gnu
验证安装是否成功:
bash复制aarch64-linux-gnu-gcc -v
这个交叉编译器会安装在/usr/bin目录下,前缀为aarch64-linux-gnu-,包括gcc、g++、objdump等全套工具。
经验分享:在实际项目中,有时需要特定版本的交叉编译器。如果遇到兼容性问题,可以考虑从ARM官方或Linaro网站下载预编译的工具链,而不是使用系统仓库中的版本。
3. Linux内核编译
3.1 内核下载
首先选择一个合适的内核版本,本文以6.6版本为例:
bash复制wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz
tar xvf linux-6.6.tar.xz
cd linux-6.6
3.2 内核配置
为了保持源码目录的干净,我们使用O=参数指定输出目录:
bash复制mkdir -p ../build/linux/out
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=../build/linux/out defconfig
这个命令会生成默认的ARM64配置。如果需要自定义配置:
bash复制make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=../build/linux/out menuconfig
在menuconfig界面中,可以按需修改配置。完成后保存:
bash复制make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=../build/linux/out savedefconfig
cp ../build/linux/out/defconfig arch/arm64/configs/my_defconfig
技巧:保存自定义配置到arch/arm64/configs目录下,方便后续使用。这样下次可以直接通过make my_defconfig来应用你的配置。
3.3 内核编译
执行编译命令:
bash复制make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=../build/linux/out Image
编译完成后,内核镜像位于build/linux/out/arch/arm64/boot/Image。
如果需要设备树支持(虽然virt机器可以不用):
bash复制make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- O=../build/linux/out dtbs
常见问题:如果编译过程中出现缺少依赖的错误,可以尝试安装以下包:
sudo apt install flex bison libssl-dev
4. BusyBox编译
4.1 BusyBox下载
BusyBox是一个集成了许多常用Unix工具的软件,非常适合作为最小系统的根文件系统:
bash复制wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xvf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
4.2 BusyBox配置与编译
创建输出目录并配置:
bash复制mkdir -p ../build/busybox
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KBUILD_OUTPUT=../build/busybox defconfig
启用静态链接(避免依赖动态库):
bash复制sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' ../build/busybox/.config
开始编译:
bash复制make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KBUILD_OUTPUT=../build/busybox
重要提示:静态链接虽然会增加二进制文件大小,但可以避免处理动态库依赖问题,特别适合这种最小系统环境。
5. 构建根文件系统
5.1 准备根文件系统目录
bash复制mkdir -p ../build/rootfs
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- KBUILD_OUTPUT=../build/busybox CONFIG_PREFIX="../build/rootfs" install
5.2 创建必要目录和文件
bash复制cd ../build/rootfs
mkdir -p proc sys dev etc/init.d
创建init脚本(直接使用busybox):
bash复制cp bin/busybox init
创建启动脚本etc/init.d/rcS:
bash复制cat > etc/init.d/rcS <<EOF
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
echo "Welcome to ARM64 QEMU System!"
exec /sbin/getty -L -n -l /bin/sh ttyAMA0 115200 vt100
EOF
chmod +x etc/init.d/rcS
5.3 打包initramfs
bash复制find . | cpio -o --format=newc | gzip -9 > ../initramfs.cpio.gz
技巧:initramfs是一种内存中的根文件系统,内核启动时会自动解压并挂载它。使用cpio+gzip格式是Linux内核支持的标准格式。
6. 启动QEMU
6.1 基本启动命令
使用virt机器模型启动QEMU:
bash复制qemu-system-aarch64 \
-machine virt \
-cpu cortex-a72 \
-smp 2 \
-m 512 \
-kernel ../build/linux/out/arch/arm64/boot/Image \
-initrd ../initramfs.cpio.gz \
-append "console=ttyAMA0,115200 earlyprintk=serial loglevel=8" \
-nographic \
-serial mon:stdio
参数说明:
- -machine virt:使用QEMU的通用ARM64虚拟机平台
- -cpu cortex-a72:模拟Cortex-A72 CPU
- -smp 2:模拟2个CPU核心
- -m 512:分配512MB内存
- -nographic:禁用图形界面,使用串口控制台
- -serial mon:stdio:将串口重定向到标准输入输出
6.2 设备树处理
虽然virt机器可以自动生成设备树,但有时我们需要查看或修改它:
bash复制qemu-system-aarch64 \
-machine virt,dumpdtb=qemu_default.dtb \
-cpu cortex-a72 \
-smp 2 \
-m 512
可以使用dtc工具反编译dtb文件:
bash复制dtc -I dtb -O dts -o qemu_default.dts qemu_default.dtb
7. 常见问题与调试技巧
7.1 内核启动失败
如果内核启动失败,可以尝试以下方法调试:
- 在内核命令行添加"earlycon earlyprintk"参数
- 增加loglevel=8获取更多日志
- 检查内核配置是否包含了必要的驱动(如VIRTIO相关驱动)
7.2 根文件系统问题
如果系统启动后无法进入shell:
- 检查initramfs是否包含必要的工具(特别是/bin/sh)
- 确保rcS脚本有可执行权限
- 检查控制台设备是否正确(ttyAMA0是virt机器的默认串口)
7.3 性能优化
为了提高QEMU性能:
- 可以使用-kvm加速(如果宿主机CPU支持)
- 增加-smp参数使用更多CPU核心
- 使用virtio设备代替模拟设备
8. 进阶使用
8.1 添加自定义程序
要在系统中运行自己的测试程序:
- 使用交叉编译器编译程序:aarch64-linux-gnu-gcc -static -o mytest mytest.c
- 将程序复制到rootfs目录中
- 重新打包initramfs
8.2 内核调试
使用QEMU和GDB调试内核:
- 启动QEMU时添加-s -S参数
- 在另一个终端中运行aarch64-linux-gnu-gdb vmlinux
- 在gdb中连接target remote :1234
8.3 网络支持
为虚拟机添加网络支持:
- 在内核配置中启用网络驱动
- 在QEMU命令行中添加网络设备参数
- 在根文件系统中添加网络配置脚本
我在实际搭建这个环境时,最大的收获是理解了Linux系统从内核到用户空间的完整启动过程。特别是initramfs的作用和创建方法,这在嵌入式开发中非常实用。另外,QEMU的virt机器模型虽然简单,但已经包含了足够多的功能来进行内核开发和测试。
