news 2026/10/22 20:42:47

QEMU + ARMv8 环境搭建:从零开始构建嵌入式开发环境

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
QEMU + ARMv8 环境搭建:从零开始构建嵌入式开发环境

1. 为什么你需要一个ARMv8模拟环境?

如果你刚开始接触嵌入式开发,尤其是ARM架构,可能会觉得有点无从下手。买一块真实的开发板?价格不菲,而且每次烧录、调试都挺麻烦,万一操作失误还有“变砖”的风险。我刚开始学那会儿,就烧坏过两块板子,心疼了好久。后来我发现,其实在电脑上就能搭建一个功能完整的ARM开发环境,这就是我们今天要聊的QEMU。

简单来说,QEMU是一个开源的“虚拟机”和“模拟器”。它厉害的地方在于,能让你在x86的电脑上,模拟运行ARM、MIPS、RISC-V等各种架构的处理器。对于学习ARMv8(也就是AArch64,64位ARM)来说,这简直是神器。你不用花一分钱买硬件,就能编写、编译、运行甚至调试你的ARM汇编或C语言程序,体验从底层寄存器操作到操作系统引导的完整流程。

这个环境特别适合几类朋友:一是嵌入式开发的初学者,想低成本入门ARM架构;二是做系统软件、驱动或内核开发的工程师,需要在特定架构上测试代码;三是学生或研究者,进行计算机体系结构相关的实验。整个过程就像在电脑里“虚拟”出了一块功能强大的ARM开发板,随开随用,安全又方便。

2. 搭建前的准备工作:安装系统与基础工具

工欲善其事,必先利其器。搭建环境的第一步,是准备好你的“工作台”。我强烈推荐使用Ubuntu Linux系统,无论是物理机安装还是用虚拟机(比如VirtualBox或VMware)都可以。Ubuntu对开发者非常友好,软件包丰富,能省去很多折腾的麻烦。我这里以Ubuntu 20.04或22.04为例,其他Linux发行版命令可能略有不同。

打开你的终端,我们首先更新软件包列表,然后安装一系列编译和开发所需的工具。别被这一长串命令吓到,它们都是构建环境的基础砖瓦。

sudo apt update -y sudo apt install -y net-tools libncurses5-dev libssl-dev build-essential openssl qemu-system-arm libncurses5-dev gcc-aarch64-linux-gnu git bison flex bc vim universal-ctags cscope cmake python3-dev gdb-multiarch openjdk-13-jre trace-cmd kernelshark bpfcc-tools cppcheck docker docker.io libelf-dev gcc-7 xterm curl clang exuberant-ctags python-is-python3

运行完上面这个命令,你的系统就已经装备了强大的“武器库”。我来简单解释几个关键工具是干嘛的:

  • build-essential, gcc-7, clang:这是C/C++编译器的全家桶,用于编译本机(x86)程序。
  • gcc-aarch64-linux-gnu:这是交叉编译工具链的核心!它能在你的x86电脑上,生成运行在ARMv8(AArch64)架构上的可执行文件。没有它,你就没法为ARM编译代码。
  • qemu-system-arm:这是Ubuntu仓库里的QEMU软件包。我们先装上它,但为了获得最新特性和更好的兼容性,后面我们通常会选择自己编译更新的版本。
  • gdb-multiarch:这是一个支持多种处理器架构的调试器。有了它,你才能调试ARM程序。
  • git, cmake:代码管理和构建工具,后续下载源码和编译时会用到。
  • libncurses5-dev, libssl-dev, libelf-dev:这些是开发库,编译一些软件(比如内核、QEMU本身)时需要它们提供的头文件和链接库。

安装完基础工具后,我们还可以为后续可能编译Linux内核做一些准备,执行下面的命令可以安装内核构建依赖:

sudo apt build-dep linux-image-generic

这一步不是必须的,但做了之后,如果你未来想自己编译ARM Linux内核,会减少很多缺少依赖的报错。好了,基础平台已经搭建完毕,接下来我们要准备主角——QEMU了。

3. 获取与编译最新版QEMU

系统仓库里的QEMU版本可能比较旧。为了获得最好的体验和对ARMv8最完善的支持,我习惯从官网下载源码自己编译。自己编译听起来复杂,其实步骤很固定,而且能让你更了解这个工具。放心,我会带你一步步走。

