尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32MP257 eMMC启动无限重启之IAC exception 128定位与恢复

STM32MP257 eMMC启动无限重启之IAC exception 128定位与恢复 一开始我以为只是普通的 eMMC 启动配置问题没想到一折腾就是两个通宵。当时正在给 STM32MP257F-EV1 板卡移植 OpenSTDroid流程走到一半先用 USB DFU 模式把所有镜像都烧进了 eMMC烧录过程顺利得让人放松警惕然后按照板卡手册把 BOOT 拨码开关切到 eMMC 启动插上串口线准备看 Android 开机动画。结果等来的不是动画而是一屏接一屏的无限重启串口日志里反复刷着同一个字样IAC exception 128。更让人头疼的是这时候把 USB-C 插到板子上想进 fastboot 抢救宿主机上fastboot devices永远是一片空白连设备都枚举不出来。如果你也卡在这个“进不去 fastboot、又不知道异常是什么”的阶段这篇文章应该能帮你节省大量排查时间。我会把这次从异常分析、根因定位、恢复到把 fastboot 重新唤醒的完整过程记录下来包括串口日志怎么看、RIF 隔离在启动链路上扮演什么角色、DFU 和 eMMC 两种启动路径为什么会有差异以及最容易被忽略的 host 端 USB/驱动问题。1. 先把背景交代清楚OpenSTDroid 在 MP257 上的启动链路1.1 这套系统正常情况下是怎么起机的STM32MP257F-EV1 是 ST 官方评估板主芯片是双核 Cortex-A35 加一个 Cortex-M33跑 OpenSTDroid 的时候A35 负责 Android 侧M33 一般跑 RTOS 或者留空。OpenSTDroid 本质上是 ST 基于 AOSP 裁剪定制的发行版启动流程和常见嵌入式 Android 不太一样它不是直接从某个裸分区跑 kernel而是要走一套完整的 ARM Trusted Firmware 链路。整条链路大概是这样的芯片上电后片内 ROM 根据 BOOT 引脚或者 OTP 配置决定从哪个介质加载 FSBL。FSBL 就是 TF-A 的 BL2负责最基础的时钟、DDR 初始化和安全配置。接着 BL2 会把 BL32OP-TEE和 BL33U-Boot加载进来OP-TEE 提供安全世界服务U-Boot 负责后续的引导包括解析 Android boot image、拉起 DTBO、校验 AVB最后把控制权交给 kernel。OpenSTDroid 里 U-Boot 不只是引导器它同时承担了 fastboot 协议的重任fastboot命令就是跑在 U-Boot 里的通过 USB gadget 对外提供刷机通道。所以你在 eMMC 里看到的分区结构通常会被拉得很开fsbl1、fsbl2放 TF-Afip放封装好的 TF-A/OP-TEE/U-Boot 组合体然后是boot、dtb、vendor、system、vbmeta、userdata这一串 Android 分区。任何一个环节的内容对不上后面就全乱套。1.2 DFU 和 eMMC 这两种启动路径到底差在哪这个问题看似简单但恰恰是理解这次故障的关键。DFU 模式和 eMMC 模式表面上只是“从 USB 下载镜像”和“从存储介质启动”的区别实际上整条链路的执行环境、镜像来源、以及安全世界的初始化状态都完全不同。DFU 场景下你通过 STM32CubeProgrammer 连接板子实际上是把 ROM 里的一段固化 bootloader 激活了。这个阶段 DDR 由 CubeProgrammer 配合下载到 RAM 的 FSBL 来初始化镜像从 USB 直接写入目标分区写完你还可以选择直接让板子从 RAM 启动。整个过程是可控的、短命的而且每一笔写入都由上位机软件盯着中途出错会立刻报出来。eMMC 启动就不一样了。上电那一刻ROM 直接去读 eMMC 的 boot 分区或者 user 分区它的逻辑就一个读出来的 fsbl 能用就继续不能用就死循环或者异常复位。这里没有上位机帮你兜底所有东西都依赖你之前烧进存储介质的内容。一旦 eMMC 里的 fsbl/fip 是旧版本、dtb 不匹配、或者分区地址错位ROM 可能仍然会把某个“能跑的东西”加载起来但跑到后面某个地址访问越界安全隔离机制立刻介入异常就来了。我在这次故障里踩到的就是第二种情况fip 和 user 分区里的镜像来自不同套件U-Boot 能起来但它在跳转到 Android kernel 时访问了不该访问的地址触发了 RIF 安全违规。2. IAC exception 128 到底是什么异常2.1 先看日志异常发生时的现场无论你是在 U-Boot 阶段崩溃还是在 kernel 阶段崩溃串口里多少都会留下点线索。我这边抓到的日志节选如下不同固件版本措辞会有差异但关键信息类似NOTICE: BL2: v2.10-stm32mp2-r1.2 (debug) NOTICE: BL2: Booting STM32MP257F-EV1 NOTICE: BL2: DDR4 init ok (1.6GB) NOTICE: BL2: BL32 (OP-TEE) loaded NOTICE: BL2: BL33 (U-Boot) loaded U-Boot 2024.04-stm32mp2-r1.0 ... Hit any key to stop autoboot: 0 IAC exception 128 ERROR: STM32MP2 RIF illegal access - master CA35, addr 0x48000000 resetting ...注意几个信息点IAC是 Illegal Access Controller 的缩写128在这里不是任意数字它对应 RIF 检测到非法访问后上报给 GIC 的中断号。换言之这不是 CPU 自己抛出来的普通 data abort而是板级安全架构主动拦截了某个访问行为然后用异常的形式把系统锤停了。从直觉上判断master CA35说明发起访问的主角是 Cortex-A35也就是 Linux/Android 侧addr 0x48000000指向的是一段被 RIF 标记为“当前世界无权访问”的地址区间。访问被拦下中断触发处理逻辑里找不到合法的处置方式只能 panic 复位然后无限循环。2.2 RIF/TrustZone 隔离与这个异常的关系STM32MP2 系列引入了一套比老 MP1 复杂得多的资源隔离框架它叫 RIFResource Isolation Framework由 RIMC、RISUP、RISAL 这些子模块组成作用是把外设、内存区域、总线访问权限分配给不同的“执行方”。执行方可以是 Cortex-A35 的安全世界、非安全世界也可以是 Cortex-M33甚至可以是 DMA。每一条访问规则其实都对应一张权限表CPU 在总线上发起读写的瞬间RIF 会在硬件层面检查这次访问是否符合规则。这个设计本身是为了安全但反过来也给 bring-up 阶段挖了不少坑。比如你在 DFU 模式下烧录的时候CubeProgrammer 下载到 RAM 的 FSBL/OP-TEE 和你接下来要启动的 eMMC 里的 FIP如果来自不同版本它们对 RIF 规则的定义可能就不一致。旧版 U-Boot 的 dtb 里声明某个外设是非安全可访问的但新版 TF-A 在安全世界里把它标记成了 secure only那 U-Boot 一旦访问这个外设的寄存器IAC 就立刻亮红灯。更隐蔽的情况是地址错位。分区表如果对不上U-Boot 会从一个错误的位置读取 kernel读到的是旧镜像的残留数据或者干脆是空的但 U-Boot 本身不会立刻感知到“我读的是错的”它只会机械地解析 boot image header然后跳转过去。一旦跳进去的指令流把我们带到了某个不该碰的地址异常就如同约好了一样准时出现。3. 定位根因为什么 DFU 成功、eMMC 反复重启3.1 第一个嫌疑分区表与镜像不匹配这是我在社区里看到最多的情况也是排查时应该第一个排除的。OpenSTDroid 和 openSTLinux 的分区布局是不同的甚至 OpenSTDroid 自己的不同版本之间boot、system这些分区的起始偏移也可能有差异。如果你在 eMMC 里同时混过两套系统的镜像比如之前用 openSTLinux 的 flashlayout 烧过一遍后来直接用 DFU 只更新了 Android 分区那么 bootloader 读到的分区链表和实际存储内容的错位几乎是必然的。验证方法很简单把板子强制进 ROM DFU 模式用 STM32CubeProgrammer 的-l或者读取 eMMC 内容的命令把分区表导出来跟当前 OpenSTDroid 烧录包里的FlashLayout_emmc_stm32mp257f-ev1.tsv文件做比对。重点看fip分区的偏移是不是和镜像里一致boot分区有没有被其他镜像占用。3.2 第二个嫌疑fsbl/fip 是旧版本或串版本分区表没问题的话下一个要看的就是 fsbl 和 fip 的内容。这里有个容易忽略的细节eMMC 有 boot1、boot2 两个专门放启动代码的硬件分区但很多 flashlayout 并不会把 fsbl 写到这两个 boot 分区里而是直接把整条 fip 写到 user 分区的fip分区。如果你之前在别的项目里动过mmc bootpart enable这类命令把 eMMC 的 BOOT_ENABLE 位打开了ROM 的加载路径会完全变化原本你以为在跑的 fsbl 和实际执行的 fsbl 可能根本不是一个东西。我在这次故障里排查到最后问题出在 fip 版本串包eMMC 里残留的 fip 是某个内部测试版的而 user 分区烧的是正式发布版的 OpenSTDroid 镜像。U-Boot 能跑起来但对 dtb 和 AVB 的预期完全不一致最后在 kernel 入口附近被 RIF 拦下。这种问题最坑的地方在于DFU 烧录时你不会有任何感觉因为 DFU 模式走的 FSBL 是从 RAM 里临时加载的跟 eMMC 里实际存的 fip 没有半毛钱关系。3.3 第三个嫌疑U-Boot 环境变量与 AVB 状态残留第三个常见原因是 U-Boot 环境变量里残留了之前的引导参数。U-Boot 在 eMMC 里会划一个专门存环境变量的分区DFU 烧录时如果只写了 fsbl/fip/boot/system没有清掉这个 env 分区那么上电后 U-Boot 还是会按照旧环境变量里的bootcmd、bootargs、mmcroot去执行。这些变量如果指向一个不存在的分区或者错误的 dtb 文件后果同样是引导失败严重时就会触发非法访问。另外OpenSTDroid 默认开了 AVBAndroid Verified Boot。vbmeta分区里如果保存了验签状态而你的 boot 或者 system 分区是被后续手动修改过的AVB 校验失败后 U-Boot 的行为随配置而定有的会回退到 recovery有的会直接 panic 重启。如果你的日志里既看不到明显的内存访问错误又找不到 RIF 违规信息优先怀疑 AVB。3.4 快速判断表总结一下遇到 IAC exception 128 或类似无限重启可以按下面这个表快速划分排查方向现象特征最可能原因优先动作U-Boot 能起来跳到 kernel 后立刻 IACfip 与分区表不匹配 / dtb 版本不对重刷整套 OpenSTDroid 镜像核对 flashlayoutU-Boot 阶段就反复重启日志极短fsbl1/fsbl2 或 fip 损坏强制进入 ROM DFU重刷 fsbl 和 fip偶尔能进系统冷启动必挂DDR 初始化数据不一致或 RIF 初始化顺序问题确认 FIP 与板卡型号完全一致重启前能看到 AVB 相关报错vbmeta 校验失败清空 vbmeta 验签或重新签名打包重启循环但按任意键能停在 U-Bootenv 分区残留旧变量擦除 u-boot-env 分区4. 从“变砖”状态救回来完整恢复流程4.1 强制进入 ROM DFU 模式第一步永远是让板子脱离 eMMC 的噩梦循环回到 ROM 可控的 DFU 模式。STM32MP2 的 ROM 引导序有一个“工程模式”只要 BOOT 引脚组合被设为从 USB/UART 启动上电后 ROM 就不会去碰 eMMC而是直接枚举出一个 USB DFU 设备。具体操作上EV1 板上有一组 BOOT 拨码开关你翻一下板卡用户手册找到对应 USB DFU 启动的组合把拨码切过去然后按住板上的复位键再松手或者直接断电重新上电。这时候在电脑上执行STM32_Programmer_CLI -c portUSB1返回USB1连接成功就说明板子已经进入 ROM DFU。如果这里提示找不到设备先别急着查线路看一下是不是 Windows 驱动没有正确安装或者 Linux/macOS 下 USB 权限不够。ROM 阶段的 DFU 设备在lsusb里能看到 STMicroelectronics 的 VIDPID 通常是df11这种经典 ROM bootloader 编号。4.2 用 STM32CubeProgrammer 检查并重刷 eMMC连接上之后先不要急着刷先做一次侦查。把当前 eMMC 里的分区和内容读出来看一下STM32_Programmer_CLI -c portUSB1 -v 1-v 1在部分版本里能打印目标介质信息也可以直接读取你关心的分区到本地文件。我比较建议的做法是确认完连接后直接执行完整重刷不要在这个阶段做太多手工操作因为我们的目标是恢复不是考古。打开 OpenSTDroid 烧录包找到 eMMC 对应的 flashlayout 文件一般叫FlashLayout_emmc_stm32mp257f-ev1.tsv。执行STM32_Programmer_CLI -c portUSB1 -w FlashLayout_emmc_stm32mp257f-ev1.tsv这条命令会严格按照 tsv 里的定义把 fsbl、fip、boot、vbmeta、system 等所有分区全部写进 eMMC 的正确位置。这里有个小坑如果 tsv 里没有包含擦除 env 分区的步骤U-Boot 环境变量会继续残留。所以刷完之后我建议顺手清一下 env 分区。4.3 清空 U-Boot 环境变量和 vbmeta 校验开关清 env 分区可以用 CubeProgrammer 直接操作STM32_Programmer_CLI -c portUSB1 -el-el在不同版本里行为可能不同更稳妥的办法是按分区名擦除。查看 tsv 里 u-boot-env 对应的分区编号然后执行按编号擦除具体参数以你手上工具版本的 help 为准。擦掉 env 后U-Boot 首次启动会使用编译时写死的默认环境变量这样就排除了旧配置干扰。同时建议在重刷时顺手把 AVB 校验关掉尤其当你只是想让板子先跑起来不关心安全启动的时候。你可以把vbmeta分区刷成带disable-verity和disable-verification标志的镜像或者直接用avbtool生成一个空 vbmetaavbtool make_vbmeta_image --flags 2 --output vbmeta_disabled.img然后把vbmeta_disabled.img通过 tsv 刷到 vbmeta 分区。注意如果是正式量产这个操作会破坏安全启动链我这里只针对开发调试场景。刷完全部镜像后把 BOOT 拨码开关切回 eMMC 启动接上串口上电。这次日志应该能走得更远至少能进 U-Boot 命令行。停在Hit any key to stop autoboot时按一下回车你就可以执行env print检查环境变量用mmc list、part list mmc 0验证分区是否正常。确认无误后输入boot继续引导。5. 把 fastboot 弄回来host 端排查实录5.1 “fastboot waiting for device”的几种死法系统能正常进 Android 之后你可能会发现fastboot devices依然是空的。别急这个阶段的问题大多数不在板子而在 host 端。我归纳了三种最常见的“waiting for device”死法。第一种板子根本没进 fastboot 模式。STM32MP 的 fastboot 是 U-Boot 的一个功能不是 Android 系统自带的那种重启到 bootloader 的行为。你需要在 U-Boot 命令行里手动执行fastboot usb 0或者在 U-Boot 环境里配置好自动进入策略。如果板子还在跑 Android执行adb reboot fastboot也未必能进入 U-Boot 的 fastboot。所以先确认状态接串口看当前是不是停在 U-Boot 里。第二种设备枚举了但 USB 权限不够。Linux 上这是重灾区。fastboot devices没有任何输出但lsusb能看到 STMicroelectronics 的设备说明权限被卡住了。解决方案是写 udev 规则SUBSYSTEMusb, ATTR{idVendor}0483, MODE0666, GROUPplugdev写入/etc/udev/rules.d/51-android.rules然后sudo udevadm control --reload-rules sudo udevadm trigger拔插 USB 再试。第三种Windows 下的驱动问题。STM32MP 的 fastboot 设备在 Windows 里经常被识别成未知设备或者驱动被之前装过的 STLink 驱动抢占了。打开设备管理器找到带感叹号的 STM 设备手动选择 STM32CubeProgrammer 自带的 USB 驱动或者用 Google USB Driver 覆盖。装完之后fastboot devices应该就能看到设备了。5.2 Linux/macOS/Windows 下的 usb 权限与驱动针对不同平台我再展开说几句。Linux 上除了权限问题还容易遇到 fastboot 工具本身太老识别不了新 PID 的情况。建议直接用apt install android-tools-adb android-tools-fastboot或者从 SDK 下官方 platform-tools不要用发行版仓库里八百年不更新的版本。macOS 上尤其是 Apple Silicon 的机器很多人会遇到一个诡异现象STM32CubeProgrammer 能识别 DFU 设备但 fastboot 工具死活看不到。这种情况先确认你是从 U-Boot 进入的 fastboot而不是 ROM 的 DFU 模式两者在系统里的枚举方式完全不同。另外macOS 上usbd守护进程偶尔会抽风sudo killall usbd然后重新拔插一般能解决。Windows 上最容易踩的是 PID 冲突。STM32MP 的 U-Boot fastboot 设备、ROM DFU 设备、STLink 调试器VID 都是0483但 PID 不同。你在设备管理器里看到 USB 设备列表里有一排 STMicroelectronics 开头的设备要认准当前这个带黄叹号的右键更新驱动手动选择STM32CubeProgrammer安装目录里的驱动文件。装错驱动会让 fastboot 能枚举但连不上。5.3 验证链路从 U-Boot 到 adb reboot fastboot最后给一套验证链路免得你来回试半天不知道卡在哪一步。板子停在 U-Boot - 执行 fastboot usb 0 - host 执行 lsusb应该有 STMicroelectronics 新设备出现 - host 执行 fastboot devices应该能看到设备 - fastboot getvar all 能返回版本信息如果lsusb有设备但fastboot devices没有90% 是权限或驱动问题。如果lsusb也没有设备那说明 U-Boot 的 USB gadget 没有起来回串口看是否有dwc2或者usb dr_mode相关的报错多半是 dtb 里 USB 控制器配置不对。Android 系统正常运行后建议把这条链路再走一遍确认adb reboot fastboot能正确让系统重启到 U-Boot 的 fastboot。我在 EV1 上试过如果 U-Boot 环境变量里没有设置对应的fastboot_bootcmdadb reboot fastboot可能只触发了一个普通重启根本进不了 fastboot。这时候在 U-Boot 里手动执行fastboot usb 0是唯一可靠的办法。6. 经验总结与避坑清单这次从故障出现到最终定位我最大的体会是永远不要相信 DFU 烧录成功就等于 eMMC 启动成功。DFU 过程中执行的一切都发生在 RAM 里RAM 里的 FSBL 和 eMMC 里的 fip 完全是两套东西它们之间的版本、配置、分区表一致性需要单独验证。下面是这次实际踩坑后整理出来的清单建议贴在你工位旁边烧录前先确认 flashlayout 文件和目标板卡型号严格匹配EV1 和 DK 板的 tsv 不能混用。重刷系统时顺手清掉 u-boot-env 分区环境变量残留比想象中坑得多。开发阶段直接禁用 AVB把 vbmeta 刷成flags 2的空镜像能减少一大类“莫名重启”。换启动介质后第一次上电一定先接串口别只看屏幕和fastboot devices。串口日志信息量远大于任何调试工具。手上常备当前 OpenSTDroid 版本的 fip 和 fsbl 原始文件RIF 异常排查时可以做对比实验。fastboot devices没输出不等于板子坏了先确认枚举再看权限最后怀疑工具版本。最后再分享一个小技巧如果你遇到 IAC 异常又一时半会定位不了别急着反复擦写整个 eMMC先只重刷 fip 分区很多时候问题就出在 fip 里的 dtb 和 RIF 配置上。fip 是整条安全链路的配置源头它对了后面的 U-Boot 和 kernel 才能在一个合法的访问框架里跑起来。祝你们一次点亮。
返回列表