
目录一、芯片工艺问题无法集成大容量 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 依旧保持固化但是它不再负责完整的板级硬件初始化。它仅完成基础介质读取把SPLU‑Boot 第一阶段加载到芯片内部 OCRAM中运行ON-Chip RAM这个是i.MX6ULL内部的RAMMask-ROM自带极简的EMMC/SD驱动控制即被固化在掩膜中的可以将市面上大多数EMMC/SD都做最简初始化。所以i.MX才能从存储器读取代码并放到自己的RAM中运行所以DDR、eMMC 等其余硬件初始化工作全部交给 SPL 以及后续完整 U‑Boot 完成。这套 U‑Boot 由下游厂商针对自己的开发板修改内部包含完整的硬件初始化代码适配当前板卡上 DDR、eMMC 等硬件的时序、电气参数。补充说明行业口语常说 i.MX6ULL 是两级 BootLoader完整硬件执行链路实际分为三段Mask‑ROM芯片固化第一级不可修改读取外部介质加载 SPL 到片上 OCRAM不会初始化 DDRSPLU‑Boot 第一阶段可修改的 BootLoader运行在 OCRAM完成 DDR 初始化完整 U‑BootDDR 中运行初始化 eMMC 等外设加载 Linux 内核而STM32 启动链路System‑Memory (BootROM)提供下载启动模式直接运行片上 Flash 的用户程序不需要外部 DRAM内部的小RAM已经够用了且这个初始化是由ST完成的同时片上 NOR Flash 支持 XIP 原地执行代码根本就不需要外接RAM无需二级 BootLoader 用以适配。三、Uboot 和第一级 BootLoader 做了啥最简硬件配置 拷贝操作系统注意这里所有硬件配置仅仅是保障当前代码SPL/U‑Boot能够运行的最低配置不等于 Linux 操作系统最终运行的硬件环境。完整 U‑Boot 必须运行在 DDR 内存中这里会出现死锁矛盾DDR 没有初始化就无法运行 U‑Boot但是初始化 DDR 又需要执行代码。解决死锁的就是 SPLSPL 体积很小可以运行在芯片自带 OCRAM片上 RAM不需要 DDRSPL 负责完成 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 的简陋配置认为硬件状态是未知、不可靠的。