U-Boot 2026.07 启动流程深度解析从Boot ROM到内核移交的7个关键阶段1. 启动模式选择与Boot ROM初始化在ARM Cortex-A系列处理器如i.MX6U中系统上电后的第一指令执行位置由BOOT_MODE引脚决定。这两个引脚的不同组合将引导芯片进入四种工作模式之一BOOT_MODE[1:0]模式类型行为描述00内部Boot模式从芯片内部Boot ROM启动通常用于生产环境01串行下载模式通过USB或UART接口下载固件常用于开发调试10保留模式具体行为依芯片型号而定11外部启动模式从外部存储器(NAND/NOR Flash, eMMC等)加载二级引导程序当BOOT_MODE1为1且BOOT_MODE0为0时芯片进入内部Boot模式此时处理器会执行固化在芯片内部的Boot ROM代码。这段代码主要完成以下关键操作/* Boot ROM代码片段示例 */ reset: /* 关闭MMU和缓存 */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002000 清除CR_Z位(禁用分支预测) bic r0, r0, #0x00000005 清除CR_M和CR_C位(禁用MMU和缓存) mcr p15, 0, r0, c1, c0, 0 /* 设置异常向量表基地址 */ ldr r0, 0x00000000 mcr p15, 0, r0, c12, c0, 0 设置VBAR /* 初始化关键时钟和PLL */ bl clock_init /* 检测启动设备 */ bl detect_boot_deviceBoot ROM在执行过程中会读取芯片的fuse配置或GPIO状态确定从哪个存储设备加载U-Boot等二级引导程序。常见的启动设备检测顺序通常为eMMC boot分区SD卡第1分区SPI NOR FlashNAND Flash网络启动(TFTP)提示i.MX6U处理器的Boot ROM会检查存储设备前1KB数据中的IVTImage Vector Table该数据结构包含程序入口点、DCDDevice Configuration Data等信息是U-Boot能被正确加载的关键。2. 设备初始化与DCD解析当Boot ROM从存储设备加载U-Boot镜像时首先遇到的是IVT数据结构其典型布局如下偏移量字段名描述0x00头标志(0x402000D1)标识有效的IVT结构0x04入口点地址U-Boot的起始执行地址0x08保留字段必须为00x0CDCD地址设备配置数据的存储位置0x10Boot数据地址启动相关信息0x14IVT自身地址用于校验0x18CSF地址安全启动相关(可选)DCDDevice Configuration Data是U-Boot镜像中的重要组成部分包含了对处理器内部外设的初始化配置。一个典型的DCD配置可能包含以下内容/* DCD数据示例配置DDR3控制器 */ struct dcd_entry { uint32_t addr; // 寄存器地址 uint32_t val; // 配置值 } dcd_table[] { {0x020e0798, 0x000C0000}, // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 {0x020e0758, 0x00000030}, // IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS {0x020e0588, 0x00000030}, // IOMUXC_SW_PAD_CTL_PAD_DRAM_RESET {0x021b001c, 0x00008000}, // MMDC0_MDSCR, 配置请求 {0x021b0800, 0xA1390003}, // DDR3配置8banks行地址15 // ... 更多DDR配置项 };DCD的解析和执行由Boot ROM完成主要初始化以下硬件模块时钟系统配置ARM核心、AHB总线、外设时钟DDR控制器设置时序参数、内存大小和映射IOMUX控制器配置引脚复用功能和电气特性基本外设初始化串口、GPIO等调试必需的外设注意DCD配置必须与具体硬件设计严格匹配特别是DDR参数错误的配置会导致后续U-Boot运行不稳定或完全无法启动。3. 低级硬件初始化阶段当Boot ROM完成DCD配置并将控制权转交给U-Boot后U-Boot首先执行的是汇编语言编写的低级初始化代码通常位于arch/arm/cpu/armv7/start.S。这个阶段的主要任务包括设置处理器模式/* 设置处理器为SVC模式 */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0初始化栈指针/* 设置初始栈指针到内部SRAM */ ldr sp, CONFIG_SYS_INIT_SP_ADDR关闭MMU和缓存/* 确保MMU和缓存关闭 */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002000 清除CR_Z位(禁用分支预测) bic r0, r0, #0x00000005 清除CR_M和CR_C位(禁用MMU和缓存) mcr p15, 0, r0, c1, c0, 0重定位U-Boot到RAM/* 检查当前运行位置是否需要重定位 */ ldr r0, _start ldr r1, CONFIG_SYS_TEXT_BASE cmp r0, r1 beq after_copy /* 执行重定位 */ ldr r2, _end sub r2, r2, r0 bl memcpy跳转到C语言环境/* 设置栈指针并跳转到board_init_f */ ldr sp, CONFIG_SYS_INIT_SP_ADDR b board_init_f这个阶段的关键寄存器状态变化如下表所示寄存器/内存区域初始状态初始化后状态CPSR (处理器状态寄存器)可能为安全监控模式SVC模式禁用中断SP (栈指针)未定义指向内部SRAM末端MMU控制寄存器(CP15)可能启用完全禁用异常向量表可能未设置设置为U-Boot内部实现4. 板级初始化和内存控制器配置board_init_f是U-Boot执行的第一个C语言函数它负责初始化基本的板级硬件并准备重定位环境。主要执行流程包括初始化关键外设void board_init_f(ulong boot_flags) { /* 初始化调试串口 */ serial_init(); console_init_f(); /* 打印U-Boot版本信息 */ puts(\nU-Boot PLAIN_VERSION ( U_BOOT_DATE - U_BOOT_TIME U_BOOT_TZ )\n); /* 初始化DRAM控制器 */ dram_init(); }配置完整的内存映射/* 典型的内存布局配置 */ gd-ram_size 0x20000000; // 512MB gd-ram_top 0x80000000 gd-ram_size; gd-relocaddr gd-ram_top - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_STACK_SIZE - sizeof(bd_t);重定位U-Boot到最终位置/* 计算重定位偏移 */ gd-reloc_off gd-relocaddr - CONFIG_SYS_TEXT_BASE; /* 执行实际的重定位 */ memcpy((void *)gd-relocaddr, (void *)CONFIG_SYS_TEXT_BASE, CONFIG_SYS_MONITOR_LEN); /* 更新全局数据结构指针 */ gd-flags | GD_FLG_RELOC;跳转到重定位后的代码/* 通过函数指针跳转避免直接地址引用 */ void (*relocated_board_init_r)(void) (void *)gd-relocaddr (board_init_r - CONFIG_SYS_TEXT_BASE); relocated_board_init_r();在内存初始化过程中U-Boot需要根据具体硬件配置DDR控制器参数。以下是i.MX6ULL处理器的典型DDR3配置参数struct mx6_ddr3_cfg { /* DDR控制器寄存器配置 */ uint32_t mstr; /* 内存控制器特性 */ uint32_t rfshtmg; /* 刷新时序 */ uint32_t init1; /* 初始化序列控制1 */ uint32_t init0; /* 初始化序列控制0 */ uint32_t init3; /* 初始化序列控制3 */ uint32_t init4; /* 初始化序列控制4 */ uint32_t init5; /* 初始化序列控制5 */ /* ... 更多时序参数 */ }; static struct mx6_ddr3_cfg ddr3_2gb { .mstr 0x00040800, .rfshtmg 0x00400046, .init1 0x00690000, .init0 0x00020083, .init3 0x00140000, .init4 0x00000001, .init5 0x00000000, /* ... */ };提示现代U-Boot支持通过设备树(DTS)配置内存参数相比硬编码方式更加灵活。开发时应优先使用设备树描述内存配置。5. 驱动初始化和环境准备board_init_r是U-Boot主循环的入口在这个阶段所有必要的驱动和设备都已初始化完毕。主要执行流程包括初始化各子系统void board_init_r(void) { /* 初始化计时器 */ timer_init(); /* 初始化环境变量 */ env_init(); /* 初始化串口控制台 */ stdio_init(); /* 初始化网络子系统 */ eth_initialize(); /* 初始化存储设备 */ mmc_initialize(NULL); }加载环境变量 U-Boot环境变量存储位置通常有以下几种选择NOR Flash直接存储在Flash的特定扇区NAND Flash存储在OOB区域或特定块eMMC/SD存储在保留分区或特定文件EEPROM通过I2C或SPI接口访问设备树(DTB)处理 现代U-Boot使用设备树描述硬件配置处理流程如下/* 设备树处理流程 */ void fdtdec_setup(void) { /* 1. 获取设备树地址 */ void *fdt_blob board_fdt_blob_setup(); /* 2. 验证设备树有效性 */ if (fdt_check_header(fdt_blob) ! 0) { printf(Invalid device tree blob\n); hang(); } /* 3. 应用运行时修改 */ fdtdec_process_fdt_blob(fdt_blob); }命令表初始化 U-Boot通过命令表提供丰富的调试和管理功能命令注册示例/* 命令注册示例 */ U_BOOT_CMD( mmcinfo, 1, 0, do_mmcinfo, display MMC info, [dev]\n - display info for the specified or current MMC device );常用U-Boot命令及其功能对比如下命令类别示例命令功能描述信息查询bdinfo显示板级信息mmcinfo显示MMC设备信息内存操作md显示内存内容mw写入内存存储设备mmc read从MMC设备读取数据nand erase擦除NAND Flash环境变量printenv打印环境变量setenv设置环境变量启动相关bootm启动内核镜像bootz启动zImage格式内核6. 内核加载与设备树处理当U-Boot准备启动Linux内核时需要完成以下关键步骤加载内核镜像# 从TFTP服务器加载内核 tftp 0x80800000 zImage # 从eMMC加载内核 mmc dev 1 mmc read 0x80800000 0x800 0x2000加载设备树 blob# 加载设备树文件 tftp 0x83000000 imx6ull-14x14-evk.dtb设置启动参数# 设置内核命令行参数 setenv bootargs consolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw启动内核# 启动zImage格式内核 bootz 0x80800000 - 0x83000000 # 启动uImage格式内核 bootm 0x80800000 - 0x83000000内核启动过程中U-Boot与Linux内核的交互主要通过以下数据结构ATAGs (ARM传统方式)已逐渐被设备树取代设备树Blob包含完整的硬件描述信息命令行参数通过bootargs环境变量传递设备树在内存中的典型布局如下--------------------- | 设备树头 (fdt_header) | --------------------- | 内存保留映射区 | --------------------- | 设备树结构区 | --------------------- | 设备树字符串区 | ---------------------U-Boot在传递设备树给内核前通常会执行以下修改操作内存节点更新根据实际检测到的内存大小更新/memory节点命令行参数注入将bootargs环境变量写入/chosen节点硬件特定修改根据运行时的硬件状态更新相应属性7. 控制权移交与内核启动U-Boot最终通过bootm或bootz命令将控制权移交给Linux内核这一过程涉及以下关键操作内核解压与重定位对于zImage格式U-Boot可能需要进行解压确保内核镜像位于正确的内存位置如ARM架构通常要求zImage在低16MB内存设置启动参数/* 典型的内核启动参数设置 */ void setup_start_tag(bd_t *bd) { params (struct tag *)bd-bi_boot_params; params-hdr.tag ATAG_CORE; params-hdr.size tag_size(tag_core); params-u.core.flags 0; params-u.core.pagesize 0; params-u.core.rootdev 0; params tag_next(params); }架构特定准备/* ARM架构的内核启动前准备 */ kernel_entry: /* 关闭中断 */ mrs r0, cpsr orr r0, r0, #0xC0 msr cpsr, r0 /* 设置机器类型ID */ mov r0, #0 ldr r1, 0xFFFFFFFF /* 设备树地址 */ ldr r2, 0x28000000 /* 内核参数地址 */ /* 跳转到内核入口 */ mov pc, r4安全状态切换对于支持ARM TrustZone的芯片U-Boot需要确保内核在正确的安全状态下启动可能涉及安全监控调用(SMC)以切换世界状态内核启动后U-Boot的使命基本完成但现代U-Boot还支持以下高级功能FIT镜像支持允许单个镜像文件包含内核、设备树和ramdisk安全启动通过HAB或CAAM模块验证镜像签名快启功能保留部分初始化结果加速后续启动过程在实际调试过程中开发者可以通过以下命令检查启动问题# 检查内存配置 md 0x80000000 10 # 验证设备树内容 fdt addr 0x83000000 fdt print /memory # 测试存储设备访问 mmc dev 1 mmc read 0x82000000 0 1 md 0x82000000 10