【DeepSeek】Trusted Firmware-A 加载 U-Boot 过程详解
·
Trusted Firmware-A 加载 U-Boot 过程详解
本文档详细描述了 Trusted Firmware-A (TFA) 如何加载 U-Boot 的完整过程,基于 bitmain/bm1684 平台的实现。
1. 引导流程概述
TFA 采用分阶段引导的方式,从 BL1 到 BL2,再到 BL31,最终跳转到 BL33(U-Boot)。整个流程如下:
- BL1:从 SPI Flash 加载,初始化基本硬件,然后加载 BL2 到安全 SRAM
- BL2:加载 BL31(EL3 运行时)和 BL33(U-Boot,非安全)到指定内存位置
- BL31:初始化 EL3 运行时环境,然后跳转到 BL33(U-Boot)
- BL33:U-Boot 启动,继续引导操作系统
2. 关键组件和文件
2.1 主要代码文件
- bl2/bl2_main.c:BL2 的主函数,协调镜像加载过程
- bl2/bl2_image_load_v2.c:实现
bl2_load_images()函数,负责加载 BL31 和 BL33 - plat/bitmain/bm1684/bm_bl2_mem_params_desc.c:定义 BL33(U-Boot)的加载参数
- plat/bitmain/bm1684/include/platform_def.h:定义内存布局和地址偏移
- bl31/bl31_main.c:BL31 主函数,负责初始化并跳转到 BL33
2.2 内存布局
根据 platform_def.h 的定义,相关内存布局如下:
| 内存区域 | 基地址 | 大小 | 用途 |
|---|---|---|---|
| NS_DRAM_BASE | 0x300000000 | 256MB | 非安全 DRAM 基地址 |
| NS_IMAGE_OFFSET | 0x308000000 | - | U-Boot 加载地址(偏移 128MB) |
| NS_IMAGE_MAX_SIZE | 0x8000000 | 128MB | U-Boot 最大大小 |
| BL31_BASE | 0x300000000 | 256KB | BL31 加载地址 |
3. 详细加载过程
3.1 BL2 加载 BL33(U-Boot)
-
BL2 主函数执行:
- 在
bl2_main()函数中,调用bl2_load_images()加载后续镜像
- 在
-
获取镜像加载信息:
bl2_load_images()调用plat_get_bl_image_load_info()获取镜像加载信息- 对于 BM1684 平台,此函数会将镜像描述符复制到安全位置
-
遍历并加载镜像:
- 遍历
bl2_mem_params_descs数组中的每个镜像 - 对于 BL31(安全镜像)和 BL33(非安全镜像),执行加载操作
- 遍历
-
BL33 加载配置:
在bm_bl2_mem_params_desc.c中,BL33 的配置如下:{ .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.pc = NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = NS_IMAGE_OFFSET, .image_info.image_max_size = NS_IMAGE_MAX_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, } -
执行加载:
- 调用
load_auth_image()加载 BL33 镜像到NS_IMAGE_OFFSET地址 - 执行平台特定的后处理操作
bl2_plat_handle_post_image_load()
- 调用
-
准备跳转参数:
- 调用
plat_get_next_bl_params()获取传递给下一个镜像的参数 - 刷新参数到内存,确保下一个镜像可以访问
- 调用
-
跳转到 BL31:
- BL2 完成加载后,跳转到 BL31 执行
3.2 BL31 跳转到 BL33(U-Boot)
-
BL31 初始化:
- 在
bl31_main()函数中,执行平台初始化、运行时服务初始化等操作
- 在
-
准备跳转到下一个镜像:
- 调用
bl31_prepare_next_image_entry()准备跳转到 BL33
- 调用
-
获取 BL33 入口信息:
- 调用
bl31_plat_get_next_image_ep_info(NON_SECURE)获取 BL33 的入口点信息 - 验证入口点信息的安全性状态
- 调用
-
配置 EL3 退出:
- 调用
cm_init_my_context(next_image_info)初始化上下文 - 调用
cm_prepare_el3_exit_ns()准备从 EL3 退出到非安全世界
- 调用
-
执行 ERET 指令:
- 执行 ERET 指令,跳转到 BL33(U-Boot)的入口点
- U-Boot 开始执行
4. 关键函数调用链
4.1 BL2 加载流程
bl2_main()
└── bl2_load_images()
├── plat_get_bl_image_load_info()
│ └── get_bl_load_info_from_mem_params_desc()
├── load_auth_image(BL31_IMAGE_ID, ...)
├── load_auth_image(BL33_IMAGE_ID, ...)
├── plat_get_next_bl_params()
│ └── get_next_bl_params_from_mem_params_desc()
├── plat_flush_next_bl_params()
└── return next_bl_ep_info (指向 BL31)
4.2 BL31 跳转流程
bl31_main()
├── bl31_platform_setup()
├── runtime_svc_init()
├── bl31_prepare_next_image_entry()
│ ├── bl31_get_next_image_type() (返回 NON_SECURE)
│ ├── bl31_plat_get_next_image_ep_info(NON_SECURE)
│ ├── cm_init_my_context(next_image_info)
│ └── cm_prepare_el3_exit_ns()
└── 执行 ERET 跳转到 BL33
5. 配置和定制
5.1 内存布局配置
U-Boot 的加载地址和大小可以通过修改 platform_def.h 中的以下宏来调整:
NS_IMAGE_OFFSET:U-Boot 的加载地址NS_IMAGE_MAX_SIZE:U-Boot 的最大大小
5.2 镜像加载配置
BL33 的加载参数可以在 bm_bl2_mem_params_desc.c 中修改,包括:
- 入口点地址
- 镜像基地址
- 镜像最大大小
- 安全状态标记
6. 调试和排错
6.1 常见问题
-
U-Boot 加载失败:
- 检查
NS_IMAGE_OFFSET是否正确 - 确认 U-Boot 镜像大小不超过
NS_IMAGE_MAX_SIZE - 检查 SPI Flash 中的 U-Boot 镜像是否正确
- 检查
-
跳转失败:
- 检查 BL33 的入口点地址是否正确
- 确认 BL31 到 BL33 的参数传递是否正确
-
内存冲突:
- 确保 BL31 和 BL33 的内存区域不重叠
- 检查其他组件是否使用了相同的内存区域
6.2 调试技巧
- 在 BL2 和 BL31 中添加调试信息,输出镜像加载的详细过程
- 使用 JTAG 调试器跟踪引导过程
- 检查 U-Boot 的反汇编代码,确认入口点逻辑正确
7. 总结
TFA 加载 U-Boot 的过程是一个精心设计的多阶段引导流程,确保了系统的安全性和可靠性。通过 BL2 加载 BL33 到指定内存位置,然后由 BL31 负责安全地跳转到 U-Boot,整个过程实现了从安全世界到非安全世界的平稳过渡。
这种设计不仅提供了安全的引导环境,还为 U-Boot 和后续的操作系统启动做好了充分准备,是现代 ARM 系统引导架构的重要组成部分。
更多推荐


所有评论(0)