一、BootROM

1.1 基础概念
BootROM(Boot Read-Only Memory)是芯片出厂前固化在硬件内部的只读存储器,存储着芯片级的最小引导程序。它并非独立的"板级组件",而是集成于CPU、MCU或SoC内部的硬件单元,是嵌入式系统上电后第一个被激活的程序载体,承载着"启动初始化"与"引导接力"的核心使命。
在一个典型的 MCU(Microcontroller)中,BootROM 指的是固化在芯片内部且一般不可修改的启动代码以及其对应的硬件区域。它通常存储在不可擦写或仅可一次性编程的物理介质上,如:Mask ROM 或 eFuse/OTP(One-Time Programmable)区域。当系统上电或复位时,CPU 的程序计数器(PC)被硬件指向 BootROM 所在的地址(可能是0x0),开始执行其中的指令。
1.2 特性
BootROM的特性由其"先天定位"决定,核心可概括为"固化性、极简性、硬件关联性"三大特征,具体如下:
物理固化,不可修改:BootROM的程序由芯片厂商在生产阶段通过光刻等工艺写入,出厂后无法通过软件手段擦除或修改。这种特性确保了启动的"根信任"------即使外部存储介质(如eMMC、QSPI)数据损坏,BootROM仍能稳定执行初始逻辑,为故障排查提供基础。
执行方式固定,依赖XIP:由于BootROM本身是只读存储器,其内部程序采用"XIP(Execute In Place,就地执行)"方式运行,无需加载到RAM中。这一特性使其在系统上电初期、RAM未初始化的场景下,能直接启动执行。
资源极致精简:BootROM的存储容量通常极小(从几十KB到几百KB不等,如NXP IMX6ULL的Boot ROM约64KB,STM32的System Memory约32KB),程序逻辑仅保留"最小必要功能",避免冗余代码占用空间。
与硬件强绑定:BootROM的功能设计完全匹配芯片的硬件架构,例如针对特定型号的存储控制器(eMMC/QSPI/NAND)、时钟模块进行适配,不同厂商、不同系列的芯片,其BootROM的逻辑与接口均存在差异。
1.3 典型芯片BootROM实例对比
不同厂商的芯片BootROM在细节上存在差异,以下两个主流芯片的实例可直观体现其特性:
(1)NXP IMX6ULL:其Boot ROM被称为"i.MX Boot ROM",支持多种启动介质(eMMC、QSPI、SD卡、USB),启动顺序可通过BOARD_ID引脚配置。它首先读取存储介质中的"IVT(Image Vector Table,镜像向量表)",通过IVT定位到SPL(二级引导程序)的地址,将SPL加载到片内OCRAM(片上静态RAM)中执行,随后移交控制权。
(2)TI AM335x:其Boot ROM支持"主次启动"机制,主启动介质优先加载引导程序,若失败则自动切换到备用介质(如主介质为eMMC,备用为USB)。它无需单独的SPL,可直接加载完整U-Boot镜像到片内SRAM,但由于SRAM容量限制(约64KB),要求U-Boot镜像的初始阶段必须精简,后续再初始化DRAM并将完整U-Boot搬运到DRAM中运行。
1.4 存储与固化
1.4.1 BootROM 的物理形态
在大多数 ARM SoC 或 MCU 中,BootROM 通常以以下几种形式存在于芯片内部:
Mask ROM
这是最传统的形式,ROM 在流片制造时就被"刻"入芯片,即代码经过掩膜处理后直接写进硅片。在这种方式下,BootROM 的内容几乎不可更改,厂商若想修复问题,通常只能在后续的引导程序(SPL / U-Boot 等)中做兼容或"打补丁"。
eFuse / OTP(One-Time Programmable)
某些高端 SoC 会将极少量的关键启动逻辑写在 Mask ROM 中,再将可配置项(如安全密钥、加密参数、极简启动逻辑)存储于 eFuse/OTP 区域。eFuse/OTP 是一类只能烧写一次或写入次数非常有限的非易失性存储。BootROM 上电时会读取这些内容来确定启动策略或安全验证所需的密钥。虽然 eFuse/OTP 具备"可烧写"的特点,但一旦烧写完成,往往不能复原或再次改写,因此也被视作"基本不可变"。
部分新兴设计:Rewrite-able 区域
极少数 SoC(尤其是面向大客户或特殊领域)可能预留一小块可更新的 ROM Patch 区,用以在后期对严重缺陷进行热修复。这类机制通常门槛极高,需要厂商专门的内部工具或签名才可以重新写入。
1.4.2 不可修改性的意义
BootROM 之所以大多采用不可修改或极难修改的方式,主要基于以下考虑:
-
安全性:当 BootROM 负责执行安全启动(Secure Boot)时,它必须是系统中最可信、最不易被篡改的部分。唯有如此,后续签名校验和加密解密流程的安全性才不至于"从根上就失守"。
-
稳定性:如果 BootROM 能随意被软件修改,一旦意外损坏,就可能导致系统彻底无法上电引导;将关键启动逻辑固化,可以大幅提高系统稳健性。
-
简化设计:只有少量逻辑写在最底层 BootROM 中,将更多功能和灵活性留给二级或更高级别的引导程序,这也是主流 SoC 的通用做法。
1.5 初始化任务:硬件基础准备
1.5.1 上电后的时钟与复位控制
当系统刚刚上电,CPU 内部时钟、复位控制电路、I/O 状态等都尚未完全配置到位。此时,BootROM 会进行以下核心操作:
(1)时钟源启用
选择并启用 SoC 内部默认时钟源,或将时钟从低速振荡器切换到更高频率的主时钟。配置必要的 PLL(Phase Locked Loop)以提供给 CPU 或外设更稳定的时钟信号。
(2)复位逻辑清理
停止某些保持在复位状态的模块,解除关键模块的复位锁定,以便后续程序能够访问它们。
(3)最小外设初始化
只有在 BootROM 需要访问外部存储(SD/eMMC/SPI 等)或执行安全密钥校验时,才会初始化对应外设。由于此时可用的代码空间和功能受限,往往只能采用非常精简的驱动逻辑。
1.6 启动模式选择:Boot Pins / eFuse / 配置寄存器
在完成最基本的硬件复位和时钟设置后,BootROM 会读取特定的"启动模式"信息,以决定下一步要从哪些外部存储介质加载二级引导代码。不同芯片的实现细节有差异,但通常包含以下三类配置来源:
| 配置方式 | 编程属性 | 典型用法 | 可改动次数 |
|---|---|---|---|
| Boot Pins | 硬件电平拉高/拉低 | 切换从 eMMC、SPI、NAND、SD 等介质启动 | 随时可变,需重新上电或复位 |
| eFuse / OTP | 一次性或极少数可编程 (不可逆) | 固定安全启动模式、存储密钥或授权信息 | 极难更改或无法复原 |
| 配置寄存器 | 上电后由 BootROM 读取或固化在芯片内部 | 指示调试启动模式(如 USB 下载)、恢复模式等 | 可能只在特定条件下允许修改 |
Boot Pins(硬件引脚):常在主板上用拨码开关或电阻拉高/拉低来配置,适合开发阶段反复测试不同启动源。
eFuse / OTP(一次性编程):适合量产阶段或对安全要求极高的场景,一旦烧写,就很难更改;能确保固定的启动顺序和安全策略。
内部配置寄存器:有些 SoC 在 BootROM 中会先检查内部寄存器(可能由前一阶段烧写或出厂配置),再决定要不要进入 USB DFU、串口下载或其他调试模式。
1.7 全系统启动链概览
1.7.1 多阶段引导的必要性
在现代的 SoC 或 MCU 体系中,启动往往被拆分为若干阶段,每个阶段都有着不同的目标与实现思路。尽管各家芯片厂商的细节实现有所不同,但总体结构大同小异,通常可归纳如下:
-
BootROM:代码位置固化在芯片内部,主要功能为最基本的硬件初始化、识别启动模式、(可选)完成安全验证、加载下一阶段,特点是不可随意修改、体积小、逻辑精简。
-
SPL/Preloader(第二阶段引导):代码位置在外部存储(eMMC、SD、SPI Flash 等),主要功能为初始化更多外设(尤其是 DRAM)、加载主引导程序或更高级别引导程序,特点是功能相对 BootROM 更灵活,可对缺陷做升级或补丁。
-
主引导程序(U-Boot、Barebox 等):代码位置在外部存储,主要功能为完整的系统硬件初始化(网络、存储、显示等),加载操作系统内核,特点是体积更大,可与硬件工程师、软件开发人员深度定制。
-
操作系统内核(Linux、RTOS 等):代码位置在外部存储或网络(在部分场景),主要功能为真正承载应用执行的平台,提供文件系统、进程管理、网络协议栈等,特点是更新与维护频率最高,体量最大。
通过这样多层次的引导架构,系统可以在逐级"解锁"硬件功能的同时,也逐级进行安全验证与环境搭建,最终平稳地进入操作系统层面。
1.7.2 BootROM 如何串联各阶段
BootROM 在这个多阶段引导链条中,扮演的是"发令枪"角色:当系统上电或复位后,CPU 首先读取并执行 BootROM 里的指令------它在短短数十毫秒内,完成以下关键动作:
-
读取启动模式:检查硬件引脚(Boot Pins/Strap Pins)或 eFuse/OTP 中记录的启动模式信息,判断是否需要进入 USB DFU、串口下载等调试模式;如无特殊配置,则进入正常启动模式。
-
访问外部存储:根据模式去访问 eMMC/SD/SPI Flash 等介质,查找并加载 SPL 或预置的二级引导镜像,在此过程中,如果系统开启了安全启动,则会进行简要的签名校验或解密操作。
-
跳转执行:将二级引导镜像拷贝到片内 RAM 或者小容量的外部 DRAM,将 PC(程序计数器)指向二级引导镜像的入口,完成对控制权的移交。
随后,SPL/Preloader 会进一步对 DRAM 等核心外设做更全面的初始化,再把控制权传给主引导程序(如 U-Boot)。这种逐步"向上"的引导方式,确保系统能从最小可行的硬件环境,一步步扩展到支撑 OS 所需的完整环境。
1.8 多阶段引导特性的横向对比
为了更直观地理解各阶段的分工,下表从功能、可修改性、常见开发工具等角度进行对比:
| 阶段 | 主要功能 | 可修改性 | 常见开发工具 / 方法 |
|---|---|---|---|
| BootROM | 上电复位后基础硬件初始化;识别启动模式;加载二级引导 | 固化于 SoC 内,一般不可修改 | 厂商文档查阅、串口日志(少量信息) |
| SPL/Preloader | DRAM 初始化;加载主引导程序或 OS Bootloader | 可通过外部介质重新烧写 | 编译工具链(如 GCC)、板级支持包(BSP) |
| 主引导程序 (U-Boot) | 更全面的硬件初始化;环境变量管理;加载 OS 内核 | 可通过外部介质重新烧写 | U-Boot 源码、编译工具链、串口/网络 TFTP 等 |
| 操作系统内核 | 提供文件系统、进程管理、驱动框架、网络协议栈等 | 可随时升级/更新 | Linux/RTOS 源码、包管理器(apt、opkg 等) |
从表格可知,BootROM 的功能最少,但地位却最为关键;SPL 具备更丰富的硬件操作能力,但依赖于 BootROM 的初始加载;主引导程序功能最全面,可以涵盖网络、存储、显示等外设;OS 内核则是应用执行的最终环境。
1.9 Fallback 策略与问题排查
1.9.1 常见的回退与冗余机制
在产品化过程中,为了提高系统可靠性,厂商或开发者往往会在引导流程中设置备用路径。例如:
-
多重引导尝试:如果从 eMMC 启动失败,则自动转去尝试 SD 卡;若依然失败,则进入 USB DFU 模式以便进一步修复。
-
冗余镜像分区:在外部闪存中保留两个引导分区,若"活动"分区出错,可自动回退到"备用"分区。
这些策略通常由 BootROM 与二级引导程序共同完成:BootROM 检测第一个介质失败后,会尝试下一个介质;或二级引导程序自带分区验证逻辑,一旦发现镜像损坏就切换到备用分区继续启动。
1.9.2 当启动失败时如何定位问题
-
串口调试日志:如果 BootROM 在硬件上实现了简单的日志输出(有些厂商会留一个"调试版 BootROM"或 Debug 功能),可通过串口捕获到启动失败前的状态;若没有 BootROM 日志,则需要看 SPL/U-Boot 在启动早期是否输出任何异常信息。
-
硬件引脚配置检查:确认拨码开关或 Boot Pins 是否符合预期,如果电平拉错,会导致 BootROM 去错误的介质或模式下引导。
-
外部存储检测:eMMC/SD 卡接口或 SPI Flash 的电路焊接、电源稳定性等也要排查,确保 BootROM 可以顺利访问到镜像。
-
安全验证失败:如果系统启用了 Secure Boot,签名或密钥不匹配时,BootROM 或 SPL 都可能进入死循环;此时可检查安全证书或 eFuse 配置。
1.10 BootROM 与安全启动 (Secure Boot)
随着嵌入式设备在金融、医疗、物联网和工业等领域的广泛应用,如何保障系统在上电之后即处于"可信赖状态"变得尤为关键。在前几章中,我们已看到 BootROM 作为系统启动的最底层基石,拥有对启动流程的初步掌控能力。本章将深入探讨 BootROM 在 Secure Boot 机制下的工作流程与相关技术实现细节。毕竟,正如尼采所言,"当你凝视深渊时,深渊也在凝视你",如果最早阶段的可信度无法保证,整个系统的安全也就无从谈起。
1.10.1 Secure Boot 的背景与目标
1.10.1.1 为什么需要 Secure Boot?
-
防止恶意篡改:一旦系统固件被攻击者替换成非法代码,后续任何软件级安全措施(如防火墙、访问控制等)都无法阻止根层的恶意行为。通过在启动最初阶段做签名校验与完整性验证,可以最大限度避免运行不受信任的镜像。
-
保护知识产权:对软件/固件进行加密或签名验证,可有效预防逆向工程或非法拷贝,保护厂商或开发者的核心算法和专有技术。
-
增强信任链 (Chain of Trust):在多级引导体系里,BootROM 通常是整个信任链的起点(Root of Trust)。如果该点被攻破,后续任何可信机制都会形同虚设。只有当从 BootROM 开始就做严格的签名校验,才能为二级引导、主引导程序以及操作系统提供可靠的"信任锚"。
1.10.1.2 BootROM 在 Secure Boot 中的角色
-
公钥或哈希存储:有些芯片会在 eFuse/OTP 中烧录公钥或哈希值,BootROM 在上电时读取这些信息,用以验证外部存储中镜像的签名。一旦写入 eFuse/OTP,即不可逆更改或极其困难,能有效避免密钥被篡改。
-
镜像签名校验:BootROM 通过内置或协处理器的加密硬件,计算二级引导程序的哈希或签名,并与 eFuse/OTP 中的预置数据对比。若验证失败,BootROM 可能会拒绝启动或跳入安全异常流程,防止系统进入不可信状态。
-
Chain of Trust 的第一环:后续 SPL、主引导程序以及操作系统内核均可在其加载时复用类似的签名校验机制,从而形成完整的多级安全启动链。
1.10.2 安全启动流程示例
下表从无安全引导与安全引导两个角度,简要对比了 BootROM 在启动流程中做的不同工作:
| 对比项 | 无安全引导 | 安全引导 |
|---|---|---|
| 密钥存储 | 无需固定密钥 | eFuse/OTP 中预置公钥或哈希,不可逆更改 |
| 校验流程 | 无校验,直接加载二级引导 | BootROM 对外部镜像做签名校验;失败则拒绝启动或报错 |
| 启动后风险 | 可能运行被篡改或恶意镜像 | 可确保镜像的完整性与来源可信 |
| 物料成本 & 复杂度 | 相对较低 | 需要加密硬件、eFuse/OTP 存储区,研发和量产流程更复杂 |
从中可看出,如果系统并不要求很高的安全性或对成本非常敏感,厂商可能会省略 Secure Boot 的配置。但对金融终端、汽车电子、智能安防等行业而言,Secure Boot 几乎成为必选项。
1.10.3 常见实现策略
1.10.3.1 PKI (Public Key Infrastructure) 模式
原理:在安全环境中生成一对公私钥,公钥烧录进 eFuse/OTP,私钥由厂商安全保管。每次量产或升级固件时,用私钥对镜像进行签名,BootROM 上电后用公钥校验。优点:广泛应用,灵活性高,可用成熟算法(RSA/ECC 等)。缺点:私钥泄露风险需重点防控,烧录公钥也需严格验证。
1.10.3.2 对称加密结合校验哈希
原理:预先在 eFuse/OTP 中存储对称密钥 (如 AES Key) 或镜像哈希;BootROM 读取该密钥,用硬件加速模块对外部镜像进行解密或哈希比对。优点:计算速度通常快于非对称算法,硬件实现成本较低。缺点:对称密钥管理难度大,一旦泄露便失去安全性。
1.10.3.3 混合模式
原理:结合非对称加密 (签名) 与对称加密 (快速解密),利用非对称签名确保镜像来自合法私钥拥有者,对称加密加速镜像的加解密过程。优点:兼具安全性与性能。缺点:实现较复杂,对 BootROM 与安全协处理器要求更高。
1.10.4 潜在漏洞与防护
即便有了 Secure Boot,也可能存在以下潜在隐患:
-
BootROM Bug:如果 BootROM 的校验逻辑本身存在漏洞或缓冲区溢出,攻击者可能利用该漏洞绕过验证。由于 BootROM 通常无法升级,这种问题相当棘手。常见应对方式是通过后续阶段(SPL/U-Boot)增加"二次校验补丁",或在硬件设计中启用 Fallback 机制。
-
密钥泄露:eFuse/OTP 硬件通常相对安全,但仍需谨慎考虑侧信道攻击、芯片逆向等高级攻防手段。量产阶段的管理流程必须严格管控私钥,必要时可设置分级签名策略。
-
篡改 Boot Pins:如果硬件上 Boot Pins 允许切换到无安全启动模式,攻击者可能篡改引脚电平以禁用签名校验或加载不可信代码。解决方案是将启动模式锁定在 eFuse/OTP 或使用防拆卸设计,降低引脚篡改风险。
二、Linux开发板的上电启动流程
Linux开发板的上电启动是一个"逐级引导、功能递进"的过程,每一级程序都在前一级的基础上完成更复杂的硬件初始化,最终实现操作系统的启动。结合主流开发板的设计(以包含SPL的U-Boot引导为例),完整流程可分为5个核心阶段:硬件复位→BootROM执行→SPL执行→U-Boot主程序执行→Linux系统启动。
2.1 阶段1:硬件复位(上电瞬间)
当开发板接入电源后,电源管理芯片(PMIC)首先完成电压校准,向CPU发送"复位信号(RESET)"。CPU接收到复位信号后,内部所有寄存器恢复默认值,程序计数器(PC)被强制设置为BootROM的起始地址(如0x00000000,由芯片架构定义)。此时,DRAM、外设等均处于未初始化状态,仅芯片核心与BootROM处于激活状态,为后续启动做好硬件准备。
2.2 阶段2:BootROM执行(启动第一级)
这一阶段完全由芯片内置的BootROM主导,流程与前文分析一致,核心是"加载下一级引导程序",具体步骤如下:
-
执行芯片核心自检,确认CPU内核、时钟模块正常;
-
初始化eMMC/QSPI控制器(根据预设启动介质);
-
读取启动介质中的IVT,定位SPL镜像地址;
-
将SPL镜像(通常几KB到几十KB)加载到片内SRAM;
-
验证SPL镜像完整性(如校验和验证),通过后跳转到SPL入口地址。
此阶段的关键限制是"无法使用DRAM",因此加载的SPL必须是精简版引导程序,体积不能超过片内SRAM的容量(通常为128KB或256KB)。
2.3 阶段3:SPL执行(过渡引导层)
SPL(Secondary Program Loader,二级引导程序)是U-Boot项目的组成部分,是为解决"BootROM无法初始化DRAM"而设计的过渡层。其核心使命是"为U-Boot主程序准备运行环境",具体功能如下:
-
扩展硬件初始化:在BootROM的基础上,SPL重点初始化DRAM(这是其最核心的任务)。它会根据开发板的硬件配置(如DRAM型号、容量、时序参数),配置DRAM控制器的寄存器,完成DRAM的自检与激活,使系统获得大容量运行内存。此外,SPL还会初始化简单的电源管理模块,确保硬件供电稳定。
-
加载U-Boot主程序:DRAM初始化完成后,SPL会再次访问外部存储介质,读取其中的U-Boot主程序镜像,并将其加载到DRAM的指定地址(如0x87800000,由链接脚本定义)。由于DRAM容量大(通常为512MB或1GB),完全可以容纳完整的U-Boot主程序(几MB大小)。
-
控制权移交:U-Boot主程序加载完成后,SPL会设置好传递给U-Boot的"启动参数"(如当前硬件状态、启动介质信息),随后跳转到U-Boot主程序的入口地址,完成过渡。
需要说明的是,若开发板硬件简单(如DRAM初始化逻辑简单、U-Boot体积小),也可省略SPL阶段,由BootROM直接加载完整U-Boot(如部分STM32MP157开发板),但主流中高端Linux开发板均会保留SPL以提升兼容性。
2.4 阶段4:U-Boot主程序执行(核心引导层)
U-Boot(Universal Boot Loader)是启动流程的核心,承担"完整硬件初始化"与"Linux内核加载"的双重任务,其执行过程可分为"初始化阶段"与"命令执行阶段"两部分:
2.4.1 初始化阶段(代码级执行)
U-Boot主程序启动后,首先执行板级初始化代码,完成"全系统硬件激活":
-
初始化串口(用于打印启动日志,是开发调试的核心接口);
-
初始化网口、USB、显示屏等外设(根据开发板配置);
-
解析环境变量(如bootcmd、bootargs,存储在EEPROM或eMMC的特定分区中,用于配置启动参数);
-
执行硬件自检(如内存容量检测、外设连通性检测),并在串口输出检测结果。
2.4.2 命令执行阶段(用户/自动引导)
初始化完成后,U-Boot会进入命令行模式(若未设置自动启动),用户可通过串口输入命令(如烧写镜像、修改环境变量);若设置了自动启动(由bootcmd环境变量控制),则自动执行以下流程:
-
根据bootcmd的配置(如"mmc dev 0; fatload mmc 0:1 0x80800000 zImage; fatload mmc 0:1 0x83000000 imx6ull-xxx.dtb"),从eMMC/QSPI等介质中读取Linux内核镜像(zImage)和设备树(dtb)到DRAM的指定地址;
-
构造Linux内核启动参数(bootargs),如指定根文件系统的位置("root=/dev/mmcblk0p2 rw")、控制台接口("console=ttymxc0,115200")等;
-
调用bootm或bootz命令,跳转到Linux内核的入口地址,将控制权正式移交给Linux内核。
2.5 阶段5:Linux系统启动(最终目标)
U-Boot移交控制权后,Linux系统开始启动,核心是"内核初始化"与"根文件系统挂载",具体流程如下:
-
内核解压与启动:若内核镜像是压缩格式(如zImage),首先执行内置的解压程序,将内核解压到DRAM的高地址区域,随后进入内核初始化流程。
-
内核初始化:内核首先初始化自身核心组件(如进程管理、内存管理、中断系统),然后解析设备树(dtb),识别开发板的硬件配置(如CPU型号、外设地址、引脚定义),并根据设备树加载对应的驱动程序,完成外设的初始化(如网口、USB、存储设备)。
-
根文件系统挂载:内核初始化完成后,根据bootargs中指定的"root"参数,找到并挂载根文件系统(rootfs)。根文件系统中包含了Linux系统的基本命令、库文件、启动脚本等核心资源。
-
用户空间启动:根文件系统挂载后,内核会启动第一个用户进程(init进程,PID=1),init进程会执行/etc/init.d/目录下的启动脚本,依次启动网络服务、应用程序等,最终完成整个系统的启动,用户可通过串口或SSH登录系统。
三、对于Boot ROM的相关疑问解答
3.1 bootROM不是支持XIP吗?那么运行bootROM时还需要将bootROM所要的临时数据放到bootROM存储区里还是芯片的SRAM?
BootROM 支持 XIP 是指 "代码原地执行",但运行时产生的临时数据,绝不会放在 BootROM 存储区,而是必须放在芯片内置的 SRAM 中。
下面分 3 个层面拆解,结合硬件特性和 BootROM 的设计逻辑讲清楚:
3.1.1 先明确:XIP 解决的是 "代码在哪执行",和 "数据存在哪" 无关
XIP(Execute In Place,原地执行)的核心目的是 避免 "把代码从存储介质加载到 RAM 再执行" ------ 对于 BootROM 来说,它的代码固化在芯片内部的只读存储介质(比如掩膜 ROM、OTP、NOR Flash)中,XIP 意味着 CPU 可以直接从这片存储介质中读取指令执行,不需要先把 BootROM 代码拷贝到 SRAM 再运行(省掉 "加载代码" 的步骤)。
但 代码执行和数据存储是完全分离的:
- 代码(指令):只需要 "读" 权限,BootROM 存储介质(ROM/OTP)是只读的,刚好满足 XIP 执行的需求;
- 临时数据:运行时会产生栈(stack,保存函数调用、局部变量)、堆(heap,动态分配内存)、全局变量(可修改的),这些数据需要 "读 + 写" 权限 ------ 而 BootROM 存储介质是只读的(硬件层面锁定,无法写入),根本不可能用来存临时数据。
3.1.2 为什么临时数据只能放 "芯片内置 SRAM"?(没有其他选择)
BootROM 是系统上电后第一个运行的程序,此时的硬件状态是 "最小化初始化",只有芯片内部的核心模块可用,外部设备全未就绪,所以临时数据只能选 芯片内置的 SRAM(片内 SRAM),原因有 2 个:
- ① 硬件层面:片内 SRAM 是 SoC 出厂时集成在芯片内部的,上电后无需任何初始化(或仅需简单配置时钟)就能直接访问,且支持读写,天生就是 "临时数据存储区";
- ② 外部设备不可用:BootROM 的核心任务之一是初始化 DRAM(或交给后续 SPL 初始化),此时外部 DRAM 还没配置,完全无法访问;而 eMMC、SD 卡等外部存储,BootROM 只有 "读代码" 的极简驱动(用于加载 SPL),没有 "写数据" 的驱动,且速度慢、延迟高,根本不适合存运行时临时数据。
简单说:BootROM 运行时,整个系统只有 "片内 SRAM" 是可用的读写空间,临时数据只能存在这。
3.1.3 结合 BootROM 的实际运行逻辑,再强化理解
BootROM 的运行流程本质是:上电 → 硬件复位 → CPU 从 BootROM 存储区(ROM/OTP)XIP 执行指令 → 自动将"数据段"(可修改的全局变量、栈、堆)映射到片内 SRAM → 执行初始化最小硬件、读取 SPL 等核心逻辑
这里有个关键设计:SoC 出厂时,硬件会默认分配一片 专属的片内 SRAM 给 BootROM(容量通常很小,比如几 KB~ 几十 KB),BootROM 的代码在编译时,就已经把 "数据区" 的地址硬编码为这片 SRAM 的地址 ------ 运行时,所有需要修改的临时数据,都会自动存到这片 SRAM 中,和 BootROM 存储区(只读)完全隔离。
3.1.4 呼应之前的 SPL 知识点,形成完整逻辑
之前聊过 "SPL 会被 BootROM 加载到片内 SRAM 运行"------ 这里的 "片内 SRAM",和 BootROM 存临时数据的 SRAM,可能是同一片(通过地址分区隔离),也可能是芯片内置的另一片专属 SRAM(取决于 SoC 设计):
- BootROM 运行时:用 SRAM 的一部分存自己的临时数据;
- BootROM 加载 SPL 时:把 SPL 镜像写入 SRAM 的另一部分(或覆盖 BootROM 用过的临时数据区,因为 BootROM 执行完就退出了);
- SPL 运行时:再用这片 SRAM 存自己的临时数据,直到 SPL 初始化完 DRAM,后续主引导程序(U-Boot)再搬到 DRAM 中。
3.1.5 总结
BootROM 支持 XIP 的核心是 "代码在只读存储区原地执行",而临时数据必须存到可读写的片内 SRAM------ 两者的分工是:
| 存储对象 | 存储位置 | 核心原因 |
|---|---|---|
| BootROM 代码(指令) | 芯片内置只读存储(ROM/OTP) | 支持 XIP 原地执行,无需加载 |
| 临时数据(栈 / 堆 / 变量) | 芯片内置 SRAM | 唯一可用的 "读 + 写" 空间,上电即就绪 |
简单说:
XIP 解决 "代码不用搬",SRAM 解决 "数据有地方存",两者配合才能让 BootROM 正常运行。XIP只解决了不用把固有代码再搬到了RAM中再进行取指译指这个过程,而临时产生的数据需要放到RAM。对于 BootROM 而言,其固化的代码本身就存储在 ROM 中,而 ROM 天然支持 XIP(只读、可随机访问取指),所以 BootROM 的代码无需 "搬入 RAM",直接在 ROM 中完成取指、译码、执行。SRAM 解决"数据有地方存":BootROM 的执行过程中,代码(指令)是 "只读" 的(固化在 ROM(只读的存储空间) 中),但指令执行必须依赖可读写的数据空间(就是RAM)。