用途:ARM32 嵌入式板(IMX6ULL / Allwinner / Rockchip RK3xxx / STM32MP 等)启动与运行期问题的"症状 → 根因 → 排查方向"速查。
使用方式:先按阶段定位(SPL → U-Boot → Kernel → 运行时),再按表查。大部分 bug 可在 5 分钟内缩到 1–2 个方向。
维护原则:新踩到的坑就补一行,过时的项就删,不追求"全"但追求"命中率"。
1. SPL / BootROM 阶段
症状 | 根因 | 排查方向 |
串口完全无输出 | BOOT_MODE 引脚 / OTP 熔丝配错;串口引脚未复用;PMIC 未完全上电 | 万用表测 BOOT_MODE 电平;核对 fuse map;示波器看 UART TX 波形 |
SPL 跑到一半挂住,串口无输出 | SPL 体积超 OCRAM 限制,覆盖 stack / BSS | arm-none-eabi-size u-boot-spl 查段大小;核对链接脚本 .bss / .stack 地址 |
DDR 校准失败(SPL 报错或直接 reset) | LPDDR/DDR3 时序参数不对;PCB 走线长度/阻抗问题;电源时序 | 对照 RPA (DDR 参考包) 工具生成的参数;跑 dram_test / mtest 扫频;示波器看 DQS/CLK |
SPL 打印 DDR OK 但加载 U-Boot 失败 | eMMC / NAND 读失败;镜像偏移错;坏块 | 核对 CONFIG_SYS_MMC_U_BOOT_START;NAND 坏块表;用 USB serial download 单独验证镜像 |
HAB 认证失败(启用 secure boot 时) | 签名未匹配 SRK hash;CSF 配置错 | hab_status 看事件日志返回码;对照 NXP CST 文档解读 event |
2. U-Boot 阶段
症状 | 根因 | 排查方向 |
U-Boot 启动后立即 hang | 向量表未 32B 对齐;relocation 失败; CONFIG_SYS_TEXT_BASE 与实际加载地址不符 | 检查链接脚本 vector 段对齐;启动 log 看 Relocating to ... 是否完成 |
saveenv 后重启变量丢失 | env 存储介质有坏块; CONFIG_ENV_OFFSET 与分区表冲突;env CRC 校验失败 | printenv 对比;mmc read / nand dump 手动读 env 区看内容 |
bootm 报 Bad Magic Number | DTB / kernel / initramfs 三个地址互相重叠覆盖 | md.l 0x83000000 看 DTB magic 0xd00dfeed;对照三个加载地址 + 实际镜像大小 |
网络启动 tftp 失败 | PHY 未复位 / MDIO 时序; ethaddr 未设;交换机端口协商失败 | mii info 看 PHY 状态;抓包看 ARP / TFTP 流程卡在哪一步 |
3. Kernel 启动阶段
症状 | 根因 | 排查方向 |
Starting kernel ... 后无任何输出 | earlycon 未配置;DTB 地址错误或被覆盖;内核编译时 CPU 架构与实际不符 | bootargs 加 earlycon= • CONFIG_DEBUG_LL=y;md.l $fdt_addr 看 magic |
Uncompressing Linux... 卡死 | 解压缓冲被 initrd / DTB 覆盖;zImage 需要 text + ~4MB 解压 headroom | 检查 bootm 三地址间距;给 kernel 加载地址向下挪 |
Error: unrecognized/unsupported machine ID | DTB 与内核不匹配; CONFIG_OF 未启用 | 核对 DTB compatible 字符串与驱动 of_match_table;dtc -I dtb -O dts 反编译看 |
Kernel panic 在 VFS: Unable to mount root fs | root= 参数错;MMC / NAND 驱动未编入;initramfs 未加载 | bootargs 看 root= 写法;/proc/partitions 是否列出设备;是否编入必要的 bus driver |
启动一半 hang 在某个 initcall | 驱动 probe 卡死(等 irq / 等 regulator / 等 clock) | bootargs 加 initcall_debug;dmesg 看最后打印的 initcall 名字 |
4. 运行时
症状 | 根因 | 排查方向 |
Kernel panic: Unable to handle kernel paging request at virtual address 0xXXXX | 驱动硬编码物理地址没走 ioremap;ioremap 后指针走出 vmalloc 区;use-after-free | /proc/vmallocinfo;dmesg Virtual kernel memory layout;启用 KASAN |
DMA 数据偶发损坏 | DMA buffer 不一致(cache 未 flush / invalidate);DMA buffer 落在 kernel / initrd 尾部 | 改用 dma_alloc_coherent;/proc/iomem • dma-ranges 看冲突;CONFIG_DMA_API_DEBUG=y |
大版本升级后 bootcmd 挂了 | kernel 或 initramfs 膨胀超出内存布局预留间隔 | ls -l 镜像大小 vs 布局空洞裕量;必要时动 bootcmd 加载地址 |
Oops 在 copy_to_user / copy_from_user | 用户指针非法;驱动直接解引用用户指针(ARM64 上 PAN 会直接挡) | 所有用户指针访问必须走 copy_{to,from}_user / get_user / put_user |
OOM killer 频繁触发 | lowmem 耗尽(ARM32 512MB 很容易);某处内存泄漏 | cat /proc/meminfo;slabtop 看哪个 cache 在涨;/proc/vmallocinfo |
偶发 hard lockup / soft lockup | 中断风暴;spinlock 嵌套错;irqoff 时间过长 | CONFIG_LOCKUP_DETECTOR=y;ftrace function_graph • irqsoff tracer |
5. 通用排查工具箱
类别 | 工具 / 命令 | 场景 |
早期串口 | earlycon=, CONFIG_DEBUG_LL=y, CONFIG_EARLY_PRINTK=y | kernel 启动早期(console 未就绪) |
内存视图 | /proc/iomem, /proc/vmallocinfo, /proc/meminfo, /proc/slabinfo | 查地址占用 / 泄漏 |
内核布局 | dmesg Virtual kernel memory layout | vmalloc / lowmem 实际边界 |
镜像分析 | arm-none-eabi-size, objdump -h, readelf -S | 段大小 / 符号定位 |
DTB | md.l <addr> (U-Boot), dtc -I dtb -O dts, fdtdump | 看设备树 magic / 内容 |
Tracing | ftrace ( function_graph, irqsoff, preemptoff), perf, bpftrace | 运行时延迟 / 调用链 |
Sanitizer | KASAN, UBSAN, LOCKDEP, DMA_API_DEBUG | 内存越界 / 锁序 / DMA 误用 |
JTAG | T32, OpenOCD, SEGGER J-Link | SPL / U-Boot 早期 hang;打 watchpoint |
硬件 | 万用表、示波器、逻辑分析仪 | BOOT_MODE / DDR DQS / PMIC 上电时序 |
6. 快速信号辨识(经验法则)
- 完全无输出:九成在 BootROM → SPL 之前。查启动模式引脚 / OTP / 串口复用。
- 输出一半停住:看最后一条打印。九成是下一段代码跑进没建页表 / 没上电 / 没初始化的区域。
- 跑进内核但挂载 rootfs 失败:九成是
bootargs/ DTB / 驱动三者之一不对,按顺序排查。
- 启动 OK 但运行时偶发问题:九成是 DMA / cache / 并发 / 内存泄漏,启用 sanitizer 比瞪代码快十倍。
- 大版本升级后才出问题:九成是镜像膨胀撞到布局边界或隐藏依赖断裂。先
ls -l对比体积,再看 bootcmd。
7. 何时换手段
- 串口看不够 → 上 JTAG。
- JTAG 还不够 → 上逻辑分析仪 / 示波器。
- 硬件信号都正常还挂 → 九成是并发或内存模型,换 sanitizer / tracer 视角。
- 本地复现不了 → 在现场机器上抓 ftrace + crash dump,回来慢慢看。






