关于达发 AIROHA Bootloader(TCBOOT) 的一些分析

概念

在ARM平台下,其实已经不存在 TCBoot 这个东西了,TCBoot 是 Airoha/Econet 厂商对其 MIPS 平台的 bootloader 的命名,ARM 平台上已经被 TF-A (Trusted Firmware-A) + U-Boot 取代了。但是由于历史惯性以及遗留的代码和文档,我们仍然会看到 TCBOOT 这个名字,并对仍然用 TCBOOT 称呼 Airoha/Econet 的 ARM bootloader。

Bootloader 组成

这个 mtd0 的 bootloader 不是单纯的 “U-Boot 一个文件”,而是厂商打包后的 tcboot.bin / bootloader 总包。从文件里看到的结构大致是:
mtd0 bootloader: 0x00000000-0x00080000, 512 KiB
里面包含:
0x00000000 起:ARMv7 启动代码 / 前级 loader / BL2 类代码
0x0001a000 附近:DDR、SPI NAND、secure boot、LZMA 解压相关代码和字符串
0x0001e000 附近:Trusted Boot / Non-Trusted Firmware 证书链
0x00021000:LZMA 压缩 payload,解出来是 BL31
0x00024800:LZMA 压缩 payload,解出来是 U-Boot
0x0007c000 附近:U-Boot 环境变量区

所以它的启动链更像是:
SoC BootROM
-> mtd0 里的前级 loader / BL2
-> 初始化 PLL / DDR / SPI NAND
-> 校验证书 / secure boot 相关处理
-> 解压并启动 BL31
-> 解压并进入 U-Boot,也就是 BL33
-> 读取 tclinux
-> bootm 启动 kernel

也就是说,你没有看到单独的 BL2.bin、FIP.bin(BL31.bin、u-boot.bin) 分区,是因为它们都被打进了一个厂商 bootloader 镜像里。

它不是裸 U-Boot,而是包含前级、BL31、U-Boot、证书和环境区的组合包。

ComponentOffsetSizeDescription
bl1.bin0x000002,016 BBL1 first-stage loader (exact match with en7523/en7523-bl1.bin)
key_area.bin0x007E01,056 BSecure-boot key/hash table
bl2.bin0x00C00127,210 BPre-assembled BL2 (DDR init, SPI-NAND, LZMA, secure boot)
certificates.bin0x200004,096 BTwo X.509 DER certificates (trusted + non-trusted FW)
bl31.lzma.bin0x2100014,336 BBL31 LZMA compressed stream
bl31.bin32,896 BBL31 decompressed (AArch64 runtime firmware)
uboot.lzma.bin0x24800358,400 BU-Boot LZMA compressed stream
uboot.bin260,352 BU-Boot 2014.04-rc1 (Jun 08 2023) decompressed
uboot.env.bin0x7C00016,384 BU-Boot environment (37 variables)

安全启动

大多数 EN7523 设备的 bootloader 编译了完整的安全启动支持,但 eFuse 未烧录 ROTPK(根信任公钥哈希),导致运行时验证被跳过。

1
ROTPK is not deployed on platform. Skipping ROTPK verification.

BL2 启动时会读取 eFuse 中的 ROTPK。由于 eFuse 没有烧录,BL2 走了 “skip” 分支——直接跳过证书验证,不检查 BL31 和 U-Boot 的签名。

验证流程(实际运行路径)

阶段做了什么安全检查
BootROM加载 BL1无验证
BL1 (0x0, 2016B)加载 BL2无 SHA-256 常量,不做哈希
BL2 (0xC00, 127KB)读 eFuse 找 ROTPK未找到 → 跳过验证
BL2 → BL31解压 LZMA 加载证书存在但未验证
BL2 → U-Boot解压 LZMA 加载证书存在但未验证
U-Boot bootmflash imgread 2048;bootm无签名验证

未生效时的安全机制

SDK 确实以 TRUSTED_BOARD_BOOT=1 编译,以下设施全部存在:

  1. Mbed TLS 完整加密栈:RSA (SHA-224/256/384/512)、RSASSA-PSS + MGF1、HMAC-SHA-224/256/384/512、DES-CBC/3DES、X.509 ASN.1 解析器

  2. 2 个 X.509 DER 证书(0x20000):

    • SoC Firmware Content Certificate(可信固件 = BL31)
    • Non-Trusted Firmware Content Certificate(非可信固件 = U-Boot)
    • 有效期:2023-06-08 ~ 2043-06-03(与 U-Boot 构建日期一致)
    • 都包含 RSA 公钥
  3. 4 类 TBBR 证书类型定义:Trusted Boot FW / Trusted Key / SoC Firmware Key / Non-Trusted FW Key

  4. 20 个 ECNT 私有 OID1.3.6.1.4.1.4128.2100.xxx

  5. 固件加密支持:代码中同时存在 FW UN-ENCRYPTIONFW ENCRYPTION 路径,当前走的是 UN-ENCRYPTION

真正启用安全验证

要激活安全启动,厂商需要:

  1. 生成 RSA 密钥对,将公钥的 SHA-256 哈希烧入 eFuse 的 ROTPK 区域

  2. 用私钥对 BL31 和 U-Boot 签名,签名嵌入证书

  3. BL2 启动时读到 ROTPK → 验证证书签名 → 验证固件哈希 → 通过才加载

BOOTEXT.RAM

