3. ATF 源码结构分析:关键目录的功能与依赖关系

ARM Trusted Firmware (ATF) 的源码采用分层模块化设计,将安全世界的启动流程拆解为多个独立的镜像阶段。理解各目录的职责与依赖关系,是进行启动优化和定制移植的基础。本章将深入分析 bl1、bl2、bl31、bl32、common 和 plat 这六个核心目录。

3.1 整体架构与启动流水线

ATF 的启动流程是一个严格的线性流水线,每个 Boot Loader (BL) 阶段负责特定的初始化任务,并加载下一个阶段。下图展示了从 ROM 到 Rich OS 的完整启动链路。

关键概念: ATF 的启动顺序是 BL1 → BL2 → BL31/32 → 非安全世界 (U-Boot/Linux)。BL33 (如 U-Boot) 由 BL31 在退出安全世界后加载。
ATF 启动流水线架构图 ATF 启动流水线架构图 BL1 BL2 BL31 BL32 (OPTee) BL33 (U-Boot) Linux Kernel 说明:BL1 由 ROM 加载,BL2 由 BL1 加载,BL31/BL32 由 BL2 加载,BL33 由 BL31 加载。 虚线表示 BL31 负责初始化并跳转到 BL32(安全世界),之后返回 BL31 再跳转到 BL33。

3.2 关键目录功能详解

每个 BL 阶段对应源码中的一个顶级目录,它们各自承担不可替代的职责。下表总结了各目录的核心功能与输出产物。

目录 全称 核心功能 输出产物
bl1 Boot Loader Stage 1 ROM 加载后的第一个固件,初始化 CPU、平台基础外设、TrustZone 控制器,加载 BL2 到 SRAM。 bl1.bin
bl2 Boot Loader Stage 2 运行在 SRAM,负责加载 BL31、BL32 和 BL33 镜像到指定内存,并传递平台参数。 bl2.bin
bl31 Boot Loader Stage 3 (EL3 Runtime) EL3 异常等级运行时固件,处理安全监控调用 (SMC)、电源管理、PSCI 服务,是安全世界的入口。 bl31.bin
bl32 Boot Loader Stage 2 (Secure OS) 安全操作系统镜像(如 OP-TEE),提供安全服务,运行在 S-EL1。 bl32.bin
common Common Library 存放各 BL 阶段共享的通用代码,如内存管理、链表操作、控制台输出、异常处理框架。 静态库 (libcommon.a)
plat Platform Porting Layer 平台移植层,包含所有与具体 SoC 和板级硬件相关的代码,如 GIC、UART、定时器、电源域。 平台定制代码

3.3 目录间的依赖关系

ATF 的依赖关系遵循严格的单向原则:低阶段依赖高阶段提供的接口,高阶段依赖低阶段完成初始化。同时,所有 BL 阶段都依赖 common 和 plat 目录。

  • bl1 → bl2:BL1 负责加载 BL2,BL2 的入口地址和参数由 BL1 通过平台结构体传递。
  • bl2 → bl31/bl32/bl33:BL2 解析镜像头部信息,将 BL31、BL32 和 BL33 加载到各自的内存区域,并设置好跳转上下文。
  • bl31 → bl32:BL31 在初始化 EL3 运行时环境后,通过 SMC 调用或直接跳转进入 BL32(安全 OS)。
  • bl31 → bl33:BL31 在完成安全世界初始化后,通过 el3_exit 退出到非安全世界的 BL33。
  • 所有 BL → common:每个 BL 阶段都链接 common 库,使用其提供的通用函数,如 console_putc、memcpy、assert。
  • 所有 BL → plat:每个 BL 阶段都通过平台宏和回调函数访问硬件资源,如 plat_get_my_entrypoint、plat_my_core_pos。
优化提示: 在启动优化中,bl2 和 bl31 是主要优化对象。减少 BL2 的镜像加载时间(如使用 DMA 或 XIP 执行)以及精简 BL31 的初始化流程,能显著缩短整体启动时间。