首先,我们找一个干净的目录,比如在家目录下创建一个armv8_workspace文件夹,然后进入。

mkdir -p ~/armv8_workspace cd ~/armv8_workspace

接着,我们去QEMU官网下载源码。你可以访问 https://www.qemu.org/download/ 查看最新版本。假设我们下载一个较新的稳定版,比如7.2.0。使用wget命令下载压缩包。

wget https://download.qemu.org/qemu-7.2.0.tar.xz

下载完成后,解压源码包:

tar xvJf qemu-7.2.0.tar.xz cd qemu-7.2.0

在编译QEMU之前,还需要安装几个它依赖的特定开发包:

sudo apt-get install -y zlib1g zlib1g-dev libglib2.0-dev libpixman-1-dev
  • zlib1g-dev:提供压缩库支持。
  • libglib2.0-dev:QEMU大量使用的通用工具库,非常重要。
  • libpixman-1-dev:像素处理库,与图形显示相关。

现在,进入解压后的QEMU目录,运行配置脚本。我们这里进行一个针对ARM架构的简化配置,让它专注于模拟ARM设备,这样编译速度会快很多。

./configure --target-list=aarch64-softmmu --audio-drv-list=

解释一下参数:

  • --target-list=aarch64-softmmu:指定我们只编译针对AArch64(即ARMv8)系统模拟的目标。softmmu表示全系统模拟(可以模拟整个计算机,包括CPU、内存、外设),与之相对的是linux-user模式(仅模拟Linux程序运行)。
  • --audio-drv-list=:这里设为空,因为我们做嵌入式开发通常不需要音频支持,可以省略相关编译。

配置脚本会检查你的系统环境,并生成对应的编译规则(Makefile)。如果看到类似 “Install prefix /usr/local” 这样的输出,没有红色的错误信息,就说明配置成功了。

接下来就是编译和安装,这步比较耗时,取决于你的电脑CPU性能,可能需要十几到几十分钟。喝杯咖啡等待一下吧。

make -j$(nproc) sudo make install
  • make -j$(nproc):-j参数表示并行编译,$(nproc)会自动获取你电脑的CPU核心数,用所有核心来编译,速度最快。
  • sudo make install:将编译好的QEMU程序安装到系统目录(默认是/usr/local/bin)。

安装完成后,验证一下是否成功。打开一个新的终端,或者回到命令行,输入:

qemu-system-aarch64 --version

你应该能看到类似 “QEMU emulator version 7.2.0” 的输出。恭喜你,一个功能强大的ARMv8模拟器已经就位了!

4. 选择你的“虚拟开发板”

有了QEMU,就像有了一个“虚拟硬件生成器”,它可以模拟很多种真实的ARM开发板。这对于学习来说非常棒,因为你可以体验不同板子的特性。我们怎么知道QEMU支持哪些板子呢?很简单,用下面这个命令查看:

qemu-system-aarch64 -M help

这个命令会列出一长串支持的机器(Machine)类型,比如raspi3b(树莓派3B)、virt(QEMU自定义的通用虚拟平台)、vexpress-a9(ARM Versatile Express开发板)等等。

对于ARMv8初学者,我主要推荐两个选择:

1.raspi3b(树莓派3B模型)这是一个非常流行的选择。它模拟的是广为人知的树莓派3B,CPU是4核的Cortex-A53(ARMv8-A)。它的外设模拟相对简单,文档和社区资源丰富,特别适合入门,运行裸机程序或学习U-Boot、Linux内核移植。

2.virt(QEMU通用虚拟平台)这是QEMU团队自己设计和维护的一个“虚拟”开发板。它不模仿任何具体实物,但包含了QEMU支持的最新一代虚拟化硬件,比如GICv3中断控制器、virtio磁盘和网络设备等。它的优点是功能强大、性能好,并且是QEMU开发和测试的首要平台,兼容性最有保障。如果你想深入研究ARM虚拟化、或者想运行一个完整的Linux发行版,virt平台通常是首选。

为了后续实验,我们还需要安装调试工具,确保之前安装的gdb-multiarch可用:

sudo apt-get install -y gdb-multiarch

