3、启动流程详解:从ROM代码到Bootloader1、Bootloader2、ATF、TEE、HLOS的完整链路

各位同学,今天我们来啃一块硬骨头——MTK8676的完整启动链路。说实话,我第一次看这个启动流程时,也被这长长的链条吓了一跳。从芯片上电到最终进入Android系统,中间要经历6个阶段,任何一个环节出问题,车机就变砖了。

我在做某个车厂项目时,就遇到过启动到一半卡死的情况。排查了整整三天,最后发现是Bootloader2的签名校验逻辑里有个字节序问题。嗯,这种坑踩过一次就忘不了。今天我把这条链路掰开揉碎了讲给你听,希望能帮你少走弯路。

3.1 启动链路全景图

先给你一个整体印象。MTK8676的启动流程是这样的:

ROM Code → Bootloader1 → Bootloader2 → ATF → TEE → HLOS (Android/Linux)

每个阶段都有明确的职责。我习惯把这条链路比作「接力赛」——每一棒只做自己该做的事,然后交给下一棒。谁越界了,系统就崩了。

阶段 存储位置 主要职责 安全等级
ROM Code 芯片内部ROM 初始化硬件、加载Bootloader1 不可更改
Bootloader1 eMMC Boot分区 初始化DDR、校验Bootloader2 签名验证
Bootloader2 eMMC Boot分区 加载ATF、TEE镜像 签名验证
ATF eMMC特定分区 建立安全世界、启动TEE EL3特权
TEE eMMC特定分区 安全服务、密钥管理 EL1/EL0安全
HLOS eMMC用户分区 车机系统、应用 EL1/EL0非安全

核心要点:整个启动链是一个「信任链」——每一级都要验证下一级的签名。ROM Code信任Bootloader1的签名,Bootloader1信任Bootloader2的签名,以此类推。这就是所谓的「安全启动链」。

3.2 ROM Code:芯片的第一口气

芯片上电后,CPU会从固定的地址开始执行。这个地址指向的就是芯片内部ROM里的代码。ROM Code是芯片出厂时写死的,你改不了,我也改不了。

ROM Code干了三件事:

  • 初始化最基本的硬件——时钟、复位、最基本的IO。注意,这时候DDR还没初始化,所以只能用芯片内部的SRAM。
  • 读取Boot配置——从eFuse或GPIO电平判断启动模式。是eMMC启动?还是UART下载模式?
  • 加载并验证Bootloader1——从eMMC的Boot分区读取Bootloader1,验证其签名,然后跳转执行。

避坑指南:我曾经遇到一个案子,芯片死活不进eMMC启动。查了半天,发现是eFuse里烧录的启动配置被误改了。ROM Code阶段没有打印输出,调试全靠示波器量信号。所以,做硬件设计时一定要留出调试接口。

3.3 Bootloader1:DDR的初始化者

Bootloader1是芯片厂商提供的第一个可编程的启动阶段。它的主要任务就是初始化DDR。为什么?因为ROM Code只有几十KB的SRAM可用,根本装不下后续的代码。

Bootloader1的典型流程:

  1. 初始化DDR控制器和PHY——这步很关键,时序参数错了DDR就罢工。
  2. 从eMMC读取Bootloader2到DDR中。
  3. 验证Bootloader2的签名——用ROM Code传递过来的公钥。
  4. 跳转到Bootloader2。

你想想看,如果DDR初始化失败,整个系统就卡在这里了。我在调试一个DDR不稳定问题时,发现是PCB走线长度不匹配导致的。嗯,硬件和软件的边界就在这里。

3.4 Bootloader2:真正的启动管家

Bootloader2是MTK的Little Kernel(LK)变种。它比Bootloader1复杂得多,功能也更丰富。

Bootloader2主要做这些事:

  • 显示启动画面——初始化显示控制器,把Logo刷到屏幕上。
  • 加载ATF和TEE镜像——从eMMC特定分区读取,验证签名。
  • 提供刷机模式——检测按键组合,进入fastboot或OTA模式。
  • 传递启动参数——把硬件信息、分区表等传给下一级。

注意:Bootloader2是安全启动链的关键节点。如果Bootloader2被篡改,整个系统就沦陷了。所以,一定要确保Bootloader2的签名校验是强制性的,不能有「跳过校验」的后门。我见过某些开发板为了调试方便,把签名校验关掉了——这在量产车机上是绝对不允许的。

3.5 ATF:安全世界的建立者

ATF(ARM Trusted Firmware)运行在EL3异常级别,是整个系统的最高权限。它的工作说白了就是:建立安全世界和非安全世界的隔离。

ATF的启动流程:

  1. 接收Bootloader2传递的控制权。
  2. 初始化GIC(中断控制器)、定时器等系统级硬件。
  3. 加载TEE镜像到安全内存区域。
  4. 验证TEE的签名。
  5. 跳转到TEE入口。

ATF还提供SMC(安全监控调用)接口,让非安全世界可以请求安全服务。比如,HLOS想读取一个密钥,就得通过SMC调用TEE。

3.6 TEE:安全服务的守护者

TEE(Trusted Execution Environment)运行在安全世界,提供隔离的执行环境。车机里的关键操作都在这里完成:

  • 密钥管理——私钥永远不出TEE。
  • 安全存储——加密后的数据存到eMMC。
  • 安全显示——比如倒车影像的显示路径。
  • 安全输入——比如PIN码输入。

TEE启动后,会初始化自己的服务,然后通过ATF通知HLOS:「我准备好了,你可以启动了。」

3.7 HLOS:车机系统的最终舞台

HLOS(High Level Operating System)就是我们熟悉的Android或Linux。它运行在非安全世界,权限最低。

HLOS的启动过程:

  1. Bootloader2把控制权交给HLOS的bootloader(比如U-Boot或LK的HLOS部分)。
  2. HLOS bootloader加载内核和设备树。
  3. 内核初始化驱动、文件系统。
  4. 启动init进程,进入Android系统。

到这里,整个启动链路就走完了。从按下电源键到看到车机主界面,大概需要15-30秒。嗯,这个时间在车规级里是可以接受的。

3.8 安全启动链的验证机制

最后,我总结一下安全启动链的验证机制。说白了就是「一级验一级」:

ROM Code (硬件固化) 
    ↓ 验证签名
Bootloader1 (eMMC Boot1)
    ↓ 验证签名  
Bootloader2 (eMMC Boot2)
    ↓ 验证签名
ATF (eMMC分区)
    ↓ 验证签名
TEE (eMMC分区)
    ↓ 验证签名
HLOS (eMMC用户分区)

关键点:每一级的公钥都存储在上一级中。ROM Code的公钥是烧录在eFuse里的,不可更改。这就是信任的根——Root of Trust。

我曾经在某个项目中,客户要求支持OTA升级Bootloader。这就涉及到公钥更新问题——如果公钥能更新,那攻击者也能更新。解决方案是:用旧私钥签名新公钥,ROM Code验证通过后才允许更新。嗯,这个方案后来成了行业标准做法。

好了,启动流程就讲到这里。下一章我们聊聊OTA升级的具体实现,包括差分升级、回滚保护这些实战内容。到时候我会分享一个差点让项目延期的OTA事故,敬请期待。