en7523_bootext.ram 和普通 bl2.bin 本质上是同一段 BL2 固件的不同打包形态,区别在于封装格式、包含内容和加载方式。

它是一个标准的 FIP (Firmware Image Package) 格式文件,结构如下:

偏移内容大小
0x0000FIP TOC Header (magic=0xAA640001)16B
0x0010TOC Entry 0: BL2 firmware (UUID: 0becf95f-...)40B
0x0038TOC Entry 1: Certificate (UUID: ea69e2d6-...)40B
0x0060NULL terminator40B
0x0400BL2 固件代码 (ARM 指令)119,454B
0x1D800X.509 证书 (“Trusted Boot FW Certificate”, DER, 2021-2041)1,135B
0x1DFFCCRC324B

总大小 122,880B (0x1E000),由 trx -t <input> bootext.ram 创建 — CRC 计算覆盖 (size-4) 字节,放在数据内部最后 4 字节,变长无 flash 填充

bl2.bin 是什么

裸 ARM 二进制,无任何容器头,直接从 mov r9, #0 指令开始。大小 115,350B,由两步创建:

  1. trx -z — 打包 bl21 + bl22.lzma + bl23.lzma + flash_table.lzma

  2. trx -x — 在数据之后追加 4 字节 CRC

核心差异

bootext.rambl2.bin
格式FIP 容器 (TOC + entries)裸 ARM 二进制
证书内含 TBBR “Trusted Boot FW Certificate”无 (证书单独存于 tcboot.bin)
CRC 位置数据内部最后 4 字节数据之后追加 4 字节
加载方式RAM 加载 (下载/恢复模式)Flash 加载 (LZMA 压缩后嵌入 tcboot.bin/mtd0)
大小122,880B (含 FIP 头+证书+对齐)115,350B (纯代码)
创建工具trx -t <fip_input> bootext.ramtrx -z + trx -x

两者 BL2 代码的前 0x34 字节完全相同(ARM vector table),仅 0x34 处一条 BL 跳转指令的目标不同(+0x42C vs +0x3C4),说明是同一代码库的不同编译版本。

简单说:bootext.ram = “boot extension” = 自包含的 RAM 加载版 BL2,自带证书和 FIP 元数据,用于 BootROM 直接加载到 RAM 执行(如下载模式/恢复模式);而 bl2.bin 是精简的 flash 启动版,会被 LZMA 压缩后塞进 tcboot.bin 的 0xC00 偏移处。

救砖

Econet/Airoha 设计了一个类似高通9008/MTK UART的“Emergency upgarde”模式,但是中文互联网更喜欢称呼为“X模式”。

飞思灵的几款基于 AN7581FP 换皮的芯片 FSL61167D/P,其 BROM 中未烧录 Emergency Upgrade 功能,并且由于其闪存控制器还是旧款基于EN7510的mtk_nand闪存控制器,使用48脚TSOP封装的闪存,救砖只能依靠 JTAG 或者 编程器。

该模式由“XMODE” 驱动,具体方法为:

  1. 按住复位键,同时连接 TTL,终端会显示 CCCC,表示进入了 XMODE,此时会提示你“Press x”

  2. 按下 x 键,设备会进入,就会进入紧急升级模式,等待主机发送 bootext.ram

  3. 通过xmodem 工具,将 bootext.ram 发送到设备,设备会在 RAM 中解压并执行 BL2,BL2 会初始化,并提示按下 x 键继续升级

  4. 按下 x 键,再次使用 xmodem 发送 tcboot.bin,BL2 会解压并写入 SPI-NAND,完成升级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
EN7523DRAMC V0.6
dram_type = 5, speed = 1866
Final Impdance Cal Result: OCDP:0x14, OCDN:0x1b, ODTP:0x6, ODTN:0x6
DDR1866 PLL setting init
[Dramc] PCDDR3 AC Timing update
Fire MRW command...
ModeReg.2, value.0x20 done
Fire MRW command...
ModeReg.3, value.0x0 done
Fire MRW command...
ModeReg.1, value.0x6 done
Fire MRW command...
ModeReg.0, value.0x1114 done
Fire MRW command...
ModeReg.1, value.0x86 done
Fire MRW command...
ModeReg.1, value.0x6 done
Calculate size.
DRAM size=512MB
Press x to update firmware

这个模式的好处是不依赖 SPI-NAND 的内容,即使 NAND 里没有有效的 bootloader,也可以通过 XMODE 直接升级。

另外如果原来的 bl2 没有被破坏,可以在第一阶段不需要升级 bootext.ram,等待其超时进入第二阶段,直接发送 tcboot.bin 也可以升级。

bootext.ram 里面包含了 BL2、证书和 CRC 校验,BL2 会在 RAM 中解压并执行,初始化 DDR、SPI-NAND、secure boot 等,然后再解压 tcboot.bin 并写入 SPI-NAND。所以bootext.ram不能乱用,里面的证书要匹配机型,一旦是不匹配的bl2和证书,触发了panic,救砖就十分困难了。所以在 en7523/en7562 系列的 ATF 开源之前,我们应该尽量提取原厂的 tcboot.bin 以及其中存在的各个组成,打包配套的 bootext.ram,避免使用不匹配的 bootext.ram。

Tips: Airoha 的 uboot 通常会设置一个账号密码 ‘telecomadmin/nE7jA%5m’,通常会要求使用console前置登录,才能进入命令行,但是如果启动失败时,uboot 会直接进入命令行,不需要登录。