你可以把它理解为一个“万能”的GDB,通过配置可以调试各种架构的程序,包括我们即将要运行的ARMv8程序。

5. 运行你的第一个ARMv8程序

环境准备好了,“开发板”也选好了,是时候让我们的ARM世界动起来了。我们从最简单的开始:运行一个编译好的ARM裸机二进制文件(通常是一个.bin文件)。假设你已经用aarch64-linux-gnu-gcc交叉编译器编译好了一个名为hello.bin的简单程序。

运行它的QEMU命令非常直接:

qemu-system-aarch64 -machine raspi3b -kernel hello.bin -nographic

让我拆解一下这个命令:

  • -machine raspi3b:指定使用树莓派3B的硬件模型。
  • -kernel hello.bin:告诉QEMU,将hello.bin这个文件作为“内核”加载到内存的特定地址(通常是ARM处理器的复位向量地址)并开始执行。
  • -nographic:这个参数很重要,它表示不使用图形化窗口,所有输出都重定向到当前终端。对于嵌入式裸机程序,它们通常通过串口(UART)输出信息,-nographic模式会将QEMU模拟的串口连接到你的终端上。程序运行的任何printf(如果链接了标准库)或对串口的直接操作,都会打印在你的终端里。

运行后,你可能会看到一些输出,或者程序直接执行完毕退出。如果没有-nographic,QEMU会弹出一个独立的图形窗口,但对于没有图形界面的裸机程序,那个窗口通常是黑的,所以我们用-nographic更方便。

如果你想使用功能更强大的virt平台,命令会稍微复杂一点,因为它可以配置更多参数:

qemu-system-aarch64 -cpu cortex-a57 -smp 1 -m 512M -machine virt,gic-version=3 -nographic -kernel hello.bin

这里多了几个参数:

  • -cpu cortex-a57:指定模拟的CPU型号为Cortex-A57。
  • -smp 1:模拟1个CPU核心(Symmetric Multi-Processing)。
  • -m 512M:为虚拟机分配512MB的内存。
  • gic-version=3:指定使用GICv3中断控制器,这是ARMv8的现代中断控制器。

通过这种方式,你就可以快速验证编译出的ARM程序是否能正确运行。这是学习底层开发的第一步,也是调试的基础。

6. 使用GDB进行源码级调试

只会运行程序还不够,调试才是开发中的常态。QEMU与GDB的配合堪称完美,可以实现源码级别的单步调试,这对于理解程序执行流程、查找bug至关重要。下面我以调试一个名为benos.elf的ELF格式文件(包含调试信息)为例,展示完整的流程。

第一步:启动QEMU并等待调试器连接我们需要让QEMU在启动后暂停,并打开一个调试端口。这需要用到-S和-s参数。

qemu-system-aarch64 -machine raspi3b -kernel benos.elf -S -s -nographic
  • -S:表示在启动时冻结CPU,不让程序立刻执行,直到调试器(GDB)发出继续运行的命令。
  • -s:是-gdb tcp::1234的简写,表示在TCP的1234端口监听GDB的连接。

执行这个命令后,终端看起来会卡住,因为虚拟机已经创建但CPU被冻结了。这就对了,它在等待调试器。

第二步:启动GDB并连接打开另一个终端窗口,进入你的项目目录。首先启动gdb-multiarch,并加载带调试信息的ELF文件。

gdb-multiarch benos.elf

GDB启动后,你会看到(gdb)提示符。接下来,让它连接到正在等待的QEMU虚拟机:

(gdb) target remote localhost:1234

如果连接成功,你会看到类似 “Remote debugging using localhost:1234” 的提示。现在,GDB和QEMU已经建立了桥梁。

第三步:设置断点并开始调试连接后,我们可以设置断点。比如,我们想在程序的入口函数_start处停下:

(gdb) b _start (gdb) c

b _start是在_start符号处设置断点。c是continue的缩写,让被冻结的CPU开始执行,直到遇到断点。执行c后,程序会运行并在_start处停下。

这时,你就可以使用各种GDB命令进行调试了:

  • layout src:切换到显示源代码和汇编的图形化布局(TUI模式),非常直观。
  • si/ni:单步执行一条汇编指令(si会步入函数调用,ni会越过)。
  • s/n:单步执行一行C源代码(需要编译时加-g参数)。
  • info registers或i r:查看所有寄存器的当前值。
  • p /x $x0:以十六进制打印通用寄存器x0的值。
  • x /10i $pc:查看当前程序计数器($pc)位置开始的10条汇编指令。