3.4 平台目录 (plat) 的内部结构

plat 目录是移植工作的核心,其内部按厂商和 SoC 系列组织。一个典型的平台目录结构如下:

plat/
├── arm/                          # ARM 官方参考平台
│   ├── common/                   # ARM 平台通用代码
│   ├── fvp/                      # Fixed Virtual Platform 模型
│   └── juno/                     # Juno 开发板
├── hisilicon/                    # 海思平台
│   └── hikey960/                 # HiKey960 开发板
├── mediatek/                     # 联发科平台
│   └── mt8173/                   # MT8173 SoC
├── nvidia/                       # 英伟达平台
│   └── tegra/                    # Tegra SoC 系列
├── rockchip/                     # 瑞芯微平台
│   ├── common/                   # Rockchip 通用代码
│   ├── rk3328/                   # RK3328 SoC
│   └── rk3399/                   # RK3399 SoC
└── st/                           # STMicroelectronics 平台
    └── stm32mp1/                 # STM32MP1 系列

每个平台目录下必须实现 platform.mk 和一系列以 plat_ 开头的 C 文件,用于定义内存布局、电源管理、中断控制器等硬件参数。

3.5 依赖关系总结图

下图以模块依赖的视角,展示了各目录之间的编译与运行时依赖关系。

ATF 目录依赖关系图 ATF 目录依赖关系图 bl1 bl2 bl31 bl32 common plat 图例 运行时加载依赖 编译/链接依赖 所有 BL 都依赖 common 和 plat bl31 负责跳转到 bl32

3.6 编译与链接依赖

在构建系统中,依赖关系通过 Makefile 和链接脚本体现。以下是各 BL 阶段与 common、plat 的编译依赖示例:

# 以 bl31 的 Makefile 片段为例
BL31_SOURCES += $(COMMON_DIR)/bl_common.c
BL31_SOURCES += $(COMMON_DIR)/tlb.c
BL31_SOURCES += $(PLAT_DIR)/plat_psci.c
BL31_SOURCES += $(PLAT_DIR)/plat_topology.c

# 链接时,bl31.elf 需要链接 libcommon.a 和平台对象
$(BUILD_DIR)/bl31/bl31.elf: $(BL31_OBJS) $(COMMON_LIB) $(PLAT_LIB)
	$(LD) -o $@ $^ -T $(LINKER_SCRIPT)
移植注意事项: 在添加新平台时,必须确保 plat 目录下实现了所有被 BL1、BL2、BL31 调用的平台接口。遗漏任何一个 plat_ 函数都会导致链接失败。建议从 ARM 官方参考平台(如 FVP)复制一份,然后逐步替换硬件相关代码。

3.7 启动流程中的关键函数调用链

为了更直观地理解目录间的协作,下表列出了从 BL1 到 BL33 的关键函数调用及其所属目录。

阶段 关键函数 所属目录 功能描述
BL1 bl1_main() bl1 BL1 主入口,初始化控制台、内存、加载 BL2
BL1 plat_get_my_entrypoint() plat 获取当前 CPU 的入口点(用于多核启动)
BL2 bl2_main() bl2 BL2 主入口,解析镜像列表,加载后续阶段
BL2 load_image() common 从存储介质加载镜像到内存
BL31 bl31_main() bl31 BL31 主入口,初始化运行时服务、PSCI、中断
BL31 psci_setup() bl31 初始化电源管理状态机
BL31 el3_exit() common 从 EL3 退出到非安全世界
BL32 opteed_setup() bl32 初始化 OP-TEE 安全 OS

通过以上分析可以看出,ATF 的源码结构清晰地将安全启动的各个阶段解耦,common 提供共享基础设施,plat 封装硬件差异,使得开发者可以专注于特定阶段的优化而不影响其他模块。