AGENT驱动QEMU搭建RISC-V AI芯片PCIe实验台
发布时间:2026/10/31 10:39:06 锦皓数字建站

1. 为什么我要用 AGENT 来搭一套 RISC-V 实验台第一次接触 RISC-V 芯片验证的时候我踩过一个很典型的坑手头只有一份 RTL 代码和一块还没流片的 FPGA 原型板想跑一个完整的启动流程结果光是环境搭建就耗掉了整整一周。交叉编译工具链版本对不上、QEMU 的机器模型和实际芯片外设对不齐、PCIe 枚举过程根本没法在纯软件里复现——这些问题堆在一起足以让一个本来只想验证指令集的人直接放弃。后来我换了个思路既然现在 AGENT 这类自动化编排工具已经足够成熟为什么不把环境搭建这件事本身交给 AGENT 来做让它去读芯片手册、生成 QEMU 启动脚本、自动拉取工具链、甚至根据 PCIe 拓扑自动生成设备树片段。这就是这篇博文要聊的核心——用 AGENT 驱动 QEMU拉起一块 RISC-V AI 芯片的实验台。这套东西适合谁如果你正在做 RISC-V CPU 设计验证、AI 加速器固件开发、或者单纯想在没有硬件的情况下先把 Linux 跑起来看看 PCIe 枚举日志那这套流程你直接抄就行。它不要求你手上有流片回来的芯片一台普通的 x86 开发机加 Docker 就能起步。核心关键词就几个AGENT、QEMU、RISC-V、AI 芯片、PCIe后面我会围绕这几个点把每个环节拆开讲。我个人的判断是未来芯片验证的门槛会越来越低不是因为硬件便宜了而是因为 AGENT 把环境搭建这种重复劳动吃掉了。你只需要描述清楚目标——我要一块能枚举 PCIe 设备的 RISC-V 虚机——剩下的脚本生成、参数调优、日志分析AGENT 都能接手。这篇就是把这个思路落地成可复现的步骤。2. 整体方案设计与选型思路拆解2.1 为什么是 QEMU 而不是其他模拟器做 RISC-V 实验台模拟器选择其实就那么几个QEMU、Spike、还有各种商业仿真器。Spike 是官方参考实现指令集覆盖最准但它只做指令级模拟没有外设模型你想跑 PCIe 枚举没门。商业仿真器功能全但授权费用和上手成本对个人开发者不友好。QEMU 的优势在于它是系统级模拟有完整的机器模型machine model能模拟 CPU、内存、中断控制器、PCIe 主机桥、甚至网卡和存储控制器。对于拉起一块 AI 芯片实验台这个目标QEMU 的virt机器类型已经内置了 RISC-V 的 PCIe 支持你只需要在命令行里加几个参数就能让虚机里出现一个 PCIe 根复合体Root Complex。提示QEMU 的 RISC-Vvirt机器默认使用virtio设备但 PCIe 支持需要显式开启-device pcie-root-port之类的参数很多人第一次搭环境就是漏了这步导致虚机里lspci什么都看不到。2.2 AGENT 在这里扮演什么角色很多人对 AGENT 的理解还停留在聊天机器人层面其实在工程场景里AGENT 的核心价值是任务编排 工具调用。具体到我们这个场景AGENT 要做四件事第一环境探测。它会先检查你本机的架构、Docker 版本、已有的工具链避免重复安装。第二脚本生成。根据你描述的芯片规格比如双核 RV64GC带 PCIe Gen3 x4生成对应的 QEMU 启动命令和 OpenSBI 固件参数。第三依赖拉取。自动去拉 RISC-V 的 GNU 工具链、Linux 内核源码、BusyBox 根文件系统。第四日志分析。启动失败时它会读 QEMU 的串口输出定位是设备树问题还是固件问题。这里要区分一个概念harness 和 agent 的区别。Harness 更像是一个固定的测试框架输入输出都是预设好的而 AGENT 是动态的它会根据中间结果调整下一步动作。比如第一次启动内核 panic 了AGENT 会去读 panic 信息判断是缺少earlycon参数还是设备树里 PCIe 节点写错了然后自动改脚本重试。这种感知-决策-执行的循环才是 AGENT 真正省时间的地方。2.3 整体架构分层我把这套实验台分成四层从下往上依次是层级组件作用宿主层x86 开发机 Docker提供隔离的运行环境模拟层QEMU OpenSBI模拟 RISC-V CPU 和外设系统层Linux 内核 根文件系统提供操作系统和驱动编排层AGENT生成脚本、拉依赖、分析日志这个分层的好处是每一层都可以单独替换。比如你想换成真实的 FPGA 原型板只需要把模拟层换掉上面的系统层和编排层基本不用动。这也是我推荐用 AGENT 而不是写死脚本的原因——脚本是死的AGENT 是活的换硬件的时候改的是描述而不是代码。3. 核心细节解析与实操要点3.1 RISC-V 工具链的选择与安装工具链是整个实验台的地基。RISC-V 的 GNU 工具链有好几个来源官方riscv-gnu-toolchain、Bootlin 的预编译版本、还有各芯片厂商自己维护的版本。我的建议是优先用预编译版本除非你要改编译器本身。官方源码编译一次大概要 40 分钟到 1 小时而且依赖一堆库gmp、mpfr、mpc、isl新手很容易在configure阶段就卡住。Bootlin 提供的riscv64-linux-gnu预编译包解压即用省下来的时间够你多跑十次 QEMU 了。安装步骤大致是这样# 下载预编译工具链以 Bootlin 为例 wget https://toolchains.bootlin.com/downloads/releases/toolchains/riscv64-linux/tarballs/riscv64--glibc--stable.tar.bz2 tar -xjf riscv64--glibc--stable.tar.bz2 -C /opt/ export PATH/opt/riscv64--glibc--stable/bin:$PATH # 验证 riscv64-linux-gnu-gcc --version注意工具链的 ABI 要和内核编译时的 ABI 一致。如果你用lp64d双精度浮点编译内核工具链也必须是lp64d否则链接阶段会报 ABI 不匹配。这个坑我在第一次编译时踩过报错信息很隐晦只说relocation truncated实际是 ABI 问题。3.2 QEMU 的编译与 PCIe 支持确认系统自带的 QEMU 版本往往偏旧RISC-V 的 PCIe 支持在 6.0 之后才比较完善。我建议从源码编译或者至少确认版本在 7.0 以上。# 检查当前 QEMU 版本和 RISC-V 支持 qemu-system-riscv64 --version qemu-system-riscv64 -machine help | grep virt # 源码编译如果需要 ./configure --target-listriscv64-softmmu --enable-debug make -j$(nproc)编译时--target-list只选riscv64-softmmu就够了全量编译会浪费大量时间。--enable-debug建议加上后面调试 PCIe 枚举问题时QEMU 的 trace 日志能帮你省很多事。确认 PCIe 支持是否开启可以看 QEMU 启动时有没有pcie相关的设备可选qemu-system-riscv64 -device help | grep pcie如果能看到pcie-root-port、pcie-pci-bridge这些说明 PCIe 支持是完整的。3.3 OpenSBI 固件的参数配置OpenSBI 是 RISC-V 的固件层相当于 x86 的 BIOS。QEMU 自带的 OpenSBI 通常够用但如果你要模拟特定的 AI 芯片可能需要自己编译 OpenSBI 并传入自定义的设备树。关键参数是-bios和-kernel的配合。QEMU 的virt机器默认会加载内置的 OpenSBI然后跳转到-kernel指定的内核。如果你想用自定义 OpenSBIqemu-system-riscv64 \ -M virt,pflash0pflash0 \ -bios /path/to/fw_jump.bin \ -kernel /path/to/Image \ ...fw_jump.bin是 OpenSBI 的跳转固件它会初始化 M 模式环境然后跳到 S 模式的 Linux 内核。这里有个细节OpenSBI 的设备树和内核的设备树必须是同一份否则 PCIe 节点的地址映射会对不上。我一般把设备树单独编译成.dtb通过-dtb参数传给 QEMU这样两边用的就是同一份。3.4 PCIe 拓扑的设备树描述这是整个实验台最核心也最容易出错的部分。QEMU 的virt机器默认生成的设备树里PCIe 节点是这样的pci30000000 { compatible pci-host-ecam-generic; device_type pci; reg 0x0 0x30000000 0x0 0x10000000; bus-range 0x00 0xff; ranges ...; interrupt-map ...; };compatible pci-host-ecam-generic是关键它告诉 Linux 用通用的 ECAMEnhanced Configuration Access Mechanism驱动来访问 PCIe 配置空间。ECAM 的地址范围0x30000000到0x40000000就是配置空间的映射区。如果你想模拟多级 PCIe 拓扑比如加一个 PCIe Switch需要在 QEMU 命令行里显式添加-device pcie-root-port,idrp1,chassis1,slot1 \ -device pcie-pci-bridge,idbr1,busrp1 \ -device e1000e,busbr1这样虚机里lspci就能看到一棵树状的拓扑而不是扁平的设备列表。对于验证 PCIe 枚举过程来说这种拓扑更有参考价值。提示PCIe 枚举的顺序是从根复合体开始逐级扫描总线号。QEMU 的pcie-root-port默认会分配总线号但如果你手动指定了bus-range要确保不冲突。我遇到过因为bus-range写重叠导致枚举卡死的情况日志里只显示pci 0000:00:00.0: BAR 0: no space排查了很久才发现是总线号冲突。4. 实操过程与核心环节实现4.1 用 AGENT 生成启动脚本假设你已经有一个 AGENT 环境可以是本地的也可以是接入 API 的第一步是给它一个清晰的描述。我一般这样写提示词目标生成一个 QEMU 启动脚本模拟一块双核 RV64GC 的 RISC-V AI 芯片。 要求 1. 使用 virt 机器类型开启 PCIe 支持 2. 内存 4GB双核 3. 添加一个 PCIe 网卡和一个 PCIe 存储控制器 4. 内核使用 Image 格式根文件系统用 initramfs 5. 输出完整的 qemu-system-riscv64 命令行AGENT 返回的脚本大概长这样#!/bin/bash qemu-system-riscv64 \ -M virt,aiaaplic-imsic \ -cpu rv64 \ -smp 2 \ -m 4G \ -kernel ./Image \ -initrd ./rootfs.cpio.gz \ -append consolettyS0 earlyconsbi root/dev/ram rdinit/init \ -device pcie-root-port,idrp0,chassis0,slot0 \ -device e1000e,busrp0 \ -device pcie-root-port,idrp1,chassis1,slot1 \ -device virtio-blk-pci,busrp1,drivedisk0 \ -drive iddisk0,file./disk.img,formatraw,ifnone \ -nographic这里有几个参数值得展开说。aiaaplic-imsic是 RISC-V 的高级中断架构AI 芯片通常需要这个来支持 MSI-X 中断PCIe 设备的中断就是走这条路径。earlyconsbi让内核在正式串口驱动加载前就能输出日志调试启动问题时非常关键。4.2 内核编译的关键配置内核配置直接决定 PCIe 能不能正常工作。以下选项必须打开CONFIG_PCIy CONFIG_PCI_HOST_GENERICy CONFIG_PCI_MSIy CONFIG_PCIEPORTBUSy CONFIG_PCIE_ECAMy CONFIG_VIRTIO_PCIy CONFIG_E1000EyCONFIG_PCI_HOST_GENERIC对应设备树里的pci-host-ecam-generic没有它内核根本不会去扫描 PCIe 总线。CONFIG_PCIEPORTBUS是 PCIe 端口总线驱动负责枚举和资源分配。编译命令make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- defconfig # 然后手动打开上面的选项或者用 scripts/config make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- -j$(nproc) Image注意RISC-V 的内核镜像格式是Image未压缩或Image.gz压缩。QEMU 的-kernel参数对两者都支持但如果你用Image.gz要确保 QEMU 版本支持自动解压。我一般直接用Image省得排查解压问题。4.3 根文件系统的制作根文件系统用 BusyBox 做一个最小的 initramfs 就够了。步骤# 编译 BusyBox静态链接 make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- defconfig make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- menuconfig # 打开 CONFIG_STATICy make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- -j$(nproc) make ARCHriscv CROSS_COMPILEriscv64-linux-gnu- install # 制作 initramfs cd _install mkdir -p proc sys dev etc cat init EOF #!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo RISC-V AI Chip Lab Ready lspci -vv exec /bin/sh EOF chmod x init find . | cpio -o -H newc | gzip ../rootfs.cpio.gzlspci -vv这行是故意加的启动后直接打印 PCIe 设备列表和配置空间方便你确认枚举是否成功。BusyBox 默认不带lspci需要额外编译pciutils或者用cat /proc/bus/pci/devices代替。4.4 启动与验证把上面几步的产物放在同一个目录执行 AGENT 生成的脚本chmod x run_qemu.sh ./run_qemu.sh正常的话串口会输出 OpenSBI 的启动信息然后是内核解压、初始化最后进入 shell。在 shell 里执行cat /proc/bus/pci/devices你应该能看到类似这样的输出0000 00:00.0 1b36:0008 ... 0001 01:00.0 8086:10d3 ... 0002 02:00.0 1af4:1001 ...每一行对应一个 PCIe 设备第一列是总线号第二列是设备号第三列是厂商 ID 和设备 ID。1b36是 Red HatQEMU 的厂商 ID8086是 Intele1000e 网卡1af4是 virtio。看到这些说明 PCIe 枚举链路是通的。4.5 用 AGENT 做日志分析启动失败是常态这时候 AGENT 的价值就体现出来了。把 QEMU 的串口输出重定向到文件./run_qemu.sh 21 | tee boot.log然后把boot.log丢给 AGENT让它分析。我常用的提示词是分析这份 RISC-V Linux 启动日志找出 PCIe 枚举失败的原因。 重点关注设备树节点、ECAM 地址映射、中断映射、BAR 空间分配。AGENT 会逐行扫描定位到类似pci 0000:00:00.0: bridge configuration invalid这样的错误然后给出修改建议。这比你自己翻几千行日志快得多。5. 常见问题与排查技巧实录5.1 PCIe 设备枚举不到这是最高频的问题。排查顺序我总结成一张表现象可能原因排查方法lspci无输出内核没开CONFIG_PCIzcat /proc/config.gz | grep PCI只有根复合体设备没挂到正确的 bus检查 QEMU 命令行的bus参数BAR 分配失败ECAM 地址范围太小扩大设备树里的reg范围中断不触发MSI-X 未配置检查aiaaplic-imsic参数我遇到最多的是第二种设备挂到了根复合体上但根复合体本身没被内核识别。原因是设备树里的ranges属性写错了导致地址映射失败。ranges的格式是子地址 父地址 长度三个值必须严格对应差一个字节都会导致整个 PCIe 节点被内核忽略。5.2 内核 panic 在 PCIe 初始化阶段如果内核在pci_host_probe附近 panic大概率是设备树里的interrupt-map有问题。RISC-V 的 PCIe 中断映射比 ARM 复杂因为涉及到 PLIC 或 APLIC 的级联。一个实用的排查技巧在 QEMU 命令行加-d int打开中断 trace然后看 panic 前的最后几条中断记录。如果看到plic: invalid irq之类的就是中断号映射错了。提示设备树里的interrupt-map-mask和interrupt-map是一对mask 决定哪些位参与映射计算map 决定映射结果。这两个属性必须成对出现缺一个内核就会用默认值而默认值往往不对。5.3 QEMU 启动卡在 OpenSBI 阶段这种情况通常是-bios和-kernel的配合问题。OpenSBI 的fw_jump会跳转到0x80200000默认地址如果你的内核加载地址不是这个就会跳飞。解决方法有两个一是用-kernel让 QEMU 自动处理加载地址二是手动指定-device loader,addr0x80200000,fileImage。我推荐第一种省事。5.4 实操心得先跑通最小系统再叠加这是我踩了无数坑之后总结的最重要一条经验不要一上来就搭完整的 AI 芯片实验台。先用最简配置跑通一个 RISC-V Linux确认工具链、QEMU、内核、根文件系统这条链路是通的然后再逐步加 PCIe 设备、加多级拓扑、加 AI 加速器模型。我见过太多人一上来就写几百行的 QEMU 命令行结果启动失败后根本不知道是哪一层的问题。分层验证每加一个设备就重启一次确认虽然看起来慢但总时间反而更短。5.5 常见问题速查表问题快速定位命令解决方向工具链找不到which riscv64-linux-gnu-gcc检查 PATHQEMU 无 RISC-V 支持qemu-system-riscv64 -machine help重新编译或换版本内核不启动看串口最后一行检查-kernel和earlyconPCIe 无设备cat /proc/bus/pci/devices检查设备树和 QEMU 参数中断不工作cat /proc/interrupts检查 AIA 配置根文件系统挂载失败看rdinit参数检查 initramfs 格式6. 从实验台到真实芯片的迁移思路QEMU 实验台跑通之后下一步自然是往真实硬件迁移。这里有个认知需要纠正QEMU 验证过的东西不代表真实芯片上一定能跑。QEMU 的 PCIe 模型是理想化的没有时序问题、没有信号完整性问题、没有电源管理问题。真实芯片上PCIe 链路训练Link Training可能就卡住你三天。但 QEMU 实验台的价值在于它帮你把软件层面的问题提前暴露了。设备树写错、驱动配置漏项、中断映射错误这些在 QEMU 里都会以同样的方式报错。等到了真实硬件上你只需要关注硬件相关的问题软件层面的坑已经填平了。迁移的时候AGENT 依然有用。你可以让它对比 QEMU 的设备树和真实芯片手册里的寄存器描述自动生成差异报告。比如 QEMU 里 PCIe 的 ECAM 基地址是0x30000000真实芯片可能是0x60000000AGENT 会提醒你改设备树里的reg属性。我个人在实际操作中的体会是AGENT 最大的价值不是替你写代码而是替你记住那些容易忘的细节。PCIe 的bus-range要留够、interrupt-map要和interrupt-controller对上、earlycon参数不能少——这些东西写一次记不住但 AGENT 每次都会帮你检查。搭实验台这件事本质上是在和细节较劲而 AGENT 恰好擅长处理细节。最后分享一个小技巧把每次成功的 QEMU 命令行和对应的设备树存成一个模板用 AGENT 管理这些模板。下次要模拟新的芯片配置直接让 AGENT 基于模板改参数比从零写快十倍。这套方法我从第一篇实验台搭到现在已经攒了十几个模板覆盖了从单核 RV32 到八核 RV64 加多级 PCIe 拓扑的各种场景。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。