调试完成后,在GDB中输入q退出,GDB会询问是否退出,确认即可。QEMU那边也会随之关闭。

这个过程一开始可能觉得有点繁琐,但熟练之后,你会发现它是探索ARM体系结构和调试复杂问题的利器。你可以观察每一条指令对寄存器的影响,深入理解中断、内存映射等核心机制。

7. 构建更复杂的开发环境:内核与文件系统

前面的例子是运行一个简单的裸机程序。但在真实的嵌入式开发中,我们更多是跟操作系统打交道,比如运行一个完整的Linux系统。这就需要我们准备两样东西:内核镜像和根文件系统。

准备Linux内核:我们可以为ARMv8编译一个Linux内核。首先获取内核源码(以稳定版5.10为例):

cd ~/armv8_workspace git clone --depth=1 -b v5.10 https://github.com/torvalds/linux.git linux-5.10 cd linux-5.10

配置内核。对于virt平台,有一个默认配置:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig

如果你需要特定的驱动或功能,可以使用菜单界面进行配置:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

然后开始编译内核镜像:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image

编译完成后,内核镜像文件位于arch/arm64/boot/Image。

制作根文件系统:根文件系统包含了Linux启动后所需的库、工具和配置文件。一个简单的方法是使用BusyBox。这里步骤较多,简述流程:

  1. 下载并编译BusyBox,配置为静态链接。
  2. 创建一个目录(如rootfs),按照Linux目录结构放置BusyBox生成的文件、必要的设备节点(如/dev/console)和初始化脚本(如/init)。
  3. 使用genext2fs或dd和mkfs.ext4命令将这个目录制作成一个ext4格式的磁盘镜像文件,例如rootfs.ext4。

使用QEMU启动完整Linux系统:有了内核和文件系统镜像,我们就可以启动一个完整的ARM Linux了。对于virt平台,一个典型的启动命令如下:

qemu-system-aarch64 -cpu cortex-a57 -smp 2 -m 1G -machine virt,gic-version=3 -nographic \ -kernel ~/armv8_workspace/linux-5.10/arch/arm64/boot/Image \ -drive file=rootfs.ext4,format=raw,if=virtio \ -append "root=/dev/vda rw console=ttyAMA0"

这个命令做了几件事:

  • 指定了CPU、内存和机器类型。
  • 通过-kernel加载编译好的Linux内核。
  • 通过-drive添加一个虚拟硬盘,里面是我们的根文件系统镜像,使用高效的virtio接口。
  • 通过-append传递内核启动参数,告诉内核根设备是第一个virtio磁盘(/dev/vda),并以读写方式挂载,控制台是ttyAMA0(即串口)。

执行后,你会看到内核启动日志在终端滚动,最后出现登录提示符(如果BusyBox配置了登录)。一个完整的ARM64 Linux系统就在你的电脑里运行起来了!

8. 常见问题与排错指南

在搭建和使用的过程中,你难免会遇到一些问题。这里我总结几个我踩过的“坑”和解决办法,希望能帮你快速排雷。

1. 编译QEMU时出现 “ERROR: glib-2.48 gthread-2.0 is required to compile QEMU” 之类的错误。这通常是因为依赖库没装全或者版本不对。请确保你已经正确安装了libglib2.0-dev。如果还是不行,可以尝试安装更高版本的glib开发包,或者查看QEMU源码目录下的README文件,获取最准确的依赖要求。

2. 运行qemu-system-aarch64提示命令未找到。如果你是自己编译安装的,默认安装路径是/usr/local/bin,请确认该目录在你的PATH环境变量中。也可以使用绝对路径/usr/local/bin/qemu-system-aarch64来运行。如果是用apt安装的,包名提供的命令通常是qemu-system-aarch64。

3. GDB连接QEMU失败,提示 “Connection refused”。首先确认QEMU启动时是否加上了-S -s参数。其次,检查GDB连接命令中的端口号是否一致(默认是1234)。最后,确保两个终端都在同一台机器上,没有防火墙规则阻止本地回环地址(localhost)的连接。

