1. 当系统卡在Starting Kernel时发生了什么每次看到屏幕上出现Starting Kernel后系统突然卡住作为嵌入式开发者的血压都会瞬间升高。这个看似简单的提示背后其实隐藏着Uboot、设备树和内核三者之间复杂的三角关系。我遇到过太多次这种情况有时候甚至怀疑是不是开发板在故意和我作对。让我们先理清这个启动过程的完整链条。当Uboot完成硬件初始化后它会做三件关键事加载内核镜像通常是zImage、加载设备树文件dtb、传递启动参数。这三者就像三个齿轮必须严丝合缝才能正常运转。其中任何一个环节出错系统就会在Starting Kernel这个节点卡住——因为这时Uboot已经完成了它的使命正准备把控制权交给内核但内核却因为各种原因无法继续执行。常见的问题症状可能有完全卡死没有任何输出出现部分内核日志后停止反复重启如果是看门狗没配置好我在i.MX6ULL平台上就遇到过从网络启动切换到EMMC启动后卡在Starting Kernel的情况。当时第一反应是内核镜像损坏但实际排查后发现是Uboot的环境变量中bootargs没有正确配置EMMC相关的参数。这种问题特别具有迷惑性因为Uboot本身能正常启动容易让人误以为Uboot没问题。2. Uboot被忽视的幕后黑手很多人觉得Uboot只要能启动就说明它没问题这种想法其实是个误区。Uboot在启动内核时要做很多准备工作任何一个细节出错都可能导致后续失败。根据我的踩坑经验Uboot方面需要重点检查以下内容2.1 启动介质配置当切换启动方式比如从网络启动改为EMMC启动时最容易忽略的就是Uboot的环境变量。以下是一个典型的EMMC启动配置示例setenv bootargs consolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw setenv bootcmd mmc dev 1; ext4load mmc 1:1 0x80800000 zImage; ext4load mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb; bootz 0x80800000 - 0x83000000 saveenv我曾经遇到过一个经典案例开发板从网络启动切换回EMMC启动后卡在Starting Kernel。排查后发现是因为Uboot的bootcmd仍然指向网络加载而bootargs却配置成了EMMC参数导致内核拿到的是矛盾的启动参数。2.2 内存加载地址内核镜像和设备树的加载地址必须严格匹配硬件设计。以i.MX6ULL为例zImage通常加载到0x80800000设备树加载到0x83000000如果地址设置错误可能会出现以下症状完全黑屏地址冲突导致数据损坏内核panic错误地址导致代码执行异常卡在Starting Kernel最常见我曾经帮同事排查过一个诡异问题他的板子在QSPI Flash启动正常但切换到SD卡就卡在Starting Kernel。最后发现是Uboot的include/configs/mx6ullevk.h文件中定义的加载地址与SD卡控制器存在冲突。3. 设备树硬件描述的密码本设备树文件.dtb就像是给内核的硬件配置说明书。一个常见的误区是认为同样的板子就应该用同样的设备树实际上即使是同一型号的开发板不同批次也可能有硬件差异。3.1 设备树匹配检查首先确认使用的设备树文件是否真的匹配你的硬件。我曾经遇到过这样的情况开发板型号i.MX6ULL EVK实际硬件版本Rev B使用的设备树imx6ull-14x14-evk.dtb对应Rev A结果就是卡在Starting Kernel因为Rev B更换了PMIC芯片而旧设备树没有相应配置。正确的做法是检查开发板丝印使用匹配的设备树文件。3.2 设备树关键节点以下设备树节点最容易导致启动失败usdhc2 { /* EMMC */ pinctrl-names default; pinctrl-0 pinctrl_usdhc2; bus-width 8; non-removable; status okay; }; iomuxc { pinctrl_usdhc2: usdhc2grp { fsl,pins MX6UL_PAD_NAND_RE_B__USDHC2_CLK 0x10069 MX6UL_PAD_NAND_WE_B__USDHC2_CMD 0x17059 /* 省略其他引脚配置 */ ; }; };如果EMMC控制器配置错误内核在初始化存储设备时就会卡住。建议的检查步骤确认compatible字段与SoC型号匹配检查pinctrl配置是否正确验证时钟和电源配置4. 内核镜像看似简单实则暗藏玄机很多人觉得内核镜像只要编译通过就没问题其实编译选项和版本匹配同样重要。4.1 内核配置检查确保内核配置中包含必要的驱动支持# 检查EMMC驱动是否编译 zgrep MMC /proc/config.gz CONFIG_MMCy CONFIG_MMC_SDHCIy CONFIG_MMC_SDHCI_ESDHC_IMXy # 检查文件系统支持 CONFIG_EXT4_FSy CONFIG_VFAT_FSy我曾经遇到过一个典型问题内核配置中启用了设备树支持CONFIG_OFy但实际使用的是非设备树的内核镜像导致卡在Starting Kernel。这种问题在新老版本交替时特别常见。4.2 内核版本兼容性Uboot和内核版本存在兼容性要求。一般来说较新的Uboot可以启动较旧的内核较旧的Uboot可能无法启动新内核特别是设备树相关功能建议的版本匹配策略使用芯片厂商提供的BSP版本组合如需升级先升级Uboot再升级内核避免混用不同来源的组件5. 实战排查指南当遇到Starting Kernel卡住时可以按照以下步骤系统排查5.1 基础检查清单确认Uboot版本和编译日期 version U-Boot 2020.04 (Jun 12 2022 - 15:30:25 0800)检查内核加载是否完整 iminfo 0x80800000 ## Checking Image at 80800000 ... Legacy image found Image Name: Linux-4.19.35 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 3846216 Bytes 3.7 MiB Load Address: 80008000 Entry Point: 80008000验证设备树加载 fdt addr 0x83000000 fdt print / chosen chosen { stdout-path serial0:115200n8; linux,initrd-start 0x83800000; };5.2 高级调试技巧如果基础检查没问题可以尝试启用Uboot的调试输出 setenv bootargs earlycon consolettymxc0,115200 debug saveenv检查内存映射 md 0x80800000 0x10 80800000: 56190527 00000000 60183b1a 00000000 ...V...;.....尝试最小化启动setenv bootargs consolettymxc0,115200 init/bin/sh记得有一次我遇到Starting Kernel卡住最后发现是DDR初始化参数不对。通过在Uboot中手动调整DDR配置后问题解决 mw 0x021b001c 0x00008000 mw 0x021b0404 0x0000000f6. 预防胜于治疗最佳实践建议根据我的踩坑经验遵循以下原则可以避免90%的Starting Kernel问题版本控制三件套为每个项目维护明确的Uboot、内核、设备树版本对应表变更记录任何启动方式或配置变更都要记录方便回滚排查分步验证先验证官方镜像能否启动然后逐个替换自定义组件每次修改只变更一个变量自动化构建使用脚本确保每次构建的环境一致#!/bin/bash make clean make imx_v7_defconfig make menuconfig make -j8最近我在一个新项目上就严格执行了这套流程当出现Starting Kernel卡住时通过对比构建记录快速定位到是某个内核配置选项被意外修改导致的这种系统化的方法比盲目试错效率高得多。