文章目录
- [1 概要](#1 概要)
- [2 STM32MP1 中的 TF-A](#2 STM32MP1 中的 TF-A)
-
- [2.1 STM32MP1 TF-A 框架](#2.1 STM32MP1 TF-A 框架)
- [2.1 STM32MP1 下的 bl1](#2.1 STM32MP1 下的 bl1)
- [2.2 STM32MP1 下的 bl2](#2.2 STM32MP1 下的 bl2)
- [2.3 STM32MP1 下的 bl32](#2.3 STM32MP1 下的 bl32)
- [2.4 STM32MP1 下的 bl33](#2.4 STM32MP1 下的 bl33)
- [3 STM32MP1 TF-A 镜像存储映射](#3 STM32MP1 TF-A 镜像存储映射)
- [4 总结](#4 总结)
- [5 其余章节](#5 其余章节)
1 概要
TF-A 的详细运行过程是很复杂的,涉及到很多 ARM 处理器底层知识,本章我们主要讲解一下 TF-A 的整个框架,了解一下 TF-A 运行的大致流程。
本章节将会分为三个章节进行讲解:
(1)设备安全怎么保证
(2)TF-A 概述
(3)STM32MP1 中的 TF-A
2 STM32MP1 中的 TF-A
2.1 STM32MP1 TF-A 框架
STM32MP1 支持 TrustZone,所以 ST 提供的软件包包含了安全固件。相比传统 ARM 处理器(如 ARM9,ARM11 等)最常见的 uboot 和 linux kernel,STM32MP1 的软件包还另外提供了TF-A、OP-TEE 等安全相关的关键软件,因此 STM32MP1 的整体软件框架必然和传统的 ARM芯片不同,STM32MP1 软件架构如图 7.3.1.1 所示:

图 7.3.1.1 从左到右分为三部分:Cortex-A7 Secure、Cortex-A7 Non-Secure 和 Cortex-M4,Cortex-M4 本教程不涉及。所以就剩下了 Cortex-A7 Secure、Cortex-A7 Non-Secure,也就是 A7的安全和非安全两种情况。
在 Cortex-A7 Secure 下重点是 TF-A 和 OP-TEE,TF-A 是用于完成安全启动的,OP-TEE 是TEE OS,如果使用 OP-TEE 的话它会和 linux 内核同时运行,OP-TEE 负责可信应用,linux 就是普通的应用程序。在 Cortex-A7 Non-Secure 下就是传统的 ARM 软件框架:uboot、linux kernel和根文件系统。
前面我们讲了,TF-A 分为了不同阶段:bl1、bl2、bl31、bl32 和 bl33,这个主要是面向 AArch64的,对于 AArch32 而言只有 4 个阶段:
**bl1:**第 1 个阶段,一般为芯片内部 ROM 代码。
**bl2:**第 2 个阶段,可信启动固件。
**bl32:**EL3 运行时(Runtime)软件,即安全固件,bl32 一般为安全系统(TEE OS)固件,比如 OP-TEE。TF-A 为 AArch32 提供了 EL3 的 Runtime软件,这个 Runtime 软件就是 bl32 固件,sp_min 就是这个 Runtime 软件。。
**bl33:**非安全固件,比如 uboot。
其中 bl1、bl2 和 bl32 都属于 TF-A 的一部分(如果你使用 TF-A 提供的 bl1 的话)。
---------------------------------回顾第一章节中AArch64的主要启动过程

从图 7.2.3.1 可以看出,当芯片复位以后首先运行 bl1 代码,bl1 一般是芯片内部的 ROM 代码,要做的就是初始化 CPU,如果芯片支持不同的启动设备,那么还需要初始化不同的启动设置,比如 NAND、EMMC、SD、USB 或串口等,初始化后将外置 Flash (EMMC等) 中的 bl2 固件加载到指定的 RAM 中,然后跳转到 bl2 部分。
bl2 为安全启动固件,bl2 会初始化 DDR、MMU、串口等,将剩余的三个启动阶段 bl31、bl32 和 bl33 对应的镜像文件加载到指定的内存中。比如 bl32 中的安全操作系统(OP-TEE),bl31 中的 EL3 (Secure Monitor)运行时固件(Runtime Firware),bl33 中的 uboot。bl2 将这些固件加载完成以后就会启动相应的固件,也就是进入到第三启动阶段。
TF-A 启动流程就是:bl1→ bl2→( bl31/ bl32/ bl33)。注意,bl31、bl32 和 bl33 对应的镜像不需要全部都有,但是 bl33 一般是必须的,因为 bl33 一般是 uboot,这个是很重要的!
------------------------------------------回顾完毕
2.1 STM32MP1 下的 bl1
bl1 部分是可选的,在编译 STM32MP1 的 TF-A 的时候可以通过添加 BL2_AT_EL3 编译选项来移除 bl1,默认情况下 ST 提供的 TF-A 源码是有添加 BL2_AT_EL3 编译选项的,在 TF-A源码里面找到 tf-a-stm32mp-2.2.r1/plat/st/stm32mp1/platform.mk,此文件定义了 STM32MP1 这个平台的编译选项,有如图 7.3.1.2 所示配置项:

从图 7.3.1.2 可以看出,platform.mk 文件定了 BL2_AT_EL3 为 1,因此在编译 STM32MP1平台对应的 TF-A 的时候不会编译 bl1 部分,STM32MP1 内部 ROM 代码完成了 TF-A 中的 bl1部分的工作,主要就是将外部 Flash 中的 bl2 代码加载到内部 RAM 中并运行。
2.2 STM32MP1 下的 bl2
bl2 为可信启动固件,在 STM32MP1 中就是 TF-A 的 bl2 部分,bl2 的主要功能就是加载下面几个阶段的固件到内存中,因此 bl2 需要初始化所要用到的外设。
首先是安全部分,STM32MP1 的 bl2 部分会初始化的外设如下:
①、BOOT、安全和 OTP 控制器,也就是 BSEC 外设。
②、扩展的 TrustZone 保护控制器,也就是 ETZPC 外设。
③、TrustZone 针对 DDR 的地址空间保护控制器,也就是 TZC 外设。
由于 bl2 需要从外部 flash 中加载下一阶段的镜像,因此还需要初始化一些外部 flash,比如:
(注意,因为bl1阶段没有初始化DDR这些,因此只能将外部flash的bl2代码加载到内部256kb的RAM中运行,运行后主要用于如下的操作:初始化基础外设cpu等,运行bl2,bl2会初始化SD,EMMC,DDR等)
①、SD 卡。
②、EMMC。
③、NAND。
④、NOR。
最后,STM32MP1 的 bl2 部分还要初始化一些其他的外设,比如:
①、DDR 内存。
②、时钟。
③、串口,用于调试以及使用 STM32CubeProgrammer 的时候通过串口下载系统。
④、USB,用 STM32CubeProgrammer 通过 USB 烧写系统的时候需要用到。
bl2 还需要对镜像镜像进行验证和鉴权,鉴权是通过调用内部 ROM 代码的鉴权服务来完成。最后,bl2 会加载 bl32 和 bl33 的固件到指定的内存区域,并跳转到 bl32,bl32 接着运行。
2.3 STM32MP1 下的 bl32
bl32 提供运行时安全服务,在 TF-A 中默认使用 sp_min,sp_min 已经在前面提过了。sp_min是一个最小的 AArch32 安全负载(Secure Payload),整合了 PSCI 库以及 AArch32 的 EL3 运行时软件。sp_min 可以替代可信系统(TEE OS)或者可信执行环境(TEE),比如 OP-TEE。当然了,STM32MP1 同时支持 sp_min 以及 OP-TEE,用户可以自行选择 bl32 使用哪个软件包,为了方便讲解,本教程选择 sp_min。
bl32 充当安全监控(secure monitor),因此它向非安全系统(non-secure os,比如 linux)提供了一些安全服务。非安全的应用软件可以通过安全监控调用(secure monitor calls)来使用这些安全服务,这些代码支持标准的服务调用,比如 PSCI。
另外,bl32也支持ST32MP1所特有的一些安全服务,可以访问特有的安全外设,比如RCC、PWR、RTC 或 BSEC。
2.4 STM32MP1 下的 bl33
bl33 没什么好说的了,就是传统的 uboot,并不属于 TF-A 本身。
简单总结一下,默认情况下 TF-A 有 bl1、bl2、bl31、bl32 和 bl33 这几个启动阶段。如果bl32 使用 sp_min 的话那么 bl1、bl2、bl31 和 bl32 都属于 TF-A。但是对于 STM23MP1 而言,因为其使用的是 AArch32,因此没有 bl31 部分。而 bl1 部分 ST 又没有用 TF-A 提供的,采用的是STM32MP1 内部 ROM 代码(前面提到过,编译的时候宏定义写1,官方TF-A固件就不会编译bl1代码),因此就只剩下了 bl2 和 bl32。所以对于 STM32MP1 而言,TF-A就两个固件:bl2 和 bl32(sp_min),TF-A 源码也采用了设备树(device tree)来设备信息,因此对于 STM32MP1 而言,TF-A 一共有三部分:设备树、bl2 和 bl32,这三部分在编译的时候会被合并成一个二进制文件。当然了,还要在最前面加上重要的头部信息,最终这 4 部分就组成了我们烧写到外部 flash中的TF-A 镜像,比如我们 6.2.3小节中烧写到 EMMC中的 tf-a-stm32mp157d-atk-trusted.stm32,其文件结构如图7.3.1.3 所示:

STM32MP1 的 TF-A 启动流程如图 7.3.1.4 所示:

图 7.3.1.4 中 TF-A 启动分了 5 步,这 5 步的含义如下:
1、复位以后内部 ROM 加载 TF-A 整个镜像,然后运行 bl2 镜像。
2、bl2 将 bl32 镜像加载到指定内存区域。
3、bl2 将 bl33 镜像加载到指定内存区域。
4、bl2 执行完毕以后就会跳转到 bl32 镜像。
5、bl32 镜像执行完以后跳转到 bl33 镜像,也就是 uboot。
最后,uboot 引导非安全系统,也就是 linux 内核。
3 STM32MP1 TF-A 镜像存储映射
上一小节讲了,我们最终烧写到 STM32MP1 里面的 TF-A 镜像有 4 部分,除去头部信息,还有设备树、bl2 和 bl32。这 3 部分虽然在"肉体"上被打包在了一起,但是"灵魂"上是三部分,比如 bl2 是一个镜像,bl32 是另外一个镜像,其执行顺序都是不一样的!当加载到内存上以后这 3 部分的存储映射如图 7.3.2.1 所示:

图 7.3.2.1 中 TF-A 各部分存储映射不是固定的,编译 TF-A 的时候配置不同,其存储地址也不同。比如图 7.3.2.1 中 BL32 的起始地址为 0x2FFED000,大家在看其他资料的时候可能是别的地址,这个没关系的,重点是其存储映射形式。
4 总结
关于 TF-A 的基础知识就讲解到这里,大家基本对 TF-A 有了一个初步的了解,也了解了STM32MP1 中的 TF-A 组织形式,方便我们后续学习。
5 其余章节
【正点原子STM32MP157 可信任固件TF-A学习篇】(1) TF-A 概述
【正点原子STM32MP157 可信任固件TF-A学习篇】(2) STM32MP1 中的 TF-A