简介
- 对于传统的 ARM 处理而言,Linux 系统的启动流程是:内部 BootROM -> uboot -> kernel -> rootfs, 整个启动过程是一个链式结构,启动过程其实是没有安全校验的,为了保证安全,ARM 推出了 Arm Trusted Firmware 的可信固件,简称 TF-A,它是一个开源的软件
- 加入 TF-A 固件以后,TF-A 就可以对 uboot、kernel 进行校验
源码下载
- 传统的 Linux 开发只涉及到 uboot 和 linux kernel 两个部分
- 现在多了个 TF-A,TF-A 会先初始化 DDR 等外设,然后再把 uboot 从 flash(NAND、NOR FLASH、SD、MMC 等)拷贝到 DDR 中
- 如果我们直接从 TF-A 官方获取 TF-A 源码的话,这样的开发难度太大,半导体厂商都会从 TF-A 官方网站下载 TF-A 源码,然后修改适配自己的芯片,我们在实际项目开发过程中一般会直接使用半导体厂商提供的 TF-A
- 由于我使用的开发板芯片是 ST 公司的 STM32MP157,于是从 ST 官方找到相关源码:https://my.st.com/content/my_st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-mpu-openstlinux-distribution/stm32mp1dev.html
- ST 资料下载是需要登录账号的,如果没有账号,必须先注册一个
- 下载完成后,需要将其拷贝到 Ubuntu 环境下,解压缩
tar -xvf en.sources-stm32mp1-openstlinux-6.1-yocto-mickledore-mp1-v23.06.21.tar.gz
- 解压完成后,进入解压后的目录下,下面会有两个文件夹 “images” 和 “sources”,进入 sources/arm-ostl-linux-gnueabi 目录下,其内容如下所示
FIP_artifacts linux-stm32mp-6.1.28-stm32mp-r1-r0 tf-a-stm32mp-v2.8.6-stm32mp-r1-r0 gcnano-driver-stm32mp-6.4.13-stm32mp-r1-r0 optee-os-stm32mp-3.19.0-stm32mp-r1-r0 u-boot-stm32mp-v2022.10-stm32mp-r1-r0
TF-A 源码打补丁
- ST 公司为 STM32MP157 这款芯片适配的 TF-A 源码就在 “tf-a-stm32mp-v2.8.6-stm32mp-r1-r0” 目录下
文件/文件夹 | 描述 |
0001-v2.8-stm32mp-r1.patch | TF-A 补丁文件 |
Makefile.sdk | 编译 TF-A 用的 MAKEFILE |
README.HOW_TO.txt | ST官方 TF-A的编译文档,编译方法 看此文档即 |
series | 存放补丁名字的文件 |
tf-a-stm32mp-v2.8.6-stm32mp-r1-r0.tar.xz | TF-A 的源码压缩包 |
- ST 也是从 TF-A 官方得到的源码,然后加入自己 STM32MP157 芯片,所以 ST 也需要对 TF-A 源码进行修改,修改的方式就是打补丁,补丁文件后缀为 .patch
- 先解压 TF-A 的源码压缩包
tar -vxf tf-a-stm32mp-v2.8.6-stm32mp-r1-r0.tar.xz
- 接下来就是给 TF-A 源码打补丁了,进入解压好的 TF-A 源码目录下
cd tf-a-stm32mp-v2.8.6-stm32mp-r1/
- 执行打补丁命令,其含义是把上一层目录下得所有 *.patch 后缀的文件都通过 patch 命令打补丁到当前(TF-A 源码)目录下
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
依赖工具安装
- 上面我们得到的 TF-A 源码是 ST 提供的,这个肯定是无法在我们的开发板上运行的,需要移植和修改
- 在正式的移植工作之前,我们可以先使用正点原子修改好的 TF-A 体验一下编译、烧录以及运行的整个过程
- 在编译 TF-A 之前,还有一些依赖工具需要安装
- 一个是 stm32wrapper4dbg 工具,下载地址:https://github.com/STMicroelectronics/stm32wrapper4dbg
- 可以直接 git 拉取代码,也可以下载 zip 压缩包,如果下载的是 zip 压缩包,可以使用如下命令进行解压
unzip stm32wrapper4dbg-master.zip
- 进入到源码目录下,执行 “make” 命令,执行完成后就会得到一个名为 “stm32wrapper4dbg” 的文件,这个就是我们要的工具,使用如下命令将其拷贝到 /usr/bin/ 目录下,这样子我们就可以在任何路径下使用这个工具了
sudo cp stm32wrapper4dbg /usr/bin/
- 可以使用 “stm32wrapper4dbg -s” 命令测试一下是否安装成功,如果安装成功,会输出如下信息
stm32wrapper4dbg: option requires an argument -- 's' Usage: stm32wrapper4dbg -s srcfile -d destfile [-b] [-f] Add a debug wrapper to a stm32 image. If "-b" is not specified, the wrapper would be placed after the last byte of the image. Options: -s srcfile input image in stm32 file format -d destfile output image in stm32 file format -b place the wrapper before the image -f force re-adding the wrapper
- 在编译 TF-A 之前,还有一个依赖库需要安装,是关于设备树编译相关的,输入如下命令
sudo apt-get install device-tree-compiler
编译正点原子提供的 TF-A
- 源码位置:程序源码/1、正点原子 Linux出厂系统源码/tf-a-stm32mp-2.2.r1-gaa9f87c-v1.5.tar.bz2
- 将其拷贝到 Ubuntu 环境下,使用如下命令解压缩
tar -xvf tf-a-stm32mp-2.2.r1-gaa9f87c-v1.5.tar.bz2
- 首先我们要将 Makefile.sdk 中的交叉编译工具链改为我们自己开发环境中的
# CROSS_COMPILE=arm-ostl-linux-gnueabi- CROSS_COMPILE=arm-none-linux-gnueabihf-
- 编译 TF-A
cd tf-a-stm32mp-2.2.r1/ # 进入到 TF-A 源码目录下 make -f ../Makefile.sdk all # 编译 TF-A,-f:指定 Makefile
- 编译完成后,如果出现如下提示,则说明编译成功
Built /home/thin-wind/atk/tf-a-stm32mp-2.2.r1/../build/serialboot/tf-a-stm32mp157d-atk.bin successfully Generate /home/thin-wind/atk/tf-a-stm32mp-2.2.r1/../build/serialboot/tf-a-stm32mp157d-atk.stm32 Image Type : ST Microelectronics STM32 V1.0 Image Size : 241728 bytes Image Load : 0x2ffc2500 Entry Point : 0x2ffd6000 Checksum : 0x00e24c6a Option : 0x00000001 Version : 0x00000000 Building stm32mp1 make[1]: Leaving directory '/home/thin-wind/atk/tf-a-stm32mp-2.2.r1' Image Type : ST Microelectronics STM32 V1.0 Image Size : 241784 bytes Image Load : 0x2ffc2500 Entry Point : 0x2fffd541 Checksum : 0x00e26305 Option : 0x00000001 Version : 0x00000000 Halt Address : 0x2ffd6000
- 编译完成后会在上一层目录下生成 "build" 目录,进入 build/trusted/ 目录,如下红框标记的即为正点原子开发板使用的 tf-a-stm32mp157d-atk-trusted.stm32
准备烧录文件
- 在烧录前,我们要提前准备好如下文件
atk_emmc-stm32mp157d-atk-qt.tsv tf-a-stm32mp157d-atk-serialboot.stm32 tf-a-stm32mp157d-atk-trusted.stm32 u-boot.stm32
- 其中,只有 tf-a-stm32mp157d-atk-trusted.stm32 这个文件是我们编译生成的
- tf-a-stm32mp157d-atk-serialboot.stm32: 由原子提供,路径:8、系统镜像/2、出厂系统镜像/1、 STM32CubeProg烧录固件包/tf-a/tf-a-stm32mp157d-atk-serialboot.stm32
- u-boot.stm32: 由原子提供,路径:8、系统镜像/2、出厂系统镜像/1、 STM32CubeProg烧录固件包/uboot/u-boot.stm32
- atk_emmc-stm32mp157d-atk-qt.tsv: 由原子提供,路径:8、系统镜像/2、出厂系统镜像/1、 STM32CubeProg烧录固件包/flashlayout/atk_emmc-stm32mp157d-atk-qt.tsv
- 为什么需要 tf-a-stm32mp157d-atk-serialboot.stm32 和 u-boot.stm32 这两个文件?tf-a-stm32mp157d-atk-serialboot.stm32 用来初始化 USB、DDR 等外设, DDR初始化了以后就可以运行 uboot 了,为什么要运行 uboot 呢?因为 uboot里面会初始化 EMMC、NAND 等外设,而且 uboot 会提供很强大的 EMMC 操作指令。也就是说,启动 uboot的目的就是为了操作 EMMC、 NAND,这样就可以在 uboot 里面通过相关的命令将 tf-a-stm32mp157d-atk-trusted.stm32 写到 EMMC 或者 NAND 里面
- *.tsv 文件是 STM32CubeProgrammer 的烧录脚本配置文件,是文本格式的,很容易阅读,关于 .tsv语法的详细讲解,请参考 https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout
- 将 atk_emmc-stm32mp157d-atk-qt.tsv 文件修改成下面的样子,注意不能使用空格,必须使用 Tab 键
#Opt Id Name Type Device Offset Binary - 0x01 fsbl1-boot Binary none 0x0 tf-a-stm32mp157d-atk-serialboot.stm32 - 0x03 ssbl-boot Binary none 0x0 u-boot.stm32 P 0x04 fsbl1 Binary mmc1 boot1 tf-a-stm32mp157d-atk-trusted.stm32 P 0x05 fsbl2 Binary mmc1 boot2 tf-a-stm32mp157d-atk-trusted.stm32
- 关于 *.tsv 内容暂时就不做具体说明了,研究明白了也不一定用的到,不同的芯片烧录方式也是不一样的,我建议是除非工作中用到,否则没必要过度研究工具的使用
烧录 TF-A
- 烧录工具:STM32CubeProgrammer, 下载地址:https://www.st.com/zh/development-tools/stm32cubeprog.html#get-software
- 一切准备就绪,下面就是实际烧录环节了
- 首先设置开发板拨码开关为000,也就是从 USB 启动
- 按下图连接硬件 USB
- 连接成功后,通过设备管理器查看相关驱动是否 OK,安装完成 STM32CubeProgrammer 后可能找不到 DFU,重启电脑即可
- 打开 STM32CubeProgrammer 软件,按如下步骤连接 USB
- 连接成功后显示如下,点击 “Open file”
- 选择刚刚准备好的烧录文件中的 *.tsv 文件,按如下操作
- 烧录成功后会有如下提示:
TF-A 的运行
- 烧录成功后,接下来就是要测试一下能否运行
- 断电,设置开发板拨码开关为010,也就是从 EMMC 启动
- 打开串口工具,波特率设置为 115200
- 上电,TF-A 是最先启动的,从打印输出的时间可以看出我们编译的 TF-A 已经成功运行了
TF-A 启动顺序
- TF-A 一共分为 5 部分:bl1、bl2、bl31、bl32、bl33,打开 TF-A 源码,可以看到 bl1、bl2、bl31、bl32 这 4 个文件夹,并没有 bl33,这是因为 bl33 是 TF-A 启动的其它第三方镜像固件,比如 uboot
- TF-A 的启动流程:bl1 -> bl2 -> (bl31/bl32/bl33), bl31、bl32 和 bl33 对应的镜像不需要全部都有,但 bl33 一般是必须的,因为 bl33 一般是 uboot