ARM64 Trust Firmware [一]
ARMv8 启动流程:
在《RK3568上电启动流程 [十五]》中,简单介绍了 RK3568 的上电启动过程,本篇再详细分解其启动流程。
在 ARMv8 架构中,启动流程包含多个阶段,这些阶段被称为 BL (bootloader) 阶段:
- BL1:第一阶段启动固件,在 RK3568 中位于 BootRom 中,负责引导 BL2 并对其进行安全验证;
- BL2:第二阶段启动固件,在 RK3568 中位于 Flash 中(比如 eMMC),负责平台相关的初始化,比如 DRAM 的初始化,并负责加载 BL31 并执行 BL31,在 RK3568 中就是我们的 miniloader.bin;
- BL31:也就是 trust Runtime firmware,BL31 是持久存在的可信固件,负责系统安全服务和在安全非非安全世界之间切换;
- BL32:包含 TEE OS 和安全应用 TAs,运行在 EL1,启动 EL0 的安全应用,完成后返回 BL31;
- BL33:非安全世界的启动固件,通常就是 U-Boot 或者直接启动 Linux 内核;
在 RK3568 中其启动全流程的输出如下:
在支持 ATF 的 ARMv8 中完整的镜像跳转流程如下:
ATF 编译和 uboot image 打包:
为了学习 ATMv8 Trust Firmware,最好的方法就是将开源的 ATF 编译,并在 RK3568 上跑起来,通过打印,调试去理解其工作机制。但是Upstream ARM Trusted Firmware 是不支持 RK3568 的,Rockchip 只提供了官方的 trust bin 文件(ATF - Rockchip open source Document)。但是最后发现在arm-trusted-firmware 的v2.12 版本中还是存在 RK3568 的 Platform,因此用 v2.12 来编译生成 bl31.elf,并将其打包进 uboot.img 中(后来发现该 bl31.elf 会导致 Linux 在初始化 SCMI 时失败,但是先不管了,至少我们可以有源码,并且能够编译和实现初步的运行)。
ATF 的编译:
git clone https://github.com/ARM-software/arm-trusted-firmware.git
cd arm-trusted-firmware
git checkout v2.12.0
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3568
将编译生成的 bl31.elf 拷贝到 u-boot 目录下。
uboot 使用 FIT Image 格式,所以我们需要先生成 u-boot.its,再使用 mkimage 工具根据 u-boot.its 文件做成 uboot.itb
uboot.its 如下:这里我将 OPTEE 的分支删除了,因为我们目前不需要研究 TEE OS。
/*
* Copyright (C) 2020 Rockchip Electronic Co.,Ltd
*
* Simple U-boot fit source file containing ATF/OP-TEE/U-Boot/dtb/MCU
*/
/dts-v1/;
/ {
description = "CXJ FIT Image with ATF/OP-TEE/U-Boot/MCU";
#address-cells = <1>;
images {
uboot {
description = "U-Boot";
data = /incbin/("u-boot-nodtb.bin.gz");
type = "standalone";
arch = "arm64";
os = "U-Boot";
compression = "gzip";
load = <0x00a00000>;
digest {
value = /incbin/("./u-boot-nodtb.bin.digest");
algo = "sha256";
};
hash {
algo = "sha256";
};
};
atf-1 {
description = "ARM Trusted Firmware";
data = /incbin/("./bl31_0x00040000.bin.gz");
type = "firmware";
arch = "arm64";
os = "arm-trusted-firmware";
compression = "gzip";
load = <0x00040000>;
hash {
algo = "sha256";
};
digest {
value = /incbin/("./bl31_0x00040000.bin.digest");
algo = "sha256";
};
};
atf-2 {
description = "ARM Trusted Firmware";
data = /incbin/("./bl31_0xfdcd0000.bin");
type = "firmware";
arch = "arm64";
os = "arm-trusted-firmware";
compression = "none";
load = <0xfdcd0000>;
hash {
algo = "sha256";
};
};
fdt {
description = "U-Boot dtb";
data = /incbin/("./u-boot.dtb");
type = "flat_dt";
arch = "arm64";
compression = "none";
hash {
algo = "sha256";
};
};
};
configurations {
default = "conf";
conf {
description = "rk3568-evb";
rollback-index = <0x0>;
firmware = "atf-1";
loadables = "uboot", "atf-2";
fdt = "fdt";
signature {
algo = "sha256,rsa2048";
key-name-hint = "dev";
sign-images = "firmware", "loadables", "fdt";
};
};
};
};
再使用 mkimage 生成 u-boot.itb:
./tools/mkimage -f u-boot.its -E uboot.itb
通过 fdtdump 我们可以看到 uboot img 包含的内容:
cuixujia.cxj@localhost:~/workspace/luban/LubanCat_SDK/u-boot$ fdtdump uboot.itb
**** fdtdump is a low-level debugging tool, not meant for general use.
**** If you want to decompile a dtb, you probably want
**** dtc -I dtb -O dts <filename>
/dts-v1/;
// magic: 0xd00dfeed
// totalsize: 0x72f (1839)
// off_dt_struct: 0x38
// off_dt_strings: 0x66c
// off_mem_rsvmap: 0x28
// version: 17
// last_comp_version: 16
// boot_cpuid_phys: 0x0
// size_dt_strings: 0xc3
// size_dt_struct: 0x634
/ {
version = <0x00000000>;
totalsize = <0x00095f0d>;
timestamp = <0x67adacea>;
description = "CXJ FIT Image with ATF/OP-TEE/U-Boot/MCU";
#address-cells = <0x00000001>;
...
...
重新烧录uboot.itb,重启后,我们可以看到系统可以成功加载 atf,uboot:
Trying fit image at 0x4000 sector
## Verified-boot: 0
## Checking atf-1 0x00040000 (gzip @0x00240000) ... sha256(3a0e0e29a2...) + sha256(cb9e165ab3...) + OK
## Checking uboot 0x00a00000 (gzip @0x00c00000) ... sha256(69d1989cfb...) + sha256(5f44711400...) + OK
## Checking fdt 0x00b4b478 ... sha256(a474c6bb61...) + OK
## Checking atf-2 0xfdcd0000 ... sha256(e25f5f200c...) + OK
Jumping to U-Boot(0x00a00000) via ARM Trusted Firmware(0x00040000)
Total: 133.134/203.236 ms
NOTICE: BL31: v2.12.0(release):v2.12.0
NOTICE: BL31: Built : 10:51:56, Feb 13 2025
NOTICE: BL31: Rockchip release version: v1.0
usb dr_mode not found
usb dr_mode not found
U-Boot 2017.09-dirty #cuixujia.cxj (Feb 13 2025 - 16:21:38 +0800)
Model: Rockchip RK3568 Evaluation Board
但是在 Linux bringup 过程中 hang 住了,由于开源 ATF 对 RK3568 支持不足,怀疑是在 SCMI 这块的支持有问题:
[ 3.068424] usbcore: registered new interface driver usbfs
[ 3.068510] usbcore: registered new interface driver hub
[ 3.068578] usbcore: registered new device driver usb
[ 3.069218] mc: Linux media interface: v0.10
[ 3.069293] videodev: Linux video capture interface: v2.00
[ 3.069435] pps_core: LinuxPPS API ver. 1 registered
[ 3.069459] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[ 3.069501] PTP clock support registered
[ 3.069575] EDAC MC: Ver: 3.0.0
[ 3.070837] arm-scmi firmware:scmi: SCMI Notifications - Core Enabled.
关于 FIT Image:
FIT(Flattened image tree)UImage,FIT 和 FDT 比较类似,利用的语法都是 Device Tree Source files 语法,生成的 image 文件也和 dtb 文件基本一样。
FIT uImage 的生成流程可以概括如下:
以 u-boot.its 的 uboot 节点为例,简述一下 its 的 语法结构:
images {
uboot {
description = "U-Boot";
data = /incbin/("u-boot-nodtb.bin.gz");
type = "standalone";
arch = "arm64";
os = "U-Boot";
compression = "gzip";
load = <0x00a00000>;
digest {
value = /incbin/("./u-boot-nodtb.bin.digest");
algo = "sha256";
};
hash {
algo = "sha256";
};
};
- description:子镜像文本的描述,可以随便写;
- data:包含该节点二进制文件的路径;
- type:子镜像类型;
- compression:压缩方法,比如 gzip,bzip2 等;
- load:二进制文件的内存加载位置;
- hash:镜像使用的校验算法,如 sha256,crc32 等;