BootROM(引导只读存储器)是SoC芯片启动时最先执行的固化代码,由芯片厂商预先烧录,不可修改。它的核心任务是完成最基础的硬件初始化,并加载下一阶段引导程序(如SPL/U-Boot)。以下是其工作流程:
上电复位
│
├─ 锁存Boot Mode引脚
│
├─ 初始化时钟/PLL
│
├─ 初始化SRAM/内存控制器
│
├─ 检测启动设备(SD/eMMC/NAND)
│
├─ 加载SPL/U-Boot到SRAM或DDR
│
└─ 跳转到SPL/U-Boot
1、 SoC上电复位(Power-On Reset, POR)
- 触发条件:芯片通电或复位信号(Reset Pin)触发。
- 硬件行为:
- CPU从固定地址(如ARMv7的
0x00000000
)取第一条指令,执行BootROM代码。 - 所有寄存器和内存被重置为默认状态。
- CPU从固定地址(如ARMv7的
- 关键任务:
- 锁存Boot Mode引脚(决定从哪种存储设备启动,如SD卡、eMMC、NOR Flash等)。
2、 BootROM执行阶段
(1)最小硬件初始化
- 时钟初始化:
- 配置PLL(锁相环),生成CPU、总线和外设的时钟信号。
- 例如,i.MX6ULL的BootROM会初始化ARM内核时钟至396MHz。
- 内存控制器初始化:
- 初始化片内SRAM(如OCRAM),作为临时运行空间。
- 若支持XIP(Execute In Place),则映射NOR Flash到内存地址空间。
- 基础外设使能:
- 初始化调试串口(UART),用于输出启动日志(可选)。
- 关闭MMU和Cache,确保直接访问物理内存。
为什么需要执行最小硬件初始化?
(1)SoC上电时硬件处于未知状态:
CPU、外设、存储控制器等硬件模块的寄存器值不确定,必须初始化后才能使用。例如,CPU需要正确的时钟信号才能运行,内存控制器(如DDR)必须配置时序参数才能访问RAM。
(2)依赖严格的初始化顺序:
某些硬件模块必须按特定顺序初始化,例如:
- 先配置PLL(锁相环),生成稳定的CPU和总线时钟。
- 再初始化内存控制器,否则CPU无法访问RAM。
- 最后使能Cache和MMU,提高执行效率。
如果没有这一步:CPU可能运行在错误的时钟频率,内存无法访问,导致死机或无法加载后续代码。
(2)检测启动设备
- 读取Boot Mode引脚:
- 根据硬件引脚电平(如BOOT_CFG[1:0])确定启动介质(SD卡、eMMC、NAND Flash等)。
- 初始化存储控制器:
- 例如,从SD卡启动时,需初始化MMC控制器;从SPI Flash启动时,需配置SPI接口。
为什么需要检测启动设备
(1)BootROM代码存储在芯片内部ROM,后续程序(如U-Boot)通常存放在外部存储:
- 片上ROM空间有限,无法存放完整的Bootloader(如U-Boot可能几百KB)。
- SoC通常支持多种启动方式(如SD卡、eMMC、NAND Flash),具体由硬件引脚(Boot Mode)决定。
- BootROM需要检测这些引脚,并初始化对应的存储控制器(如MMC/SD控制器、SPI控制器)。
(3)加载下一阶段代码(SPL/U-Boot)
- 从存储设备读取数据:
- 从SD卡、eMMC等设备的固定偏移量(如SD卡的第1个扇区)读取SPL或U-Boot镜像。
- 校验完整性(可选):
- 若启用安全启动(Secure Boot),校验镜像的数字签名。
- 加载到运行地址:
- SPL通常被加载到片内SRAM(如i.MX6ULL的
0x00900000
)。 - U-Boot主阶段需加载到DDR(如
0x87800000
),但需先初始化DDR。
- SPL通常被加载到片内SRAM(如i.MX6ULL的
为什么需要加载下一阶段代码(SPL/U-Boot)
BootROM通常只做最基本的硬件初始化,而完整的Bootloader(如U-Boot)需要:
- 初始化更多外设(网卡、USB、显示等)。
- 加载操作系统内核(如Linux)。
- 提供交互式命令行(如U-Boot的
bootcmd
)
IMX6ULL的BOOTROM程序会根据解析出来的链接起始地址在一开始就把整个Uboot源码读取到DDR中去,也就是说Uboot的第一行代码就运行在DDR中,这是不同于三星的传统Uboot的,传统Uboot的第一句代码是运行在片内SRAM上的。
(4)跳转到下一阶段
- 通过汇编指令直接跳转到SPL/U-Boot的入口地址