4. 程序在QEMU中运行无输出,或者立即退出。对于裸机程序,首先要确认你的程序是否正确初始化了串口,并且输出到了正确的UART设备地址上。不同的开发板模型,其串口内存映射地址是不同的。例如,树莓派3B的Mini UART地址是0x3F215040(PL011 UART是0x3F201000),而virt平台的PL011地址通常是0x09000000。你需要查阅对应板子的技术手册或QEMU源码来确定。其次,检查交叉编译工具链是否正确,程序是否链接到了正确的启动地址。

5. 使用-nographic启动后,想退出QEMU怎么办?在-nographic模式下,QEMU会捕获你的键盘输入。要退出,先按下Ctrl+A,松开后再按X键(即Ctrl-A X)。也可以先按Ctrl+A再按C进入QEMU监视器,然后输入quit命令退出。

6. 如何让QEMU虚拟机访问主机网络?最简单的网络配置是使用“用户模式网络”(User Networking),它允许虚拟机访问外部网络,但外部无法直接访问虚拟机。在启动命令中添加-netdev user,id=mynet -device virtio-net-device,netdev=mynet即可。这样虚拟机内部就可以使用dhcp获取IP,并ping通外网了。

遇到问题别慌张,多查看终端输出的错误信息,善用搜索引擎(记得用英文关键词,如 “qemu raspi3b uart not working”),大部分常见问题都有解决方案。嵌入式开发本身就是一个不断解决问题的过程,每解决一个坑,你的功力就增长一分。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 0:20:27

当代码不再昂贵:IT人春节群像

腊月二十八,春节假期第一天晚上,我的微信消息列表突然“炸”了。不是拜年祝福,而是一连串来自IT同行的深夜留言:“哥,今年过年特别焦虑,看00后用AI十分钟搭个应用,我十年经验好像一夜归零。”“…

作者头像 李华
网站建设 2026/10/13 1:08:05

SDPose-Wholebody在SpringBoot医疗应用中的集成指南

SDPose-Wholebody在SpringBoot医疗应用中的集成指南 1. 引言 在医疗康复领域,准确的动作识别和姿态分析对于患者康复训练至关重要。传统的康复训练往往需要专业治疗师一对一指导,成本高且难以规模化。而基于计算机视觉的姿态估计技术,特别是…

作者头像 李华
网站建设 2026/10/13 0:21:02

保姆级教程:从零部署实时手机检测模型(基于Modelscope)

保姆级教程:从零部署实时手机检测模型(基于Modelscope) 1. 引言:为什么选择实时手机检测模型 在日常工作和生活中,手机检测是一个非常有用的技术。想象一下这些场景:会议室里需要检测参会人员是否违规使用…

作者头像 李华
网站建设 2026/10/5 22:40:40

新手友好:ERNIE-4.5-0.3B-PT模型部署与使用全攻略

新手友好:ERNIE-4.5-0.3B-PT模型部署与使用全攻略 1. 快速了解ERNIE-4.5-0.3B-PT模型 ERNIE-4.5-0.3B-PT是一个轻量级的文本生成模型,基于百度最新的ERNIE 4.5架构开发。这个模型虽然参数量相对较小(0.3B),但继承了E…

作者头像 李华
网站建设 2026/10/13 0:56:52

从零开始:造相Z-Image镜像部署与使用全攻略,小白也能轻松上手

从零开始:造相Z-Image镜像部署与使用全攻略,小白也能轻松上手 你是不是也想体验AI绘画的魅力,却被复杂的安装配置劝退?显卡驱动、CUDA版本、Python环境、依赖冲突……这些技术门槛让很多想尝试AI绘画的新手望而却步。 别担心&am…

作者头像 李华
网站建设 2026/10/13 0:21:25

FLUX.1文生图实战:如何用ComfyUI打造专属AI画师

FLUX.1文生图实战:如何用ComfyUI打造专属AI画师 1. 快速了解FLUX.1:你的新一代AI绘画助手 FLUX.1是近期开源社区最受关注的文生图模型之一,由前Stability AI核心团队打造。这个模型在图像细节、提示词理解、风格多样性方面都表现出色&#…

作者头像 李华