ARM64-Trust-Firmware[3]-BL1解析
3 BL1
3.1 bl1_entrypoint
bl1的源码如下

- bl1.ld.S为链接文件
- bl1.mk为编译文件
在bl1.ld.S中定义了bl1的入口函数为bl1_entrypoint以及内存布局,ROM的内存为可读可执行,RAM的内存可读可写可执行
ENTRY(bl1_entrypoint) |
关于BL1_RO_BASE和BL1_RW_BASE的值,这个是和平台息息相关的,比如qemu平台上:
/* |
bl1_entrypoint函数定义在bl1\aarch64\bl1_entrypoint.S中:
.globl bl1_entrypoint |
bl1_entrypoint函数进来首先会掉用
el3_entrypoint_common此宏,此宏做了很多事情,会根据传入的参数来进行操作:参数 含义(是否需要执行该步骤) 典型使用场景 备注 _init_sctlr 是否初始化 SCTLR_EL3(含 endian 设置) 几乎总是需要 通常传 1 _warm_boot_mailbox 是否检查 warm boot mailbox 并跳转 BL31 通常需要,BL1 通常不需要 决定是否要读平台 entrypoint _secondary_cold_boot 是否区分 primary/secondary CPU 并处理 secondary 冷启动多核平台几乎都要 可设 0 跳过(已知只 primary) _init_memory 是否执行平台内存初始化(platform_mem_init) 通常 primary CPU 冷启动需要 — _init_c_runtime 是否初始化 C 运行时环境(清 BSS、COHERENT_RAM 等) 几乎所有进入 C 代码前都要 — _exception_vectors 要设置的 VBAR_EL3 向量表地址 必填,通常是 el3_vectors 或类似 — _pie_fixup_size PIE(位置无关可执行)需要修复的 GDT 大小 开启 PIE 时非 0 通常是映像大小
接着通过
bl bl1_main跳转到bl1_main函数中执行,执行完毕bl1_main后会接着判断是否启用ENABLE_RME,关于RME是什么,可以参考如下的文章,这是ARM-V9引入的新的特性,我们暂且不关注https://zhuanlan.zhihu.com/p/25848029106。这是一种应用于ARM机密计算(CCA)的一种新架构

- 最后调用
el3_exit函数进入下一阶段运行
3.2 el3_entrypoint_common
/* ----------------------------------------------------------------------------- |
总体流程如下:
1. (可选)初始化 SCTLR_EL3 |
3.2.1 SCTLR_EL3寄存器
此寄存器全名为:System Control Register for Exception Level 3

各个bit的解释如下:
| 位 | 名称 | 含义(简要中文) | 取值解释 | 复位值(PE 复位到 EL3 时) | TF-A 典型做法(el3_entrypoint_common) | 是否常见扩展特性 |
|---|---|---|---|---|---|---|
| [63:45] | — | 保留,RES0 | — | — | — | — |
| 44 | DSSBS | 禁用投机存储旁路安全(Speculative Store Bypass Safe) | 0:异常进入 EL3 时 PSTATE.SSBS = 0(启用 SSBS 防护) 1:PSTATE.SSBS = 1(禁用防护) | IMPLEMENTATION DEFINED | 强制清0(安全优先) | ARMv8.0-SSBS |
| 43 | ATA | EL3 分配标签访问控制(Allocation Tag Access) | 0:禁止访问 Allocation Tags 1:允许访问 | UNKNOWN | 通常不设(依赖平台) | ARMv8.5-MemTag |
| 42 | — | 保留,RES0 | — | — | — | — |
| [41:40] | TCF | EL3 Tag Check Fault 处理方式 | 00:无影响 01:同步异常 10:异步累积 11:保留 | UNKNOWN | 通常不设 | ARMv8.5-MemTag |
| [39:38] | — | 保留,RES0 | — | — | — | — |
| 37 | ITFSB | Tag Check Fault 异步异常进入 EL3 时是否自动同步到 TFSR | 0:不同步 1:同步 | UNKNOWN | 通常不设 | ARMv8.5-MemTag |
| 36 | BT | PAC 分支类型兼容性(Branch Type compatibility) | 0:PAC*ASP 与 BTYPE=0b11 兼容 1:不兼容 | UNKNOWN | 通常不设 | ARMv8.5-BTI |
| [35:32] | — | 保留,RES0 | — | — | — | — |
| 31 | EnIA | 使用 APIAKey_EL1 对指令地址进行 PAC(Pointer Authentication) | 0:禁用 1:启用 | UNKNOWN | 通常不设(或平台决定) | ARMv8.3-PAuth |
| 30 | EnIB | 使用 APIBKey_EL1 对指令地址进行 PAC | 同上 | UNKNOWN | 同上 | ARMv8.3-PAuth |
| [29:28] | — | 保留,RES1 | 必须写1 | — | — | — |
| 27 | EnDA | 使用 APDAKey_EL1 对数据地址进行 PAC | 0:禁用 1:启用 | UNKNOWN | 通常不设 | ARMv8.3-PAuth |
| 26 | — | 保留,RES0 | — | — | — | — |
| 25 | EE | EL3 数据访问 + Stage-1 页表走访 的 Endianness | 0:Little-endian(小端) 1:Big-endian(大端) | IMPLEMENTATION DEFINED | 强制 0(现代系统全 LE) | 基础特性 |
| 24 | — | 保留,RES0 | — | — | — | — |
| 23 | — | 保留,RES1 | 必须写1 | — | — | — |
| 22 | EIS | 异常进入 EL3 是否为上下文同步事件(Context Synchronizing) | 0:不是 1:是 | UNKNOWN | 通常不设(默认0) | ARMv8.5-CSEH |
| 21 | IESB | 隐式错误同步屏障(Implicit Error Synchronization Barrier) | 0:禁用 1:启用(异常进入/ERET 前加隐式 ESB) | UNKNOWN | 如果 ENABLE_FEAT_RAS 则设1 | ARMv8.2-IESB |
| 20 | — | 保留,RES0 | — | — | — | — |
| 19 | WXN | Write 权限隐含 XN(Writeable implies eXecute-Never) | 0:无影响 1:EL3 可写区域强制不可执行 | UNKNOWN | 强制 0(避免限制) | 基础特性 |
| 18 | — | 保留,RES1 | 必须写1 | — | — | — |
| 17 | — | 保留,RES0 | — | — | — | — |
| 16 | — | 保留,RES1 | 必须写1 | — | — | — |
| [15:14] | — | 保留,RES0 | — | — | — | — |
| 13 | EnDB | 使用 APDBKey_EL1 对数据地址进行 PAC | 0:禁用 1:启用 | UNKNOWN | 通常不设 | ARMv8.3-PAuth |
| 12 | I | EL3 指令缓存控制 | 0:指令 Non-cacheable 1:正常缓存策略 | 0 | 通常后续设1(开启 I-cache) | 基础特性 |
| 11 | EOS | 异常返回(ERET)是否为上下文同步事件 | 0:不是 1:是 | UNKNOWN | 通常不设 | ARMv8.5-CSEH |
| [10:7] | — | 保留,RES0 | — | — | — | — |
| 6 | nAA | 非对齐访问控制(针对某些 Acquire/Release 指令) | 0:强制 16 字节对齐,否则 Alignment fault 1:允许非对齐 | UNKNOWN | 通常不设(默认0较安全) | ARMv8.4-LSE |
| [5:4] | — | 保留,RES1 | 必须写1 | — | — | — |
| 3 | SA | SP(栈指针)对齐检查 | 0:禁用 1:SP 必须 16 字节对齐,否则异常 | UNKNOWN | 强制 0(方便栈操作) | 基础特性 |
| 2 | C | EL3 数据缓存控制 | 0:数据 Non-cacheable 1:正常缓存策略 | 0 | 通常后续设1(开启 D-cache) | 基础特性 |
| 1 | A | 常规内存访问对齐检查 | 0:禁用对齐检查 1:启用(未对齐访问 → Alignment fault) | UNKNOWN | 强制 0(避免不必要故障) | 基础特性 |
| 0 | M | EL3 Stage-1 MMU 使能 | 0:关闭地址翻译 1:开启 | 0 | 早期通常0,后续视平台设1 | 基础特性 |
在el3_entrypoint_common中做了如下设置:
mov_imm x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \ |
- SCTLR_RESET_VAL:硬件复位后的默认值(平台定义,但通常包含未知位)
- 强制 EE=0(小端)
- 强制 WXN=0(不强制写=不可执行)
- 强制 SA=0(栈不对齐也行)
- 强制 A=0(普通访问不对齐也行)
- 强制 DSSBS=0(启用 SSBS 防护)
3.2.2 EL3异常向量表设置

Bits **[63:11]**:真正的向量基地址(Vector Base Address)
- 必須對齊到 2KB(因為最低 11 bits 是保留的)
Bits **[10:0]**:RES0(保留,必須為 0)
/* --------------------------------------------------------------------- |
- 设置EL3的异常向量表为
bl1_exceptions
/* ----------------------------------------------------------------------------- |
bl1的异常向量表从 bl1_exceptions 开始,2KB 对齐,总共 0x800 字节,分成 4 个 0x200 字节的块:
| 偏移 | 异常来源 | BL1 处理方式 | 预期异常类型 |
|---|---|---|---|
| 0x000 | Current EL with SP0 | 全部 panic | 不应该发生 |
| 0x200 | Current EL with SPx (EL3 用自己的 SP) | 全部 panic | 不应该发生 |
| 0x400 | Lower EL 使用 AArch64 | 只允许 SMC,其余 panic | 只允许 SMC |
| 0x600 | Lower EL 使用 AArch32 | 全部 panic | 不支持 AArch32 |
plat_report_exception是一个和平台相关的自定义函数,例如:
/* ----------------------------------------------------- |
对于smc_handler64的处理,函数逻辑如下:
func smc_handler64 |
smc_handler64
├─ 如果 x0 == BL1_SMC_RUN_IMAGE
│ └─ 走「RUN_IMAGE 快速路径」→ 直接跳转下一个 BL
│
└─ 否则
└─ 走「普通 SMC 路径」
→ bl1_smc_wrapper_aarch64
→ el3_exit
3.2.3 CPU复位
.macro call_reset_handler |
3.2.4 公共初始化
/* |
3.2.5 恢复EL3执行环境
- EL3 会在 Secure / Non-secure / Realm 等世界之间来回切换
- lower EL 可能修改:
- 中断屏蔽
- debug / PMU 状态
- CPTR / SCR 等寄存器的某些位
👉 如果不“每次回来都重置”,EL3 的行为就会被下层世界污染
/*----------------------------------------------------------------------------- |
3.3 bl1_main
/******************************************************************************* |
3.3.1 加载验证BL2镜像
主函数在加载BL2镜像时会根据板级配置拿到BL2镜像的大小、地址等信息,然后将其从存储介质(如 Flash 或 FIP 容器)读取 BL2 镜像到可信 SRAM,同时还会执行执行加密校验(哈希、签名验证),确保镜像完整性和来源可信。
/* Get the image id of next image to load and run. */ |
3.3.2 跳转前的准备
/*************************************************************************** |
对应的SPSR_EL3寄存器如下:

SPSR_EL3寄存器是ARMv8-A (AArch64 执行状态) 中的 PSTATE(Processor State)的描述,主要关注最后几位:
Bits **[4:0]:M[4:0]**(Mode bits,执行模式)
- nRW(bit 4):0 = AArch64 执行状态,1 = AArch32 执行状态。
- **M[3:0]**(bit [3:0]):异常级别 + SP 选择
- 常见编码:
- 0b0000:EL0t(EL0,使用 SP_EL0)
- 0b0100:EL1t(EL1,使用 SP_EL0)
- 0b0101:EL1h(EL1,使用 SP_EL1)
- 0b1000:EL2t / EL2h 等
- 0b1100:EL3t / EL3h
- 常见编码:
- M 字段决定当前异常级别(EL)和使用的栈指针(SP)。
异常进入 EL3(如 SMC / IRQ / reset)
PSTATE ──保存──▶ SPSR_EL3 ``PC ──保存──▶ ELR_EL3异常返回(ERET)
PSTATE ◀──恢复── SPSR_EL3 ``PC ◀──恢复── ELR_EL3
/******************************************************************************* |
3.4 el3_exit
/* ----------------lib\el3_runtime\aarch64\context.S-------------------------------------------------- |
所以整体的BL1流程大概如下:

虽然ARM提供了一个BL1,但是基本上各自的厂商都会实现自己的BL1,并且固化在芯片的ROM中。








![Xhyper剖析[6]--中断虚拟化](/2026/01/20/Xhyper%E5%89%96%E6%9E%90-6-%E4%B8%AD%E6%96%AD%E8%99%9A%E6%8B%9F%E5%8C%96/17689244713913.png)
![Xhyper剖析[5]--MMIO虚拟化](/2026/01/20/Xhyper%E5%89%96%E6%9E%90-5-MMIO%E8%99%9A%E6%8B%9F%E5%8C%96/17689243819381.png)