📺B站:博主个人介绍
📘博主书籍-京东购买链接*:Yocto项目实战教程
📘加博主微信,进技术交流群:jerrydev
Trust 在 Rockchip 与 Jetson 平台中的角色与实现:从 BL31/BL32 到系统安全服务
关键词:ARM TrustZone、BL31/BL32、Secure Monitor、SMC/SMCCC、PSCI、OP-TEE、ATF、Rockchip Trust、Jetson Trust
本文以 Rockchip 官方《Trust 指南》(V1.1.1)为主线,围绕“Trust 在系统架构里的位置、在启动链路里的作用、在运行期提供的关键能力”展开讲解,并在对 Rockchip 机制讲清楚的基础上,进一步梳理 Jetson(以 Orin 系列为代表)在EL3/安全世界上的对应设计,从而形成一份“可对照、可落地、可调试”的结构化笔记。
0. 先把结论说清楚:Trust 到底是什么
在工程语境里,“Trust”往往不是一个单独的软件项目,而是安全世界固件集合的统称。
- 从 ARM 架构视角:TrustZone 将系统划分为Normal World与Secure World。安全世界负责关键安全服务与安全资源管控;普通世界运行 Linux/Android/Hypervisor 等。
- 从启动阶段视角(ATF 术语):典型链路用 BL1/BL2/BL31/BL32/BL33 表示。BL31 运行在 EL3,提供 Secure Monitor 与运行期服务;BL32 常用于 TEE(如 OP-TEE)等安全世界载荷;BL33 通常是 U-Boot/UEFI 等非安全引导程序。
- 从 Rockchip SDK 视角(文档定义):Rockchip 的 Trust 可以理解为ARM Trusted Firmware(偏 BL31)+ OP-TEE OS(BL32)的组合(64 位平台),并以“trust.img”形式交付。
因此:
Trust = 让 CPU 具备“世界切换”和“安全世界服务”的那组固件(核心是 EL3 + Secure-EL1)。
这也解释了很多现象:
- Linux 内核里调用 PSCI、SMCCC,最终会通过 SMC 指令进入 EL3(BL31)执行;
- Android/Linux 的 TEE Client(CA)要调用 TA/PTA,仍要通过 SMC 进入安全世界(BL31/BL32);
- Trust 出问题时,常见现象不是“应用崩了”,而是早期启动卡死、CPU 上电/休眠异常、SMC 调用失败、甚至 EL3 panic。
1. TrustZone 的“世界划分”与“执行级别”
1.1 世界划分:安全世界为什么能管住普通世界
TrustZone 的核心不是“软件自觉”,而是硬件对资源打标:
- 总线、内存控制器、外设控制器可将访问请求区分为 Secure / Non-secure;
- 安全世界可访问两边资源,普通世界只允许访问 non-secure 资源;
- 普通世界越界访问 secure 资源,往往会触发硬件总线错误或异常。
换句话说:
安全隔离的底座是硬件访问控制,而不是软件约束。
1.2 执行级别:EL3、Secure-EL1 分别负责什么
在 AArch64(64 位)下,常见执行级别为:
- EL0:用户态
- EL1:内核态(Linux kernel)
- EL2:Hypervisor
- EL3:Secure Monitor(安全监控层,世界切换入口)
再叠加世界属性:
- Normal EL0/EL1/EL2:普通世界
- Secure EL0/EL1:安全世界(TEE/Trusted OS)
- EL3:严格意义上属于安全监控层(负责世界切换与关键运行期服务)
Rockchip 文档给出一句非常关键的定位:
Rockchip 的 Trust 可以理解为 EL3 + 安全 EL1 的功能集合。
这句话可直接映射到工程角色:
- BL31(EL3):世界切换、SMCCC/PSCI 运行期服务、异常与中断相关的安全处理、平台安全配置入口
- BL32(Secure-EL1):TEE OS(如 OP-TEE),负责密钥派生/安全存储/TA 执行等
2. 用一张图把启动链路固定下来:BL1/BL2/BL31/BL32/BL33
为了后续的对照分析,先把“阶段编号”和“工程固件”对应关系写成表:
| ATF 阶段 | 典型职责 | AArch64 执行态 | Rockchip 对应(文档映射) | 常见产物 |
|---|---|---|---|---|
| BL1 | BootROM,加载下一阶段 | EL3/ROM | Maskrom | 固化在芯片 |
| BL2 | 二级引导,完成初始化并加载 BL31/BL32/BL33 | EL3/安全环境 | Loader | miniloader/loader.bin 等 |
| BL31 | EL3 Runtime Firmware(Secure Monitor/PSCI/SMCCC) | EL3 | Trust(含 BL31) | ATF BL31 binary |
| BL32 | Secure-EL1 payload(TEE OS) | Secure-EL1 | Trust(含 BL32) | OP-TEE OS binary |
| BL33 | Non-trusted firmware(U-Boot/UEFI) | Normal EL2/EL1 | U-Boot | u-boot.itb/uboot.img |
Rockchip 文档给出 Android 启动顺序:
Maskrom → Loader → Trust → U-Boot → kernel → Android
上面这条链路,就是你在调试“安全启动/TEE/PSCI”时应该首先对齐的系统时序。
3. Rockchip 平台的 Trust:架构、固件组织与运行期职责
3.1 Rockchip 的实现机制:64 位与 32 位的差异
文档明确区分:
- 64 位 SoC:采用ARM Trusted Firmware + OP-TEE OS的组合
- 32 位 SoC:采用OP-TEE OS(文档用语是“32 位平台上使用 OP-TEE OS”)
工程含义是:
- 在 64 位平台上,EL3 的 Secure Monitor 与运行期服务由 ATF 提供(BL31),OP-TEE 负责 Secure-EL1(BL32);
- 在 32 位平台上,历史上存在更多“把安全世界固件打包为一个整体”的交付方式,工程上更依赖厂商实现与平台集成方式。
本文为了讲清楚逻辑,以64 位平台为主。
3.2 Trust 固件如何交付:trust.img 从哪里来
Rockchip 文档强调:
- 对外发布通常只提供binary,不提供完整源码;
- 编译某个平台的 uboot.img 时,对应平台的trust.img会被同时打包生成;
- trust.img 的打包通过ini 文件索引完成;
- 也可下载独立 rkbin 仓库获取各平台 bin。
从使用者视角,这里容易踩的坑是:
- 你以为“只换 u-boot 就行”,但 trust.img 与 u-boot 往往要同版本协同;
- 你以为“trust 是一个目录”,实际交付常常只有一个 trust.img,内部再封装 BL31/BL32 等。
建议的工程习惯:
- 记录每次烧录的 trust.img 版本来源(对应 SDK commit 或 rkbin 版本)。
- 通过串口 log 解析 BL31/OP-TEE 的版本号,形成“运行态版本证据链”。
3.3 Trust 的运行内存布局与生命周期
文档给出两个非常硬的数值:
- ARM Trusted Firmware:运行在 DRAM 起始偏移 0M~2M,入口地址0x10000(64KB)
- OP-TEE OS:运行在 DRAM 起始偏移 132M~148M(各平台略有差异),入口地址0x08400000(132M)
并明确:
Trust 自上电初始化之后始终常驻于内存。
工程意义:
- 这不是“启动完就走人”的固件,而是运行期一直提供服务;
- 内存规划冲突会很致命:例如 DDR layout、reserved-memory、CMA、IOMMU 映射都可能间接影响 Trust 稳定性;
- 当你遇到“休眠/唤醒、CPU hotplug、系统复位异常”时,不要只看 kernel,往往需要回到 PSCI/BL31 的路径。
3.4 Security 边界:哪些阶段属于安全世界
文档给出清晰划分:
- Loader、Trust运行在安全世界
- U-Boot、kernel、Android运行在非安全世界(安全 driver、APP 除外)
这能帮助你快速判断“一个功能应该归谁管”:
- 早期安全配置(TZPC/TZASC/安全 ID 等)通常在 Loader/Trust 完成;
- Linux/Android 侧的安全能力(如 TEE Client、Keymaster、DRM 框架)通常是“普通世界调用入口”,真正敏感操作落在 BL32/安全世界。
4. Rockchip Trust 的核心功能:PSCI、Secure Monitor、平台安全配置
4.1 PSCI:为什么 CPU 电源管理要放到固件里
文档解释 PSCI 的工程动机:
- 不同 SoC 的 CPU 电源/时钟/复位设计差异巨大;
- 内核不希望维持碎片化实现;
- 通过 PSCI,内核把“策略”留在内核,把“与硬件强相关的执行细节”交给固件。
在 Linux 里,这体现为:
- CPU 上电/下电、系统 suspend、system reset/off 等,都会走 PSCI 接口;
- PSCI 的调用本质是SMC陷入到 Trust(EL3),由 BL31 执行。
你可以把 PSCI 理解为:
Linux 与 EL3 固件之间的“电源管理 RPC 接口”。
4.2 Secure Monitor:世界切换的桥
Secure Monitor 是 TrustZone 的“交通警察”。
- 普通世界要进入安全世界:执行 SMC 指令 → 进入 EL3 → Secure Monitor 切换世界属性 → 跳转到安全世界服务
- 安全世界回普通世界:同理,经由 EL3 完成切换
如果 Secure Monitor 出问题,常见症状包括:
- Linux 执行 PSCI/SMCCC 调用卡死
- TEE Client 调 TA 卡死或直接返回错误
- 早期启动在 “Initializing BL32” 或 “Preparing for EL3 exit” 前后停住
4.3 安全信息配置与安全数据保护:Trust 的“平台侧责任”
文档指出 Trust 还承担:
- TrustZone 相关 IP 的安全信息配置
- 安全数据的保护(安全支付、DRM、企业服务等)
这里的关键理解是:
- BL31 更偏“平台安全配置 + 运行期服务”
- BL32(OP-TEE)更偏“安全应用执行 + 密钥/安全存储 + TA 生态”
很多平台把“安全存储”落地为 RPMB、secure partition、或 TrustZone 保护的存储区域,这些往往由 BL32 统一管理,普通世界只能通过受控接口请求。
5. 让 Linux 正确用上 Trust:DTS 里把 PSCI 接上
Rockchip 文档用较大篇幅强调:DTS 使能 PSCI。
5.1 内核 4.4+ 的典型写法(推荐对齐)
关键点只有两个:
- 增加 psci 节点,声明版本与方法
- 在每个 CPU 节点添加 enable-method = “psci”
示意(按文档给出的范式整理):
cpus { #address-cells = <2>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53", "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; }; cpu@1 { /* ... 同理 ... */ }; }; psci { compatible = "arm,psci-1.0"; method = "smc"; };5.2 为什么 DTS 这一步很关键
因为 Linux 并不会“猜测你有 PSCI”。
- 没有 psci 节点:内核可能用不了 PSCI 路径,CPU hotplug/idle/suspend 相关能力会异常
- 没有 enable-method:即使 psci 节点存在,CPU 节点也可能不走 PSCI
你在调试“多核上下电、深度休眠、系统复位”时,DTS 是第一张清单。
6. 现场问题怎么定位:开机日志、版本号与 Panic 识别
Rockchip 文档给了非常实用的“故障定位入口”。
6.1 日志中如何识别 BL31 与 OP-TEE 的输出
典型输出风格(文档给出的示例,非逐字复刻):
- BL31(ATF):NOTICE/INFO 开头,常见行含 “BL31:”
- OP-TEE:INF/ERR 开头,含 “TEE-CORE” 等模块名
理解建议:
- 你在串口里看到 NOTICE: BL31 → 表示 EL3 固件已经开始执行
- 你看到 “Initializing BL32” 或 OP-TEE 的 init 输出 → 表示 BL32 已被加载并开始启动
- 你看到 “Preparing for EL3 exit to normal world” → 表示即将跳转 BL33(U-Boot)
6.2 固件版本号怎么提取
文档给出一种直接方法:
- BL31 版本号:日志中会出现一个短 hash(示例中形如 4c793da)
- OP-TEE 版本号:日志中会出现 gxxxxxxxx 形式(忽略 g 前缀即可)
工程意义:
- 不要只看文件时间戳,运行期日志才是最终证据
- 一旦出现“同一个 trust.img 在不同板子表现不一致”,第一步就是对齐 BL31/OP-TEE 版本号
6.3 Panic 识别:EL3 Panic vs OP-TEE Panic
- EL3 Panic(ATF):往往会打印 EL3 异常寄存器、x0-x30 等上下文信息
- OP-TEE Panic:常见 “Unexpected page fault” 之类的异常,随后 PANIC
建议:
- 记录完整串口 log(含上电到崩溃全部内容)。
- 如果平台支持,结合 JTAG 更接近根因。
- 优先确认:是否 DDR layout、reserved-memory、或 trust.img 与 u-boot/loader 版本不匹配。
7. Jetson 的 Trust:把“Rockchip 术语”映射过去
你已经掌握了 Rockchip 的 Trust 语义,现在把 Jetson(以 Orin 为代表)的体系做一次“同构映射”,理解会更快。
7.1 Jetson 启动链路的常见分层(概念版)
Jetson 的引导链路名词更多(MB1/MB2/UEFI 等),并且有多处理器协同(如 BPMP)。本文采用“对照理解”的方式,给出一个与 BLx 模型对应的抽象:
BootROM ↓ MB1 (平台早期初始化/安全配置,常在安全控制处理器上执行) ↓ MB2 (加载并准备后续镜像) ↓ EL3 Runtime (ATF/secure monitor 语义层) ↓ TEE (OP-TEE 或平台 Trusted OS) ↓ UEFI / CBoot (非安全引导程序) ↓ Linux kernel / Android上面这张“概念图”不追求每个镜像的官方命名完全一致,而是强调:
- Jetson 同样需要EL3 层来承载 Secure Monitor/SMCCC/PSCI 等职责
- Jetson 同样会有Secure-EL1 的 Trusted OS/TEE(是否启用、以何种形态启用,取决于平台配置与发行版)
- Jetson 的早期引导更强调“硬件安全控制器参与初始化”(与 Rockchip 的 Maskrom/Loader 模型不同)
7.2 Jetson 的“Trust”到底指哪一段
在 Jetson 语境里,“Trust”通常不是一个文件名,而是以下能力集合的交集:
- 安全启动链(Secure Boot chain):从 BootROM 开始到引导程序与内核镜像的签名验证
- 密钥材料与硬件熔丝(eFUSE):设备身份、Root of Trust、公钥 hash、密钥派生基
- 安全世界运行期(EL3 + TEE):世界切换、PSCI/SMCCC、TEE 服务(安全存储、派生密钥、TA)
如果用 Rockchip 的语义映射:
- Rockchip 的 trust.img 更像“把 BL31/BL32 打包后交付”的载体
- Jetson 的“trust 相关固件”更分散:EL3/TEE/安全初始化镜像通常由平台工具链与 flash 流程组合下发,并受 fuse 与签名策略约束
7.3 Jetson 与 Rockchip 的关键差异(对照表)
| 维度 | Rockchip(文档主线) | Jetson(以 Orin 代表,抽象对照) |
|---|---|---|
| 交付形态 | trust.img(封装 BL31/BL32)+ uboot.img 等 | 多镜像协同(MB1/MB2/UEFI/ATF/TEE 等),通过 flash 流程组合 |
| 早期引导命名 | Maskrom/Loader | BootROM/MB1/MB2(平台名词) |
| EL3 承载 | BL31(ATF) | 同样需要 EL3 运行期固件(secure monitor 语义层) |
| TEE 承载 | BL32(OP-TEE) | 常见为 OP-TEE/平台 TOS(是否启用与版本相关) |
| Linux 侧对接 | DTS PSCI + SMCCC,TEE Client | 同样依赖 PSCI/SMCCC;TEE Client 与安全存储策略更与平台发行版绑定 |
| 调试入口 | 串口日志识别 BL31/OP-TEE 版本;panic 分类 | 亦可通过启动日志、签名验证日志、TEE log 排查;同时要关注 fuse/签名策略 |
7.4 “同一个概念”的对齐方式:用接口而不是文件名
最稳妥的对齐方法是:
- 看Linux 调用什么接口:PSCI/SMCCC/TEE Client
- 看这些接口在硬件上最终落到哪一层:SMC → EL3 →(必要时)跳转到 Secure-EL1
也就是说,不要陷入“Rockchip 叫 trust.img,Jetson 叫 xxx.img”的名词泥潭。
接口路径一致,工程本质就一致。
8. 面向实战的“排查清单”:当你怀疑 Trust 有问题
下面给出一份跨平台通用的检查顺序(由外到内):
8.1 第一层:现象归类(先别急着改代码)
- 开机停在早期:怀疑 Loader/Trust/签名验证链
- 多核异常、CPU 热插拔失败、休眠唤醒异常:优先怀疑 PSCI/EL3
- TEE 调用失败、TA 无法加载、安全存储异常:优先怀疑 BL32/TEE 与其存储后端
8.2 第二层:证据链(把版本与日志固定)
- 串口 log:截取从上电到进入 U-Boot 或 kernel 的完整日志
- 识别并记录:BL31 版本、OP-TEE 版本
- 对照:当前烧录的 trust.img(或 Jetson 的镜像组合)来源与版本
8.3 第三层:配置链(DTS/内存布局/启动参数)
- DTS:psci 节点、cpu enable-method、reserved-memory
- 内存:OP-TEE 预留区是否被覆盖、CMA/内存碎片化对预留区影响
- 启动参数:是否错误设置导致早期内存布局变化
8.4 第四层:接口链(PSCI/SMCCC/SMC)
- 内核 dmesg:是否有 psci/firmware/rockchip_sip 等相关输出
- 触发点:CPU on/off、suspend、system reset 时是否立即异常
- 深入:必要时用 tracepoint、ftrace、kprobe 跟踪 psci 调用路径
9. 常见误区澄清
误区 1:Trust = Secure Boot
Trust 与 Secure Boot 强相关,但不是同义词。
- Trust 更偏运行期(EL3/TEE)与安全世界服务
- Secure Boot 更偏启动链路的“签名验证/反回滚/熔丝策略”
现实项目里,两者通常会同时出现,因此容易混用。
误区 2:只要有 OP-TEE 就够了
没有 EL3 的 Secure Monitor(BL31),世界切换与 SMCCC/PSCI 等机制无法完整工作。
在 64 位平台里,BL31 是基础设施,BL32 才是安全应用运行环境。
误区 3:PSCI 只是内核功能
PSCI 的设计目的就是把“硬件强绑定的执行逻辑”放到固件里。
内核调用 PSCI,仅是发起请求,真正让电源状态变化的执行常在 EL3/固件侧完成。
10. 总结:用“层次模型”掌握 Trust,跨平台迁移才不会乱
本文围绕 Rockchip《Trust 指南》的主线,建立了一个可迁移的层次模型:
- 架构层:TrustZone 世界划分 + EL0/1/2/3 执行级别
- 启动层:BL1/BL2/BL31/BL32/BL33 阶段模型(Rockchip 映射为 Maskrom/Loader/Trust/U-Boot)
- 运行层:BL31(EL3)提供 Secure Monitor/PSCI/SMCCC,BL32(Secure-EL1)提供 TEE 服务
- 对接层:Linux 通过 DTS 使能 PSCI,通过 SMC 调用进入 EL3,再进入安全世界服务
- 调试层:串口日志识别版本号、区分 EL3 panic 与 OP-TEE panic,建立版本证据链
- 迁移层:Jetson 名词体系不同,但“接口路径一致、层次职责一致”,用映射表可快速对齐
如果你正在做“安全启动 + TEE + 磁盘加密/安全存储 + OTA”的完整方案,这篇文章可以作为 Trust 章节的骨架:
- 先用 BL31/BL32 明确边界
- 再用 PSCI/SMCCC/TEE Client 把普通世界与安全世界的接口闭环
- 最后用日志与版本号把问题定位流程标准化
关键问答(用于巩固)
Q1:Rockchip 文档里为什么说“Trust 可以理解为 EL3 + 安全 EL1 的功能集合”?
**A1:**因为在 64 位平台上,Trust 的关键职责正落在BL31(EL3)与BL32(Secure-EL1)两层:前者负责世界切换与 PSCI/SMCCC 等运行期服务,后者通常承载 TEE OS(OP-TEE)执行 TA 与安全存储等能力。两层合在一起,才构成平台意义上的“Trust”。
Q2:为什么必须在 DTS 中写 psci 节点与 enable-method=“psci”?
**A2:**因为 Linux 需要通过设备树显式获知“平台的 CPU 电源管理由 PSCI 提供,调用方式为 SMC”。缺失 psci 节点或 enable-method,内核可能不会走 PSCI 路径,从而导致 CPU 上下电、idle、suspend、system reset 等行为异常或不可用。
📺B站:博主个人介绍
📘博主书籍-京东购买链接*:Yocto项目实战教程
📘加博主微信,进技术交流群:jerrydev