TF-A
文章目录
一、概述
在上一节中,我们已经简单介绍过了TF-A
TF-A
是一个开源的、可信赖的固件层,旨在为ARM Cortex-A
处理器系列提供安全启动、初始化和运行时支持。在启动流程中,TF-A
最先启动,它负责系统引导和硬件初始化。在上一节启动流程中我们已经讲过,在安全启动(Secure boot)模式下,在嵌入式Linux启动链条(Boot chain)中,TF-A
经常作为FSBL来对硬件进行鉴权(authentication)。
二、TF-A的使用
1. 源码下载
从以上描述可以知道,TF-A是开源的,所有人都可以下载使用,但事实上,作为普通开发者,我们不太可能凭借一己之力来使用TF-A,这样的开发难度太大了。所以,TF-A源码大多是供半导体厂商使用,他们会对其进行修改,将自己的芯片产品添加进去。我们在实际的项目开发时,只需要使用半导体厂商提供的TF-A源码即可,意法半导体为开发者提供的是一个开发包:STM32MP1 OpenSTLinux Developer Package
意法半导体官方提供三种开发开发包:
选项 | 简介 |
---|---|
STM32MP1Dev | STM32MP1Dev 代表了STM32MP1开发板,这个SDK可以帮助开发者快速入门并熟练掌握STM32MP1系列芯片的各项特性和应用方法,我们需要下载这个SDK |
Yocto_SDKaarch64 | 是一个针对ARM架构aarch64 的SDK,适用于基于Yocto Project 构建的STM32MP1 Linux发行版 |
Yocto_SDKx86 | 可在x86架构的计算机上使用,用于基于Yocto Project 构建的STM32MP1 Linux发行版 |
2. 源码打补丁
下载好STM32MP1Dev后解压缩,我们可以看到在\stm32mp1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21\sources\arm-ostl-linux-gnueabi
目录下有名为tf-a-stm32mp-v2.8.6-stm32mp-r1-r0
的文件夹,这就是ST官方提供的TF-A固件目录,在其中有几个文件:
文件 | 简介 |
---|---|
0001-v2.8-stm32mp-r1.patch | ST官方提供的TF-A补丁文件 |
Makefile.sdk | 编译TF-A时使用的Makefile文件 |
README.HOW_TO.txt | ST官方的README文档 |
series | 存放补丁名称的文件 |
tf-a-stm32mp-v2.8.6-stm32mp-r1-r0.tar.xz | TF-A源码压缩包 |
在开头我们已经说过,各大半导体厂商需要修改TF-A源码,将自己的芯片产品添加进去,才能正常编译和使用TF-A。打补丁的过程在正点原子的驱动开发手册中已经说的很详细了,在此不再赘述。
3. 编译TF-A
在虚拟机Ubuntu18.04中,打开终端,输入以下指令
进入刚才的tf-a-stm32-2.2.r1
目录:
cd tf-a-stm32mp-2.2.r1/
使用上一层目录中的Makefile.sdk编译此目录中的内容:
make -f …/Makefile.sdk all
编译完成后,会在上一层目录生成一个build
目录,其中包含三个子目录:optee
、serialboot
和trusted
,那么Makefile.sdk中到底有什么内容,它们分别起什么作用呢?让我们具体看一看。
三、TF-A的Makefile.sdk
1. #remove default variables
在Makefile.sdk
的开头,使用#remove default variables
来说明了需要清除掉的变量内容,没有太多意义
#//此部分通常用来注释掉默认变量或清除之前的定义内容。
#remove default variable
LDFLAGS=
CFLAGS=
CPPFLAGS=
CC=
CPP=
AS=
AR=
LD=
NM=
2. 编译路径和EXTRA_OEMAKE
在此之后,在Makefile中指定了编译路径:
#// PWD 是目前所在目录路径,将其赋值给LOCAL_PATH,作用是指定编译路径
LOCAL_PATH=$(PWD)
下面一部分,我们主要聚焦于EXTRA_OEMAKE
这个变量。在TF-A
的makefile
中,EXTRA_OEMAKE
是一个环境变量,用于指定编译参数和目标环境配置。例如,在不同平台上可能需要针对 CPU 类型、内存大小等因素进行额外的编译配置。在这种情况下,我们可以通过设置EXTRA_OEMAKE
这个变量来传递相应参数,并执行make
命令时就能获得针对性的编译结果。具体的EXTRA_OEMAKE
内容取决于目标平台的需求和项目要求。
此外,EXTRA_OEMAKE
变量也可以用于设定一些自定义编译选项,比如打开或关闭某个功能模块等等。总之,在TF-A
编译过程中,我们可以根据实际需求为EXTRA_OEMAKE
设置合适的值,以便于得到更符合期望的编译结果。
#// 这一部分给EXTRA_OEMAKE赋予了更加具体的设定,比如CROSS_COMPILE指定了具体的交叉编译器, \
这里使用的是正点原子教程中指定的arm-none-linux-gnueabihf,arm代表是arm官方发布的, \
none表示没有特殊的备注,linux表示适用于linux系统,gnueabihf规定了具体的编译方式, \
这里的hf表示hard float。当然,我们也可以使用linaro发行的交叉编译器。DEBUG置1,表示debug模式开启, \
PLAT指定了具体的平台,ARCH指定了具体的架构,ARM_ARCH_MAJOR指定了aarch的版本号。
#// 之后的STM32MP_SDMMC、STM32MP_EMMC、STM32MP_SPI_NOR、STM32MP_RAW_NAND和 \
STM32MP_SPI_NAND几条命令,针对的是 STM32MP1 处理器中集成的各种接口所对应的功能模块, \
将其都置为1,那么编译器会引入与其对应的相关代码和库,以便在生成的固件中支持这些接口 \
(SD卡、EMMC、NOR、NAND)。
EXTRA_OEMAKE=CROSS_COMPILE=arm-none-linux-gnueabihf- DEBUG=1 LOG_LEVEL=40 PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_SPI_NOR=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1
#// 此段代码中的EXTRA_OEMAKE_SERIAL,是和串口相关的UART接口和USB接口, \
在编译过程中需要引入相关接口的功能。当这两个值都被置为1时,说明在当前编译配置下, \
TF-A 项目的编译结果将同时支持两种编程方式:UART 方式和 USB 方式。 \
用户可以根据自己的需要选择最合适的接口进行固件烧录。需要注意的是, \
在 STM32MP1 系列处理器开发过程中,有时可能会出现其他编程方式,如 JTAG 等。 \
在这种情况下,也需要适当调整 EXTRA_OEMAKE 变量的内容以适配这些接口。
EXTRA_OEMAKE_SERIAL= STM32MP_UART_PROGRAMMER=1 STM32MP_USB_PROGRAMMER=1
#// 此时我们编译的是TF-A,所以上面这一句是需要保留执行的,最终得到的是tf-a-xxxx-trusted.stm32文件, \
如果我们想得到和serialboot相关的内容,则需要将以上一句注释掉,转而执行下面的命令
#// 下面的代码也是和串口相关的,使用filte-out命令排除上述对于SD卡、EMMC、NOR和NAND的相关配置, \
只将UART和USB选项置为1,如此编译,将得到tf-a-xxxx-serialboot.stm32文件
EXTRA_OEMAKE_SERIAL=$(filter-out STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_SPI_NOR=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1,$(EXTRA_OEMAKE)) STM32MP_UART_PROGRAMMER=1 STM32MP_USB_PROGRAMMER=1
3. 默认设置
在这部分,Makefile设置了默认的配置选项
# Set default config
#// ELF_DEBUG_ENABLE 变量表示是否启用内建调试符号表,开发者可以选择在编译过程中是否添加调试符号表, \
从而控制编译后的固件大小和调试功能,这里的 ? 是bash扩展语法中的逻辑运算符,表示默认为1, \
如果编译过程中没有明确设置该变量,则按照默认值进行编译
#// TF_A_CONFIG 用于指定编译时所需的 TF-A 核心配置选项。TF-A 配置选项有许多种, \
例如内核版本、CPU 类型、固件压缩方式等等。编译成功后会在build目录中生成三个对应名称的文件夹
ELF_DEBUG_ENABLE ?= 1
TF_A_CONFIG ?= trusted optee serialboot
# Set specific OEMAKE config
#// TF_A_CONFIG_OEMAKE 变量表示 TF-A 配置选项的额外 OEM 参数, \
后面的trusted、optee和serialboot则指定了 OEM 参数的多个实例。
#// trusted,"AARCH32_SP=sp_min":这是为 trusted 组件配置的选项。在这里, \
AARCH32_SP 通常用于指定 TF-A 的安全世界组件(Security Partition)的类型, \
sp_min 表示安全世界的最小配置(minimum),这种配置也被称为最小安全层。
TF_A_CONFIG_OEMAKE = trusted,"AARCH32_SP=sp_min" optee,"AARCH32_SP=optee" serialboot,"AARCH32_SP=sp_min"
# Set default TFA_DEVICETREE
#// TFA_DEVICETREE 负责编译设备树文件,我们看到下列被注释掉的内容中包含了MP157系列的众多开发板, \
在后续编译是,如果保留它们,就会编译出很多对应的设备树文件,为了简化流程, \
我们只要求编译正点原子的设备树文件。
#TFA_DEVICETREE ?= stm32mp157d-atk stm32mp157a-dk1 stm32mp157d-dk1 stm32mp157c-dk2 stm32mp157f-dk2 stm32mp157c-ed1 stm32mp157f-ed1 stm32mp157a-ev1 stm32mp157c-ev1 stm32mp157d-ev1 stm32mp157f-ev1
TFA_DEVICETREE ?= stm32mp157d-atk
#Set default TF_A_ENABLE_DEBUG_WRAPPER
#// TF_A_ENABLE_DEBUG_WRAPPER 变量是一个开关标志,指示是否启用 Debug Wrappers 功能。 \
Debug Wrapper 是一种用于记录和传递调试信息的机制。它可以捕获处理器的状态、异常信息、 \
寄存器值和其他与调试相关的数据,并将这些数据传递给外部调试工具,如 JTAG 调试器或仿真器。 \
这对于分析嵌入式系统的问题、跟踪代码执行、查找故障和进行性能分析非常有用。
TF_A_ENABLE_DEBUG_WRAPPER ?= 1
4. help
使用Makefile文件时,开发者最初对编译的具体设置并不十分了解,这就需要一个模块来列举说明当前的编译配置,这就是help模块的作用,通过使用命令make help
,我们可以获取当前的编译配置。
help:
@echo
@echo "Available targets:"
@echo " all : build TF-A binaries for defined config(s)"
@echo " clean : clean build directories from generated files"
@echo
@echo "TF-A configuration:"
@echo " TF_A_CONFIG = $(TF_A_CONFIG)"
@echo " TFA_DEVICETREE = $(TFA_DEVICETREE)"
@echo " ELF_DEBUG_ENABLE = '$(ELF_DEBUG_ENABLE)' ('1' to export elf files)"
@echo " TF_A_ENABLE_DEBUG_WRAPPER = '$(TF_A_ENABLE_DEBUG_WRAPPER)' ('1' to generate tf-a for debugging)"
@echo
5. all
all 是一个构建目标(target)的名称。all 是一个常见的构建目标名称,如果没有明确指定其他目标,通常被定义为默认目标,在运行 make 命令时将会被构建。
在 TF-A 的 Makefile 中,all 通常代表构建整个 TF-A 固件,包括不同的组件和引导加载程序。构建 all 目标时,通常会触发一系列任务,以生成用于嵌入式系统引导的二进制文件。这些任务包括编译、链接、生成设备树二进制文件、生成引导映像等。
#// 在这里,all: tf意味着all的依赖项是tf
all: tf
#// host_tools 是一个变量,用于指定构建过程中需要在主机(开发计算机)上执行的工具。 \
这些工具通常用于生成或处理与 TF-A 构建相关的文件或数据。host_tools 变量列出了需要在主机上可用的工具, \
并在构建过程中使用这些工具来执行各种任务。
#// 之后的内容定义了 host_tools 目标的构建规则。它通过 $(MAKE) 命令在LOCAL_PATH目录中创建子目录/tools, \
并构建名为 stm32image 的文件。--no-print-directory 选项用于在构建过程中不显示子目录的构建信息, \
以保持输出内容的单一
host_tools:
@$(MAKE) --no-print-directory -C $(LOCAL_PATH)/tools/stm32image
#// 通过在构建规则中指定 tf: host_tools,Make 工具确保在构建 tf 目标之前,会执行构建 host_tools 目标。
tf: host_tools
#// 最外层的循环遍历了上文(3. 默认设置)中 TF_A_CONFIG 所有的值("trusted"、"optee"、"serialboot"), \
迭代 TF-A 配置中的不同选项。
for config in $(TF_A_CONFIG) ; do \
# Init any extraoemake \
# 此处对应了上文中的EXTRA_OEMAKE部分,初始化一个add_extraoemake 变量 \
add_extraoemake= ; \
# 此循环遍历了TF_A_CONFIG_OEMAKE中的所有额外OEMAKE配置选项 \
for fullconfig in $(TF_A_CONFIG_OEMAKE) ; do \
# 从内到位:echo $$fullconfig:使用 echo 命令输出 fullconfig 变量的内容, \
也就是 TF_A_CONFIG_OEMAKE 变量中的一个元素。fullconfig 包含例如"trusted,"、"optee"的字符串; \
cut -d',' -f1:使用cut命令来分割字符串;-d',':以逗号为界限进行分割;-f1:指定提取第一个字段, \
即逗号之前的字段。 \
# 合在一起,这个命令从 fullconfig 中提取配置选项名称,例如 "trusted" 或 "optee" \
extraconfig=$$(echo $$fullconfig | cut -d',' -f1) ; \
# 检查 extraconfig 和 config 这两个变量的值是否相等,如果匹配则执行后续命令 \
if [ "$$extraconfig" = "$$config" ]; then \
# 类似于上部分,这又是一个字符串分割和提取,依然是以逗号为分隔符, \
提取逗号后的第二部分字段,比如之前的 "AARCH32_SP=sp_min" 以及其他配置, \
并将其赋予之前初始化的add_extraoemake变量 \
add_extraoemake=$$(echo $$fullconfig | cut -d',' -f2) ; \
fi ; \
done ; \
# mkdir -p:按次序建立目录,这里在LOCAL_PATH目录下建立了/build目录, \
并用使用各个配置$$config的名称命名其中的子目录,这里在/build目录下构建了三个子目录, \
分别是/optee,/serialboot和/trusted \
mkdir -p $(LOCAL_PATH)/../build/$$config ; \
# test 命令是用于执行各种条件测试的 Bash 命令,-n 选项即检查一个字符串是否非空。 \
对应的的条件就是"$(TFA_DEVICETREE)",即检测设备树文件的名称是否为空(对应的设备树文件是否存在) \
if test -n "$(TFA_DEVICETREE)" ; then \
# 检查通过,设备树文件存在,则进入循环,对于每一个TFA_DEVICETREE中的元素dt进行操作 \
for dt in $(TFA_DEVICETREE) ; do \
# 如果TF_A_CONFIG(tf-a配置)不是serialboot \
if [ "$(TF_A_CONFIG)" != "serialboot" ]; then \
# 将EXTRA_OEMAKE的参数传给 make,并切换至LOCAL_PATH目录, \
使用dt中储存的设备树文件名称来进行编译 \
$(MAKE) $(EXTRA_OEMAKE) -C $(LOCAL_PATH) DTB_FILE_NAME=$$dt.dtb BUILD_PLAT=$(LOCAL_PATH)/../build/$$config $$add_extraoemake ; \
else \
# 如果 TF_A_CONFIG 是 serialboot,则使用EXTRA_OEMAKE_SERIAL的参数传给make, \
并切换至对应的目录进行编译 \
$(MAKE) $(EXTRA_OEMAKE_SERIAL) -C $(LOCAL_PATH) DTB_FILE_NAME=$$dt.dtb BUILD_PLAT=$(LOCAL_PATH)/../build/$$config $$add_extraoemake ; \
fi \
# Copy binary file with explicit name \
# 将构建好的.stm32文件拷贝并重命名,这一步之后,就会得到对应的stm32文件, \
比如在tf-a-stm32mp157d-atk-trusted.stm32这个文件名中,stm32mp157d-atk对应$$dt(设备树名称), \
trusted对应$$config(配置名称) \
cp -f $(LOCAL_PATH)/../build/$$config/tf-a-$$dt.stm32 $(LOCAL_PATH)/../build/$$config/tf-a-$$dt-$$config.stm32 ; \
# 在正点原子的教程中,编译tf-a之前必须安装stm32wrapper4dbg, \
这个工具就是用来生成调试包(debug wrapper)的 \
if [ "$(TF_A_ENABLE_DEBUG_WRAPPER)" = "1" ]; then \
# Generate wrapper for debugging \
# 生成调试包,-s命令指定了原始tf-a二进制文件的路径,例如,在编译好的/build/trusted目录中, \
原始tf-a文件名称为tf-a-stm32mp157d-atk.stm32;-d指定了调试包的输出路径, \
在这里会在/trusted目录中生成一个debug-tf-a-stm32mp157d-atk-trusted.stm32文件 \
stm32wrapper4dbg -s $(LOCAL_PATH)/../build/$$config/tf-a-$$dt.stm32 -d $(LOCAL_PATH)/../build/$$config/debug-tf-a-$$dt-$$config.stm32 ; \
fi \
done ; \
else \
# 如果设备树文件不存在,则使用MAKE工具执行EXTRA_OEMAKE的配置,切换到LOCAL_PATH路径, \
BUILD_PLAT指定了具体的构建路径,在这里还是生成一个/build目录,并在其中按照EXTRA_OEMAKE的配置, \
依照不同的config值构建子目录,并对tf-a进行编译。接下来一行初始化了tf_version变量, \
使用find指令来查找指定目录下名称匹配 tf-a*.stm32 模式的文件。在这里,它在目录 \
$(LOCAL_PATH)/../build/$$config 下查找所有满足条件的文件。 \
“-exec basename {}” 部分将找到的文件路径转换为文件名,去掉路径部分,以便后续处理。 \
之后再使用 sed 命令,在输出中执行文本替换操作,将 .stm32 扩展名从文件名中去除, \
以获得版本信息。最后,将上面的输出赋值给 tf_version 变量, \
从而将 find 和 sed 命令的结果存储在 tf_version 变量中。 \
$(MAKE) $(EXTRA_OEMAKE) -C $(LOCAL_PATH) BUILD_PLAT=$(LOCAL_PATH)/../build/$$config $$add_extraoemake; \
tf_version=$$(find $(LOCAL_PATH)/../build/$$config -name tf-a*.stm32 -exec basename {} \; | sed "s/\.stm32//") ; \
# Copy binary file with explicit name \
# 和之前按设备树文件编译的流程一样,将构建好的.stm32文件拷贝并重命名, \
得到对应的stm32文件。之后再使用stm32wrapper4dbg工具生成debug调试包 \
cp -f $(LOCAL_PATH)/../build/$$config/$$tf_version.stm32 $(LOCAL_PATH)/../build/$$config/$$tf_version-$$config.stm32 ; \
if [ "$(TF_A_ENABLE_DEBUG_WRAPPER)" = "1" ]; then \
# Generate wrapper for debugging \
stm32wrapper4dbg -s $(LOCAL_PATH)/../build/$$config/$$tf_version.stm32 $(LOCAL_PATH)/../build/$$config/debug-$$tf_version-$$config.stm32 ; \
fi \
# 在else分支中,由于没有指定的设备树文件,首选需要确定tf_version,也就是tf-a的版本号。 \
之后只需按照EXTRA_OEMAKE配置进行编译 \
fi ; \
# Copy elf files with explicit name \
# ELF_DEBUG_ENABLE 控制是否启用或禁用生成 ELF(可执行和链接格式)调试信息的功能
if [ "$(ELF_DEBUG_ENABLE)" = "1" ] ; then \
# 如果判定启动ELF调试信息,则意味着在编译过程中已经生成了.elf文件, \
只需在下面判定文件是否存在,若存在,则拷贝值指定的路径即可。 \
.elf文件未来会被用作bootloader,在不同的tf-a启动过程阶段(bl2和bl32)中用于引导和管理系统的安全性。 \
指定的路径是两个,分别是optee、serialboot和trusted目录,以及各个bl2子目录中 \
if [ -f $(LOCAL_PATH)/../build/$$config/bl2/bl2.elf ] ; then \
cp -f $(LOCAL_PATH)/../build/$$config/bl2/bl2.elf $(LOCAL_PATH)/../build/$$config/tf-a-bl2-$$config.elf ; \
fi ; \
if [ -f $(LOCAL_PATH)/../build/$$config/bl32/bl32.elf ] ; then \
cp -f $(LOCAL_PATH)/../build/$$config/bl32/bl32.elf $(LOCAL_PATH)/../build/$$config/tf-a-bl32-$$config.elf ; \
fi ; \
fi ; \
done
6. clean
在Makefile中,clean部分通常用于执行清理操作。这意味着它的主要功能是删除构建过程中生成的临时文件、构建输出以及其他不再需要的文件,以便在下次构建之前保持工作目录的整洁和准备。
可以使用make distclean
命令来执行clean
# 对于所有TF_A_CONFIG中的配置进行递归强制删除,在这里具体删除的就是/build目录, \
以及其中包含的/optee、/serialboot和/trusted三个子目录中的所有内容。 \
这样就能够保持工作目录的整洁,方便下一次重新编译时重新生成各种配置文件。
clean:
@for config in $(TF_A_CONFIG) ; do \
rm -rf $(LOCAL_PATH)/../build/$$config ; \
done
四、TF-A启动流程简述
理解了Makefile.sdk后,我们大概了解了TF-A的编译配置和编译过程,下面我们转向存有TF-A源码的目录,根据正点原子教程提供的文件,我们的源码目录名称为tf-a-stm32mp1-2.2.r1,如果你使用的是更新版本,目录名称可能会有差异。
1. 不同阶段的BL
在TF-A的源码目录中,我们可以看到名为bl1、bl2、bl2u、bl31和bl32的bootloader子目录,这些对应的就是TF-A对应的启动阶段。TF-A的启动是链式的,不同的阶段有不同的功能,简图如下:
2. BL1
BL1 是第一个执行的阶段,被设计为 ROM 代码;它被加载并在内部 RAM 中执行。对于 STM32 MPU 来说,它并未被使用。由于 STM32 MPU 拥有自己专有的 ROM 代码,因此可以移除这部分,然后 BL2 成为执行的第一个 TF-A 二进制文件。
一般 BL1 要做的就是初始化 CPU,如果芯片支持不同的启动设备,那么还需要初始化不同的启动设置,比如 NAND、EMMC、SD、USB 或串口等。然后根据 BOOT 引脚的高低电平来判断当前所选择的启动设备,从对应的启动设备中加载 bl2 镜像,并放到对应的内存中,最后跳转到 BL2 镜像并运行。
3. BL2
TF-A 的 BL2 基于设备树配置。它使用与内核相同的设备树(例如源码目录中/fdts/stm32mp157d-atk.dtsi),但仅保留引导阶段的强制节点以减小二进制文件的大小。该设备树是最终 STM32 文件的一部分,以便被 ROM 代码验证并同时加载到 SYSRAM 中。
为了能够被 ROM 代码正确加载到 SYSRAM 中,TF-A BL2 固件需要封装在一个以 STM32 头部开头的二进制文件中。STM32 头部信息对于 ROM 代码加载、验证和启动固件是强制的。由于 ROM 代码只能加载单个二进制文件,STM32 文件必须在单个图像中嵌入头部、设备树和 BL2 二进制固件。
4. BL2U
BL2U 是Boot Loader Stage 2 Update(BL2U)的缩写。BL2U 是一个用于更新引导加载程序的一部分,通常位于 BL2 的下一个更新阶段。BL2U 主要负责引导加载程序的更新和升级,以确保系统能够加载新版本的引导加载程序或其他相关组件。
BL2U 的主要功能:
-
引导加载程序更新: BL2U 负责加载和运行新版本的引导加载程序(通常是 BL2 的更新版本),以便引导系统到新的软件版本。
-
验证和完整性检查: 在加载新引导加载程序之前,BL2U 可能会执行验证和完整性检查,以确保新的软件版本是受信任的,并且没有被篡改。
-
回滚支持: 如果引导加载程序更新失败或新版本的引导加载程序存在问题,BL2U 可能支持回滚到之前的稳定版本,以确保系统的可用性和稳定性。
-
配置更新: BL2U 可能还用于更新引导加载程序的配置,例如设备树或其他相关参数,以适应新的硬件或需求。
5. BL31
BL31 是 Boot Loader Stage 3.1 的缩写,BL31 是 TrustZone 技术中安全世界的一部分,主要负责初始化和管理系统的安全性和可信度。
BL31 的功能是确保系统的安全性、可信度和隔离。它为安全的执行环境提供了一个坚实的基础,并负责初始化和管理 TrustZone 安全状态的切换。BL31 通常由芯片制造商或系统设计者提供,以适应特定的硬件和安全需求。这使得系统能够安全地运行受信任的应用程序和服务,从而提供更高级别的安全性。
6. BL32
BL32 是 Boot Loader Stage 3.2 的缩写。BL32 也是 TrustZone 安全世界的一部分,它的主要任务是与 BL31 协同工作。
BL32 提供运行时安全服务,在 TF-A 中默认使用 sp_min。如前文所述 sp_min
是一个最小的 AArch32 安全负载(Secure Payload),整合了 PSCI 库以及 AArch32 的 EL3 运行时软件。sp_min 可以替代可信系统(TEE OS)或者可信执行环境(TEE),比如 OP-TEE。当然了,
STM32MP1 同时支持 sp_min 以及 OP-TEE,用户可以自行选择 bl32 使用哪个软件包。bl32 充当安全监控(secure monitor),因此它向非安全系统(non-secure os,比如 linux)提供了一些安全服务。非安全的应用软件可以通过安全监控调用(secure monitor calls)来使用这些安全服务,这些代码支持标准的服务调用,比如 PSCI。另外,bl32也支持ST32MP1所特有的一些安全服务,可以访问特有的安全外设,比如RCC、PWR、RTC 或 BSEC。
7. BL33
BL33 是 Boot Loader Stage 3.3 的缩写,通常被用作 Non-Secure Monitor 的一部分。BL33 负责引导非安全世界的操作系统或应用程序。我们一般使用 U-Boot 来作为BL33,实现对Linux bootfs的引导。到此为止,我们已经脱离了TF-A所处的安全世界,进入了供用户使用的非安全世界。