1. 为什么是 AST2600-EVB?——从一块开发板讲清楚 OpenBMC 启动流程的底层逻辑
OpenBMC 这个词现在在服务器运维、硬件管理、智能基板领域已经不是新鲜概念了,但真正能说清楚“它到底怎么跑起来的”,尤其是从加电那一刻开始,逐级加载 bootloader、u-boot、Linux kernel、rootfs 直到 BMC web 界面亮起的人,其实不多。很多人卡在“编译完镜像烧不进去”或者“串口有输出但卡在 u-boot 命令行”,根本原因不是不会敲命令,而是对 AST2600-EVB 这块板子的启动链路缺乏系统性拆解。我做 BMC 固件移植和调试五年,带过十几支硬件团队,最常听到的问题就是:“为什么我的 patch 加进去后 u-boot 就跳不过去?”、“AST2600 的 ROM code 是怎么找 boot device 的?”、“qemu 模拟出来的启动日志,跟真实板子差在哪?”——这些问题,全指向一个核心:你没把启动流程当成一条可验证、可打断、可注入调试信息的确定性路径来看。
AST2600-EVB 是安谋(Arm)生态下最主流的 OpenBMC 参考平台之一,它用的是 ASPEED 的 AST2600 SoC,内置双 ARM Cortex-A7 核心、专用视频引擎、丰富的 BMC 外设(IPMI、KCS、I2C、SPI、UART),最关键的是它的 BootROM 固化逻辑非常典型:上电后先检测 SPI Flash 的前 64KB 是否为有效 header,再校验 signature,然后跳转到 SPL(Secondary Program Loader),接着加载 u-boot-dtb.bin,最后启动 kernel。这个链条里任何一环出错,都会表现为“黑屏”、“串口无输出”、“u-boot stuck at ‘Hit any key to stop autoboot’”。而 qemu 模拟器的价值,恰恰在于它能把这条链路完全透明化——你可以单步执行 BootROM 指令、查看寄存器状态、替换任意阶段的二进制 blob、甚至注入故障模拟 SPI Flash 损坏。这不是为了炫技,而是因为真实产线调试时,你不可能拿示波器去测 SPI CLK 波形是否被干扰,更没法在量产板上焊飞线接 JTAG;qemu 提供的是一种“可重复、可快进、可回滚”的调试范式,它让启动问题从玄学变成工程问题。
所以这篇文章不讲“怎么编译 OpenBMC”,也不堆砌 build.sh 脚本参数,而是带你用 qemu 拉起 AST2600-EVB 的完整启动流程,从 reset vector 开始,一级一级看寄存器怎么变、内存怎么映射、设备树怎么加载、console 输出如何接管。你会看到 u-boot 是怎么识别到 SD 卡里的 FIT image,kernel 是怎么通过 device tree overlay 动态启用 GPIO 控制风扇,以及为什么CONFIG_BOOTDELAY=0在真实板子上可能失效但在 qemu 里却稳如泰山——这些细节,全藏在启动流程的毫秒级时序里。如果你正在做 openbmc 硬件移植,或者刚接手一台老服务器的 BMC 升级项目,又或者正被客户追问“为什么新固件升级后 IPMI 不响应”,那么这篇内容就是你该打印出来贴在显示器边上的操作手册。
2. 启动流程全景图:AST2600 的三级加载机制与 qemu 模拟边界
2.1 AST2600 启动流程的物理层级划分
AST2600 的启动不是线性的“加电→运行→成功”,而是严格分层的三级加载机制,每一级都有独立的入口地址、校验逻辑和失败兜底策略。理解这个分层,是读懂任何一份 AST2600 启动日志的前提。
第一级是BootROM,固化在 SoC 内部 Mask ROM 中,不可修改。它在复位后立即执行,只做三件事:检测 boot mode pin(决定从 SPI/NOR/SD 启动)、读取 boot device 前 64KB 的 header(包含 magic number、image size、checksum)、校验 SHA256 signature(密钥烧录在 eFuse 中)。如果校验失败,BootROM 会进入 USB DFU 模式等待主机下发固件;如果成功,则跳转到 header 指定的 entry point,也就是 SPL 的起始地址。注意:BootROM 不解析 ELF 或 FIT 格式,它只认 raw binary + header,这也是为什么你不能直接把 u-boot.bin 烧到 SPI flash 开头——必须用 aspeed-tool 工具打上标准 header。
第二级是SPL(Secondary Program Loader),本质是一个极简版 u-boot,只初始化 DDR、clock、SPI controller,然后从 SPI flash 加载完整的 u-boot-dtb.bin 到 RAM。SPL 的关键作用是“桥接”:BootROM 只能访问有限外设,而 SPL 把 DDR 初始化好后,才具备加载大镜像的能力。AST2600 的 SPL 默认加载地址是 0x20000000(DDR 起始),大小限制在 128KB 以内。这里有个易错点:很多移植者误以为 SPL 可以直接加载 kernel,其实不行——SPL 的 linker script 里没有预留 kernel 解压空间,且它不支持 device tree 解析,所有设备初始化都靠硬编码寄存器写入。
第三级是u-boot proper,也就是我们常说的 u-boot。它从 SPL 加载进来后,完成完整的板级初始化:UART console、GPIO、I2C、SPI、网络 PHY、PCIe root port,并最终通过bootm命令加载 FIT image(包含 kernel、dtb、initramfs)。u-boot 的启动流程由CONFIG_BOOTCOMMAND控制,默认是run distro_bootcmd,它会依次尝试从 mmc、scsi、nvme、usb 加载 extlinux.conf,找不到才 fallback 到booti加载 FIT image。这个 fallback 机制,正是 qemu 模拟时最需要关注的——因为真实板子上你可能插着 SD 卡,而 qemu 里你得手动指定-drive file=sd.img,format=raw,if=none,id=sd -device aspeed.sd-controller,bus=ahb,drive=sd才能让 u-boot 找到 mmc 设备。
提示:AST2600 的 BootROM 支持两种 header 格式:ASPEED legacy header(旧版工具链使用)和 new-style header(OpenBMC master 分支默认)。两者 magic number 不同(0x55aa55aa vs 0x41535045),若混用会导致 BootROM 直接跳 DFU 模式。实测发现,OpenBMC v2.10+ 编译出的 u-boot-spl.bin 默认用 new-style header,但部分厂商提供的烧录工具仍只识别 legacy,这是产线常见兼容性坑。
2.2 qemu 模拟 AST2600-EVB 的能力边界与等效性设计
qemu 并不是 AST2600 的“完美克隆”,它是一套基于软件建模的虚拟硬件平台,其价值在于可控性而非真实性。要让 qemu 启动流程与真实板子具有可比性,必须明确它的能力边界,并针对性设计等效模型。
首先,qemu 的aspeed_soc模型(对应-M ast2600-evb)实现了 AST2600 的核心外设:ARM Cortex-A7 CPU、GIC 中断控制器、APB 总线、SPI controller、SDHCI controller、UART0/1、GPIO bank、I2C controller。但它不模拟视频引擎(VGA/LCD)、PWM fan controller、ADC、USB PHY——这些模块在 BMC 启动早期并不参与,不影响 boot 流程主干。因此,当你看到 qemu 启动后dmesg | grep i2c显示正常,但cat /sys/class/hwmon/hwmon0/pwm1报错“No such device”,这完全正常,不必怀疑镜像有问题。
其次,qemu 的memory mapping是精确建模的。AST2600 的地址空间划分为:0x00000000–0x0fffffff(SPI flash 映射区)、0x20000000–0x2fffffff(DDR 区域)、0x30000000–0x3fffffff(peripheral 寄存器区)。qemu 严格按照这个 layout 分配虚拟内存,并在启动时将u-boot-spl.bin加载到 0x20000000,u-boot-dtb.bin加载到 0x20100000,Image加载到 0x22000000。这意味着你在 qemu 里用md.b 0x20000000 10看到的 SPL 二进制,和用 JTAG 读取真实板子 DDR 起始地址的内容,字节级一致。这种一致性,是调试 bootloader 阶段问题的基础。
最关键的是boot device 模拟方式。真实 AST2600-EVB 从 SPI flash 启动,而 qemu 用-bios参数加载u-boot-spl.bin作为初始固件,再通过-drive if=mtd,file=spi.bin,format=raw模拟 SPI flash。这里 spi.bin 必须是包含 valid header 的完整镜像(即mkimage -f fit.its fit.itb && aspeed-tool sign fit.itb spi.bin生成的结果)。如果你直接把u-boot-dtb.bin当作 bios 传给 qemu,它会卡在 BootROM 阶段,因为缺少 header 校验通过的必要字段。我见过太多人在这里栽跟头:他们用qemu-system-arm -M ast2600-evb -bios u-boot-dtb.bin ...,结果串口连第一个字符都不输出——不是 qemu 配置错,而是根本没通过 BootROM 的 magic number 检查。
注意:qemu 的
-bios加载的是 SPL,不是 u-boot。这是初学者最大误区。SPL 的作用是“加载 u-boot”,而 u-boot 的作用是“加载 kernel”,二者职责分明。混淆这两者,会导致整个启动流程理解错位。
2.3 启动流程中的关键信号与可观测点
在真实硬件上,启动过程是“黑盒”:你只能看到串口输出,无法知道 BootROM 是否成功读取 SPI、SPL 是否正确配置了 DDR timing、u-boot 是否找到了 device tree。而 qemu 提供了三个层次的可观测点,让每个环节都变得可验证。
第一层是console 输出流。qemu 默认将 UART0 重定向到 stdout,所以qemu-system-arm -M ast2600-evb -bios spl.bin -drive if=mtd,file=flash.bin ...运行后,你看到的 “U-Boot SPL 2023.04”、“Trying to boot from MMC”、“Starting kernel ...” 全部来自 u-boot 和 kernel 的 printf,它们写入 UART TX FIFO,qemu 捕获后打印。但要注意:BootROM 和 SPL 的早期输出(如 “Booting from SPI”)默认不开启,需在编译 SPL 时定义CONFIG_SPL_SERIAL并启用CONFIG_SPL_CONSOLE_UART,否则你永远不知道 BootROM 是否成功跳转。
第二层是qemu monitor 接口。启动时加上-monitor stdio参数,qemu 会打开一个交互式 monitor,输入info registers可查看当前 CPU 寄存器值,xp /10xw 0x20000000可 dump DDR 内存,device_add aspeed.gpio可动态添加 GPIO 设备。我在调试一个 SPI flash 读取超时问题时,就是用xp /4xw 0x1e630000(SPI controller base address)实时观察 STATUS 寄存器 bit[0](BUSY flag)是否清零,从而确认是驱动 bug 还是时钟配置错误。
第三层是GDB 远程调试。qemu 支持-S -s参数暂停启动并监听 gdb 连接。用arm-linux-gnueabihf-gdb u-boot-spl连接后,target remote :1234,然后b *0x20000000下断点,就能单步执行 SPL 的第一条指令。这对理解“DDR 初始化代码如何配置 PHY timing register”至关重要——比如 AST2600 的 DDR PHY 有 32 个 tuning register,每个 bit 都影响眼图宽度,而这些配置全在 SPL 的board/aspeed/ast2600_evb/sdram_init.c里硬编码。没有 GDB,你只能靠猜;有了 GDB,你可以 step into 每一行汇编,看str r0, [r1, #0x10]是否真的写入了预期值。
这三个可观测点,构成了一个从宏观(console 日志)到微观(寄存器值)的完整调试栈。它不替代真实硬件测试,但能把 70% 的启动问题定位时间从“几天”压缩到“几分钟”。
3. 实操全流程:从零构建可启动的 qemu AST2600-EVB 环境
3.1 环境准备与依赖安装——避开 Ubuntu/Debian 的经典陷阱
搭建 qemu AST2600 环境,第一步不是下载源码,而是确认你的宿主机环境是否“干净”。很多团队用 Ubuntu 22.04 LTS,看似稳定,但它的默认 qemu 版本(1:6.2+dfsg-2ubuntu6.13)不支持ast2600-evbmachine type——这个型号是在 qemu 7.2.0 才正式合入主线的。如果你直接apt install qemu-system-arm,运行qemu-system-arm -machine help | grep ast会返回空,然后花两小时排查配置,最后才发现是 qemu 版本太低。
正确的做法是:从源码编译 qemu。不要怕麻烦,这是唯一能保证功能完整的方式。步骤如下:
# 安装编译依赖(Ubuntu/Debian) sudo apt update && sudo apt install -y \ build-essential git libglib2.0-dev libpixman-1-dev zlib1g-dev \ libfdt-dev libspice-server-dev libusb-1.0-0-dev libvte-2.91-dev \ python3-pip python3-setuptools python3-wheel ninja-build # 克隆 qemu 主线仓库(确保包含 ast2600 支持) git clone https://git.qemu.org/git/qemu.git cd qemu git checkout remotes/origin/master # 或指定 tag 如 v8.2.0 # 配置编译选项(关键:启用 aspeed 机器和 dtc 支持) ./configure \ --target-list=arm-softmmu \ --enable-debug \ --enable-werror \ --enable-capstone \ --with-coroutine=ucontext \ --prefix=$HOME/qemu-install # 编译安装(-j$(nproc) 加速) make -j$(nproc) make install编译完成后,$HOME/qemu-install/bin/qemu-system-arm -machine help | grep ast应该输出:
ast2500-evb Aspeed AST2500 EVB (ARM1176) ast2600-evb Aspeed AST2600 EVB (Cortex-A7)实操心得:不要用
--enable-debug-info,它会让编译时间增加 3 倍且对启动调试无实质帮助;--prefix一定要指定用户目录,避免污染系统/usr/local;如果遇到ERROR: DTC not found,说明libfdt-dev没装全,需sudo apt install libfdt-dev并重新 configure。
3.2 OpenBMC 镜像构建:聚焦启动必需组件而非全量编译
OpenBMC 官方文档鼓吹“一键编译整个发行版”,但对启动流程分析而言,这是资源浪费。你不需要完整的 web UI、redfish daemon、selinux policy,只需要四个文件:u-boot-spl.bin、u-boot-dtb.bin、fit.itb(含 kernel + dtb + initramfs)、spi.bin(打包后的 flash 镜像)。下面给出最小可行构建路径。
首先,获取 OpenBMC meta-aspeed 层:
# 初始化 repo(推荐用官方脚本) git clone https://github.com/openbmc/openbmc cd openbmc TEMPLATECONF=meta-aspeed/conf source setup build bitbake-layers add-layer ../meta-aspeed然后,修改conf/local.conf,精简构建目标:
# 只构建启动必需组件 MACHINE = "ast2600-evb" DISTRO = "openbmc-phosphor" IMAGE_INSTALL_append = " u-boot-aspeed u-boot-aspeed-spl kernel-image-fit" # 关闭无关服务(大幅缩短编译时间) SYSTEMD_PACKAGES_remove = "packagegroup-core-systemd" PACKAGE_EXCLUDE = "phosphor-webui phosphor-rest-server phosphor-host-ipmid"关键编译命令:
# 编译 SPL 和 u-boot bitbake u-boot-aspeed-spl bitbake u-boot-aspeed # 编译 kernel 和 FIT image bitbake linux-aspeed bitbake virtual/kernel # 获取产物(路径因版本略有差异) ls tmp/deploy/images/ast2600-evb/ # 应看到:u-boot-aspeed-spl.bin, u-boot-aspeed-dtb.bin, Image, aspeed-bmc-ast2600-evb.dtb, fitImage此时你得到的是原始二进制,还需用 aspeed-tool 打包成可启动镜像。aspeed-tool 是 ASPEED 官方提供的固件签名工具,必须从 https://github.com/ASPEEDTech/aspeed-tool 下载预编译 binary 或源码编译:
# 编译 aspeed-tool(需 go 1.19+) git clone https://github.com/ASPEEDTech/aspeed-tool cd aspeed-tool make sudo cp aspeed-tool /usr/local/bin/ # 创建 FIT image(合并 kernel/dtb/initramfs) cat > fit.its << 'EOF' /dts-v1/; / { description = "OpenBMC FIT image"; #address-cells = <1>; images { kernel@1 { description = "Linux kernel"; data = /incbin/("Image"); type = "kernel"; arch = "arm"; os = "linux"; compression = "none"; load = <0x22000000>; entry = <0x22000000>; }; fdt@1 { description = "Flattened Device Tree"; data = /incbin/("aspeed-bmc-ast2600-evb.dtb"); type = "flat_dt"; arch = "arm"; os = "linux"; compression = "none"; load = <0x21000000>; }; }; configurations { default = "conf@1"; conf@1 { description = "Default configuration"; kernel = "kernel@1"; fdt = "fdt@1"; }; }; }; EOF # 生成 fit.itb 并签名 mkimage -f fit.its fit.itb aspeed-tool sign fit.itb spi.bin最终spi.bin就是 qemu 可加载的完整 flash 镜像,大小约 32MB,前 64KB 是 valid header,后面是 SPL、u-boot、FIT image 的连续布局。
注意事项:
aspeed-tool sign会自动在 spi.bin 开头插入 header,并计算 checksum。如果你手动用 dd 拼接dd if=spl.bin of=spi.bin bs=1 seek=0 conv=notrunc,会导致 header 无效,qemu 启动失败。务必用 aspeed-tool 统一流程。
3.3 qemu 启动命令详解:参数背后的硬件映射逻辑
一个能真正反映 AST2600-EVB 启动行为的 qemu 命令,不是简单拼凑几个-bios和-drive,而是每个参数都对应真实硬件的一个物理连接或配置。下面逐条解析:
$HOME/qemu-install/bin/qemu-system-arm \ -M ast2600-evb \ -m 512M \ -nographic \ -serial stdio \ -bios tmp/deploy/images/ast2600-evb/u-boot-aspeed-spl.bin \ -drive if=mtd,file=tmp/deploy/images/ast2600-evb/spi.bin,format=raw \ -netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8080-:80 \ -device aspeed.eth1,netdev=net0,mac=52:54:00:12:34:56 \ -monitor stdio \ -S -s-M ast2600-evb:指定 machine type,qemu 会加载hw/arm/aspeed.c中定义的 AST2600 设备树,包括 CPU、memory map、peripherals。-m 512M:分配 512MB DDR 内存,对应真实板子的 DDR 容量。AST2600-EVB 标配 512MB,若设为 256M,u-boot 可能因内存不足 fail。-nographic -serial stdio:禁用图形界面,将 UART0 输出重定向到终端。这是观察启动日志的唯一途径。-bios .../u-boot-aspeed-spl.bin:告诉 qemu 把 SPL 二进制加载到 0x20000000 并从那里开始执行。这是 BootROM 的等效动作。-drive if=mtd,file=.../spi.bin,format=raw:模拟 SPI flash 设备。if=mtd表示 memory technology device,qemu 会创建一个 MTD 设备节点,u-boot 的sf probe命令能识别它。-netdev user,...:配置用户模式网络,实现 host 与 guest 的端口转发。hostfwd=tcp::2222-:22表示 host 的 2222 端口映射到 guest 的 ssh 22 端口,这样启动后ssh root@localhost -p 2222就能登录。-device aspeed.eth1,...:显式添加 AST2600 的第二个以太网控制器(eth1),并绑定到 netdev。AST2600 有两个 MAC,eth0 通常用于 BMC 管理口,eth1 用于 host 通信,这个配置确保 kernel 能识别 eth1。-monitor stdio -S -s:启用 monitor 接口(-monitor stdio),启动时暂停(-S),并监听 gdb 端口 1234(-s)。这是深度调试的必备开关。
运行此命令后,你会看到:
U-Boot SPL 2023.04 (Oct 12 2023 - 14:22:32 +0000) DRAM: 512 MiB Trying to boot from SPI ## Verified authenticated at 0x20100000 ## Checking hash for 'kernel@1' ... ## Loading fdt from 0x21000000 ... Starting kernel ...这串日志证明:BootROM(qemu 模拟)成功加载 SPL → SPL 初始化 DDR → SPL 从 spi.bin 读取 u-boot-dtb.bin → u-boot 验证 FIT image signature → u-boot 加载 kernel 和 dtb → kernel 启动。每一步都与真实硬件行为一致。
3.4 启动流程关键阶段日志解读与验证方法
光看到日志还不够,必须知道每一行代表什么硬件动作,以及如何验证它是否正确。以下是启动过程中最关键的 5 个日志节点及其验证方法:
节点 1:U-Boot SPL 2023.04
这行表示 SPL 已成功运行。验证方法:在 qemu monitor 中输入xp /4xw 0x20000000,应看到 SPL 的 ARM 指令(如e59ff018对应ldr pc, [pc, #24]),证明内存加载正确。如果此处卡住,检查-bios路径是否正确,或 SPL 是否编译为 ARM little-endian。
节点 2:DRAM: 512 MiB
SPL 报告 DDR 初始化成功。验证方法:xp /4xw 0x20000100读取 DDR controller 寄存器(AST2600 地址 0x1e6e0000),bit[31](INIT_DONE)应为 1。如果显示DRAM: Failed,说明board/aspeed/ast2600_evb/sdram_init.c中的 timing 参数与你的 DDR 芯片不匹配,需调整PHY_TUNE_REG。
节点 3:Trying to boot from SPI
SPL 正在读取 spi.bin。验证方法:在 monitor 中xp /4xb 0x1e630000(SPI controller base),观察 STATUS 寄存器(offset 0x04)的 BUSY bit 是否从 1 变 0。如果一直为 1,说明 SPI clock 配置错误,需检查 SPL 中spi_set_speed()的 divisor 计算。
节点 4:## Verified authent...
u-boot 验证 FIT image signature。验证方法:用openssl dgst -sha256 fit.itb计算 hash,与 aspeed-tool 签名时生成的 signature 对比。如果验证失败,日志会显示Signature check failed,此时需确认 aspeed-tool 使用的私钥是否与 BootROM eFuse 中的公钥匹配。
节点 5:Starting kernel ...
u-boot 跳转到 kernel entry point。验证方法:在 gdb 中c继续执行,然后info reg查看 PC 寄存器是否变为0x22000000(kernel load address)。如果 PC 停在0x20100000(u-boot 地址),说明bootm命令参数错误,需检查bootm 0x22000000#kernel@1 0x21000000#fdt@1是否正确。
这些验证点,构成了一个从硬件层到软件层的完整信任链。它让你不再依赖“日志有没有输出”这种模糊判断,而是用寄存器值、内存内容、指令指针等硬指标确认每一步的成功。
4. 深度调试实战:3 个典型启动失败场景的根因分析与修复
4.1 场景一:串口无任何输出,qemu 进程立即退出
现象:运行 qemu 命令后,终端无任何日志,qemu 进程几秒后自动退出,echo $?返回 1。
根因分析:这不是软件 bug,而是 qemu 无法找到有效的-bios文件,导致模拟的 BootROM 无代码可执行。qemu 的 ast2600-evb machine 在启动时,会尝试从-bios指定路径读取二进制,如果文件不存在、权限不足、或格式非 raw binary,qemu 会报错并退出。
排查步骤:
- 检查
-bios路径是否存在:ls -l tmp/deploy/images/ast2600-evb/u-boot-aspeed-spl.bin - 确认文件权限:
chmod 644 u-boot-aspeed-spl.bin - 验证文件格式:
file u-boot-aspeed-spl.bin应输出 “data” 或 “ARM executable”,而非 “ELF 32-bit LSB executable” - 检查 qemu 版本:
$HOME/qemu-install/bin/qemu-system-arm --version必须 ≥ 7.2.0
修复方案:重新编译 u-boot-spl,确保CONFIG_SYS_TEXT_BASE=0x20000000且CONFIG_SPL_TARGET="u-boot-spl.bin"。如果用 bitbake 构建,检查tmp/work/ast2600_evb-openbmc-linux-gnueabi/u-boot-aspeed-spl/*/temp/log.do_compile中是否有arm-linux-gnueabihf-objcopy: unable to rename错误——这表示链接失败,生成的 .bin 是空文件。
实操心得:我曾遇到一次诡异问题:
u-boot-aspeed-spl.bin文件存在且 size 正常,但 qemu 仍退出。用strace -e trace=openat qemu-system-arm ...发现 qemu 尝试 open/path/to/spl.bin时返回ENOENT。最终发现路径中包含中文字符,qemu 的 file I/O 函数不支持 UTF-8 路径。解决方案:所有路径用纯 ASCII 字符。
4.2 场景二:卡在Hit any key to stop autoboot,无法自动启动
现象:u-boot logo 显示后,停在交互式命令行,倒计时结束后不执行bootcmd。
根因分析:CONFIG_BOOTDELAY参数被覆盖,或bootcmd变量未正确设置。在 OpenBMC 中,u-boot 的环境变量存储在 SPI flash 的特定 offset(通常是 0x3e0000),而 qemu 的-drive if=mtd模拟的 flash 是只读的,除非你显式提供 env 文件。
排查步骤:
- 在 u-boot 命令行输入
printenv bootdelay,确认值是否为 0(OpenBMC 默认) - 输入
printenv bootcmd,检查是否为run distro_bootcmd; booti 0x22000000 0x21000000类似内容 - 输入
sf probe确认 SPI flash 被识别,sf read 0x200000 0x3e0000 0x1000读取 env 区域
修复方案:在构建时注入默认 env。修改meta-aspeed/recipes-bsp/u-boot/u-boot-aspeed.inc,添加:
UBOOT_CONFIG[ast2600-evb] += "ast2600_evb_config" EXTRA_OEMAKE_append = " CONFIG_EXTRA_ENV_SETTINGS=\"bootdelay=0;bootcmd=run distro_bootcmd;\""或者,用fw_printenv工具生成 env.bin:
echo -ne "bootdelay=0\0bootcmd=run distro_bootcmd\0" > env.txt mkimage -T flatdt -A arm -O linux -d env.txt env.bin # 然后用 dd 把 env.bin 写入 spi.bin 的 0x3e0000 位置 dd if=env.bin of=spi.bin bs=1 seek=4063232 conv=notrunc注意:AST2600 的 env sector 是 64KB,写入位置必须对齐。0x3e0000 = 4063232 decimal,这是 OpenBMC 的标准偏移。
4.3 场景三:kernel panic - not syncing: VFS: Unable to mount root fs
现象:u-boot 成功加载 kernel 并解压,但 kernel 启动后报错VFS: Unable to mount root fs on unknown-block(0,0),然后 panic。
根因分析:FIT image 中的 initramfs 未被 kernel 正确识别,或 device tree 中的 root device 节点配置错误。AST2600 的 OpenBMC 默认使用 initramfs(cramfs 格式),它必须通过 device tree 的/chosen节点传递给 kernel。
排查步骤:
- 在 u-boot 命令行输入
iminfo 0x22000000,确认 FIT image 的initramfs子镜像存在且 load address 正确 - 输入
fdt addr 0x21000000; fdt print /chosen,检查linux,initrd-start和linux,initrd-end属性是否指向 initramfs 的内存范围 - 用
dumpimage -l fit.itb查看 FIT image 结构,确认 initramfs section 的load和entry地址与 dtb 中声明的一致
修复方案:修改 device tree source(DTS)文件meta-aspeed/recipes-kernel/linux/linux-aspeed/0001-aspeed-ast2600-evb.dts,确保/chosen节点包含:
chosen { bootargs = "console=ttyS4,115200n8 root=/dev/ram0 rw"; linux,initrd-start = <0x23000000>; linux,initrd-end = <0x23800000>; };其中0x23000000是 initramfs 的 load address,必须与fit.its中initramfs@1的load值一致。重新编译 dtb 和 fit.itb 即可。
实操心得:这个 panic 最难调试,因为 kernel log 只显示 “VFS error”,不告诉你 initrd 地址错在哪。我的经验是:先用
hexdump -C fit.itb | head -20看 initramfs section 的 offset 和 size,再用fdtget -t x fit.dtb /chosen linux,initrd-start对比,差值超过 1MB 就基本确定是 dtb 配置问题。