15. TF-A的介绍与编译¶
Trusted Firmware-A 是Arm提供的安全世界软件的参考实现。它最初是为 Armv8-A 平台设计的,并已被 STMicroelectronics 调整为在 Armv7-A 平台上使用。Trusted Firmware-A 是 Trusted Firmware 项目的一部分,该项目是由 Linaro 托管的开放治理社区项目。
当使用可信引导链时,它被用作STM32 MPU平台上的第一阶段引导加载程序(FSBL)。
15.1. 获取TF-A源码¶
TF-A官网: https://www.trustedfirmware.org/
野火TF-A仓库: https://gitee.com/Embedfire/ebf_linux_tfa/tree/ebf_2.0-r0_star/
注意:本教程以野火提供的TF-A源码为分析样本
1 2 | #使用-b参数指定ebf_2.0-r0_star分支
git clone -b ebf_2.0-r0_star https://gitee.com/Embedfire/ebf_linux_tfa.git
|
15.2. TF-A工程结构分析¶
学习一个软件,尤其是开源软件,首先应该从分析软件的工程结构开始。一个好的软件有良好的工程结构,对于读者学习和理解软件的架构以及工作流程都有很好的帮助。
TF-A的源代码布局和我们讲的Linux内核源码类似,使用了按照模块划分的结构,并且充分考虑了体系结构和跨平台问题,其源代码树结构请参考下图
目录/文件 |
说明 |
---|---|
bl1、bl2、bl31、bl32 |
包含了TF-A 的不同阶段的引导加载程序的代码。 |
common |
公共的代码,可以被各个部分共享使用。 |
drivers |
包含了设备驱动程序的代码,用于与处理器和外设进行交互。 |
docs |
包含了项目的文档,包括用户手册、开发者指南等 |
include |
包含了一些头文件。 |
lib |
包含了一些通用的库函数或者工具函数。 |
Makefile、Makefile.sdk |
用于构建项目的 Makefile 文件,定义了编译、链接和构建过程中的规则和命令。 |
plat |
包含了针对特定平台的代码或者配置。 |
services |
包含了一些辅助工具,用于项目的构建、调试等。 |
maintainers.rst |
维护者指南文件,记录了项目的维护者联系信息等。 |
dco.txt、license.rst、readme.rst |
包含了项目的许可证信息、开发者签署协议等重要说明。 |
15.3. TF-A 不同启动阶段¶
对于32位Arm处理器,可信启动分为四个阶段(按执行顺序):
引导加载程序阶段1 (BL1)应用程序处理器信任的ROM
引导加载程序阶段2 (BL2)可信引导固件
引导加载程序阶段3-2 (BL32)可信运行时固件
引导加载程序阶段3-3 (BL33)不受信任的固件
其中BL1和BL2是TF-A的一部分,BL32可以在TF-A内也可以在TF-A外(例如OP-TEE)。
由于STM32 MPU平台使用专用的ROM代码,因此删除了BL1引导阶段。
BL33在TF-A之外。这是TF-A加载的第一个非安全代码。在引导序列中,这是二级引导加载程序(SSBL)。对于STM32 MPU平台,SSBL默认为U-Boot。
TF-A可以通过设备树进行配置管理。在BL2阶段,它是Linux内核的简化版本,在引导过程中只使用所需的设备。
TF-A加载步骤:
ROM代码加载并调用BL2
BL2装载BL32
BL2装载BL33
BL2呼叫BL32
BL32呼叫BL33
15.3.1. BL1¶
BL1是执行的第一阶段,被设计为ROM代码,它在内部RAM中加载和执行。它不用于STM32 MPU,由于STM32 MPU有自己的专有ROM代码,可以删除该部分,然后BL2是第一个要执行的TF-A二进制文件。
15.3.2. BL2¶
BL2负责加载下一阶段的固件(安全和非安全)。要实现这个任务,BL2必须初始化所有必需的外设。
系统组件:时钟,DDR,…
安全组件:加密外设,内存防火墙,…
存储
BL2提供了不同的功能来加载和验证固件。
在其执行结束时,在加载了BL32和下一个引导阶段(BL33)之后,BL2跳转到BL32。
15.3.3. BL32¶
BL32提供运行时安全服务。
在Armv7架构上,BL32必须嵌入安全监视器,因为它将在相同的特权级别(PL1-SVC安全)中执行。
BL32作为安全监视器,为不安全的操作系统提供安全服务。这些服务由带有安全监视器调用的非安全软件调用。
参考资料:
https://wiki.stmicroelectronics.cn/stm32mpu/wiki/TF-A_overview
15.4. 编译TF-A源码¶
进入TF-A源码顶层目录,执行以下命令进行编译。
1 2 | #-f指定使用Makefile.sdk
make -f Makefile.sdk all
|
如果编译成功,输出信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | make[1]: Entering directory '/home/hyw/157/ebf-image-builder/ebf_linux_tfa'
Including bl32/sp_min/sp_min.mk
make[2]: Nothing to be done for 'all'.
AS plat/st/stm32mp1/stm32mp1.S
LDS plat/st/stm32mp1/stm32mp1.ld.S
LDS /home/hyw/157/ebf-image-builder/ebf_linux_tfa/build/trusted/stm32mp1.o
Built /home/hyw/157/ebf-image-builder/ebf_linux_tfa/build/trusted/tf-a-stm32mp157a-star.bin successfully
Generated /home/hyw/157/ebf-image-builder/ebf_linux_tfa/build/trusted/tf-a-stm32mp157a-star.stm32
tools/stm32image/stm32image -s /home/hyw/157/ebf-image-builder/ebf_linux_tfa/build/trusted/tf-a-stm32mp157a-star.bin -d /home/hyw/157/ebf-image-builder/ebf_linux_tfa/build/trusted/tf-a-stm32mp157a-star.stm32 -l 0x000000002ffc2500 -e 0x000000002ffd8000 -v 0
Image Type : ST Microelectronics STM32 V1.0
Image Size : 245128 bytes
Image Load : 0x2ffc2500
Entry Point : 0x2ffd8000
Checksum : 0x00eaa04d
Option : 0x00000001
Version : 0x00000000
Building stm32mp1
make[1]: Leaving directory '/home/hyw/157/ebf-image-builder/ebf_linux_tfa'
|
编译会生成build目录,其中build目录下的trusted目录保存了编译生成的MP1所有型号的TF-A固件,野火使用的固件为:tf-a-stm32mp157a-star-trusted.stm32
15.5. TF-A固件烧录¶
如果是SD镜像,请编译完整镜像然后烧录到SD卡进行启动。
如果是usb镜像,替换usb烧录包stm32mp157_release_xxx/stm32mp157-cubeprogrammer/目录下的tf-a-stm32mp157a-star-trusted.stm32,然后烧录到emmc中进行启动。
15.6. TF-A启动信息分析¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | NOTICE: CPU: STM32MP157AAC Rev.Z
NOTICE: Model: STMicroelectronics STM32MP157A-DK1 Discovery Board
INFO: Reset reason (0x15):
INFO: Power-on Reset (rst_por)
INFO: Using EMMC
INFO: Instance 2
INFO: Boot used partition fsbl1
NOTICE: BL2: v1.6-r3.0(debug):d64a19a
NOTICE: BL2: Built : 15:17:50, Feb 3 2021
INFO: BL2: Doing platform setup
INFO: RAM: DDR3-1066/888 bin G 2x4Gb 533MHz v1.45
INFO: Memory size = 0x40000000 (1024 MB)
INFO: BL2 runs SP_MIN setup
INFO: BL2: Loading image id 4
INFO: Loading image id=4 at address 0x2ffef000
INFO: Image id=4 loaded: 0x2ffef000 - 0x30000000
INFO: BL2: Loading image id 5
INFO: Loading image id=5 at address 0xc0100000
INFO: STM32 Image size : 823559
WARNING: Skip signature check (header option)
INFO: Image id=5 loaded: 0xc0100000 - 0xc01c9107
NOTICE: BL2: Booting BL32
INFO: Entry point address = 0x2ffef000
INFO: SPSR = 0x1d3
INFO: Cannot find st,stpmic1 node in DT
NOTICE: SP_MIN: v1.6-r3.0(debug):d64a19a
NOTICE: SP_MIN: Built : 15:17:50, Feb 3 2021
INFO: ARM GICv2 driver initialized
INFO: stm32mp HSE (20): Secure only
INFO: stm32mp PLL2 (27): Secure only
INFO: stm32mp PLL2_R (30): Secure only
INFO: SP_MIN: Initializing runtime services
INFO: SP_MIN: Preparing exit to normal world
U-Boot 2018.11-stm32mp-r4-g569038fc (Feb 11 2022 - 03:03:27 +0000)
CPU: STM32MP157AAC Rev.Z
Model: STMicroelectronics STM32MP157A-DK1 Discovery Board
Board: stm32mp1 in trusted mode (st,stm32mp157a-dk1)
DRAM: 1 GiB
|
第1行,使用的CPU型号是STM32MP157AAC,Rev.Z表示某个修订版本。
第2行,开发板型号是STMicroelectronics的STM32MP157A-DK1 Discovery Board。
第3行到第4行,系统复位的代码为0x15,复位的具体原因是上电复位。
第5行到第6行,正在使用EMMC作为存储设备,通道2。
第7行,启动过程中使用了名为“fsbl1”的分区通常是一个引导加载程序(Boot Loader)分区。
第8行到第9行,BL2版本、构建时间。
第10行,BL2正在执行平台设置。
第11行到第12行,使用的RAM类型是DDR3,速度533MHz,容量为2x4Gb(8Gb),版本为v1.45,换算GB为1024MB(1GB)。
第13行,BL2正在运行一个名为“SP_MIN”的设置或配置。
第14行到15行,BL2正在加载一个标识为“id 4”的镜像,被加载到内存地址0x2ffef000。
第16行,镜像id 4已加载,并占用了从0x2ffef000到0x30000000的内存空间。
第17行到第21行,BL2正在加载另一个标识为“id 5”的镜像。加载镜像id 5时跳过了签名检查。加载到内存地址0xc0100000到0xc01c9107。
第22行,BL2正在启动BL32。
第23行,BL32的入口点地址是0x2ffef000。
第24行,ARM处理器相关的特殊程序状态寄存器(SPSR)的值
第25行,在设备树中找不到名为“st,stpmic1”的节点。
第26行到27行,SP_MIN的版本信息,构建时间。
第28行,ARM Generic Interrupt Controller (GIC) v2的驱动程序已初始化。GIC是ARM架构中用于处理中断的组件。
第29行,HSE(High Speed Ethernet)接口在20MHz的频率下仅用于安全环境。
第30行,PLL2(Phase-Locked Loop 2)在27MHz的频率下仅用于安全环境。PLL通常用于生成时钟信号。
第31行,PLL2_R(PLL2的某种派生或分频)在30MHz的频率下也仅用于安全环境。
第32行,SP_MIN正在初始化运行时服务,这些服务可能在后续的正常世界操作中使用。
第33行,SP_MIN正在准备退出到正常环境。
第36行,U-Boot的版本信息,包括版本号、针对STM32MP的修改和构建时间。