为什么 i.MX6ULL 需要两级 BootLoader,而 STM32 只需要一级?
2026/9/15 7:20:35 网站建设 项目流程

目录

一、芯片工艺问题:无法集成大容量 Flash ——> 下游厂商获得 Flash 选择权

二、BootROM的代码是固定的吗?SPL和UBoot 的诞生

三、Uboot 和第一级 BootLoader 做了啥?最简硬件配置 + 拷贝操作系统

四、 为什么操作系统不能信任Uboot的配置,还要重新按 dtb 配置硬件?


本文背景是在了解STM32的BootLoader时,发现流程不一定会走到掩膜内部的BootLoader产生了疑问,于是回忆了i.MX6uLL的UBoot相关流程,梳理出以下文章。

虽然本文对于写代码并无本质帮助,但如果你从事Linux驱动、内核裁剪移植等工作,将作为最底层的原理,帮助思考后续问题。

一、芯片工艺问题:无法集成大容量 Flash ——> 下游厂商获得 Flash 选择权

STM32 属于 Cortex‑M 系列的 MCU,大多采用 90nm、110nm 这类成熟流片工艺来控制成本。成熟工艺可以低成本将 NOR‑Flash、CPU 内核以及各类外设控制器集成在同一块硅片上。虽然老工艺 CPU 主频上限不高,但完全可以满足单片机控制场景的需求。

而 i.MX6ULL 属于 Cortex‑A7 系列的 MPU,为了实现更高 CPU 主频,采用 40nm 先进流片工艺。先进工艺擅长跑高速 CPU 与复杂总线,但很难集成大容量片上 Flash。MPU 运行 Linux 操作系统至少需要几十 MB 的 Flash 存储空间,如果强行在先进工艺芯片内部集成大容量 Flash,芯片成本会大幅上升,失去商用价值。

这就带来一个差异:STM32 芯片内部自带 Flash;而 i.MX6ULL 必须在芯片外部外接 eMMC 这类存储器件。

二、BootROM的代码是固定的吗?SPL和UBoot 的诞生

STM32 的 System‑Memory、i.MX6ULL 的 Mask‑ROM,都属于掩膜 ROM。掩膜 ROM 的代码是芯片厂商在流片之前就预先定义,芯片制造时通过光刻直接固化在硬件内部,出厂之后内容固定,无法擦写、无法重新烧录。

它的核心作用:配合 BOOT 引脚修改启动地址。比如 STM32 中,将 BOOT0 引脚置 1,复位后硬件会把启动地址指向内部 BootROM,进入串口烧录模式,同时完成内部 Flash、串口等少量外设的初始化。

STM32 所有外设、存储器件全部由 ST 原厂选定,BootROM 需要初始化的硬件范围是确定的,所以STM32的掩膜 ROM 内的初始化代码可以写死。

但 i.MX6ULL 的 DDR、eMMC 全部由下游板卡厂商自主选型(比如野火、正点原子的开发板)。不同板卡 DDR 的电压、时序参数各不相同,NXP 不可能把市面上全部外设的驱动参数全部预置到 Mask‑ROM 内部。

于是 NXP 采用这样的方案:Mask‑ROM 依旧保持固化,但是它不再负责完整的板级硬件初始化。它仅完成基础介质读取,把SPL(U‑Boot 第一阶段)加载到芯片内部 OCRAM中运行;(ON-Chip RAM,这个是i.MX6ULL内部的RAM,Mask-ROM自带极简的EMMC/SD驱动控制,即被固化在掩膜中的,可以将市面上大多数EMMC/SD都做最简初始化。所以i.MX才能从存储器读取代码,并放到自己的RAM中运行)所以DDR、eMMC 等其余硬件初始化工作,全部交给 SPL 以及后续完整 U‑Boot 完成。

这套 U‑Boot 由下游厂商针对自己的开发板修改,内部包含完整的硬件初始化代码,适配当前板卡上 DDR、eMMC 等硬件的时序、电气参数。

补充说明:行业口语常说 i.MX6ULL 是两级 BootLoader,完整硬件执行链路实际分为三段:

  1. Mask‑ROM(芯片固化,第一级,不可修改):读取外部介质,加载 SPL 到片上 OCRAM,不会初始化 DDR
  2. SPL(U‑Boot 第一阶段,可修改的 BootLoader):运行在 OCRAM,完成 DDR 初始化
  3. 完整 U‑Boot:DDR 中运行,初始化 eMMC 等外设,加载 Linux 内核

而STM32 启动链路:

  1. System‑Memory (BootROM):提供下载启动模式
  2. 直接运行片上 Flash 的用户程序,不需要外部 DRAM(内部的小RAM已经够用了,且这个初始化是由ST完成的;同时片上 NOR Flash 支持 XIP 原地执行代码,根本就不需要外接RAM),无需二级 BootLoader 用以适配。

三、Uboot 和第一级 BootLoader 做了啥?最简硬件配置 + 拷贝操作系统

注意:这里所有硬件配置,仅仅是保障当前代码(SPL/U‑Boot)能够运行的最低配置,不等于 Linux 操作系统最终运行的硬件环境。

完整 U‑Boot 必须运行在 DDR 内存中,这里会出现死锁矛盾:DDR 没有初始化就无法运行 U‑Boot,但是初始化 DDR 又需要执行代码。解决死锁的就是 SPL:SPL 体积很小,可以运行在芯片自带 OCRAM(片上 RAM,不需要 DDR),SPL 负责完成 DDR 的初始化;DDR 就绪之后,再把完整版 U‑Boot 拷贝到 DDR 内运行。

之后 DDR 中运行的完整 U‑Boot,会重新对 DDR、其余板载硬件做一次完整初始化,让 DDR 时序、电压完全匹配当前板卡硬件,发挥硬件全部性能。 最后 U‑Boot 把 Linux 内核镜像、dtb 设备树拷贝到 DDR 内存,把系统执行权交给 Linux 操作系统。

四、 为什么操作系统不能信任Uboot的配置,还要重新按 dtb 配置硬件?

在刚刚的描述中,我们会引出一个问题:为什么 U‑Boot 需要把 dtb 也拷贝进来,直接让操作系统自己读取 dtb 不行吗?

这里会遇到鸡生蛋、蛋生鸡的困境:Linux 刚启动的阶段,存储控制器还没有完成初始化,此时还无法正常读写 eMMC。 如果 dtb 存放在 eMMC 上,内核就没办法拿到设备树配置信息。

所以由已经完成 eMMC 初始化的 U‑Boot,提前把 dtb 读取拷贝到 DDR 内存中,并且向 Linux 内核传递 dtb 在内存中的物理地址。内核启动之后直接访问内存,就可以拿到这份硬件配置手册。

为什么Linux不能信任Uboot呢?

  • U-Boot:极简配置,只满足启动、读存储、串口打印这几个最小需求。只保证 “能读 eMMC、能打印 log”,不做复杂配置,很多外设只开最低功能。
  • Linux 内核:完整驱动,要管理时钟、电源、DMA、中断、缓存、总线、功耗管理。内核不信任 U-Boot 的简陋配置,认为硬件状态是未知、不可靠的

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询