前面我们分析了SPL汇编的执行过程,在SPL之后就要进入另一个loader加载镜像了。在正式分析跳转流程之前,我们需要搞清楚在我们平时下载的imx-boot-xxx
这个镜像是如何组成的。
在编译完Uboot、optee和ATF之后,会产生u-boot-spl.bin
,u-boot-nodtb.bin
,imx8mp-evk.dtb
,bl31.bin
和tee.bin
。首先将ddr的固件和u-boot-spl.bin
拼接为u-boot-spl-ddr.bin
,这个bin文件就是SPL部分。其余的bin文件需要组装为一个含uboot.bin的文件,然后将这俩个bin组装起来,加上IVT等头信息就得到了最终可用的imx-boot-xxx
。
1 image source file
Linux kernel
在ARM架构中引入device tree
(全称是flattened device tree,后续将会以FDT代称)的时候,怀揣着一个Unify Kernel的梦想,即同一个Image,通过切换不同的dtb支持多个不同的平台。device tree在kernel中普及之后,Uboot也引入了device tree。因此为了和kernel类似,Uboot也需要一种新的image格式,这种格式需要支持以下特性:
- Image中需要包含多个dtb文件
- 可以方便的选择使用哪个dtb文件
结合以上两点需求,Uboot推出了新的image格式:FIT image,其中FIT是flattened image tree
的简称。它利用了Device Tree Source files
(DTS)的语法,生成的image文件也和dtb文件类似(从its编译为itb)。
1.1 image source file的语法分析
下面是i.MX8MP使用的its文件,在image
标签中声明了uboot-1
,fdt-1
,atf-1
,tee-1
子标签,分别代表uboot,dtb,atf和tee。
对于子标签当中的定义,description
描述这个子标签是什么;data
声明这个bin文件的位置和名称;type
声明这个子标签的类型;arch
表明最终固件运行的架构;compression
表示是否是压缩格式;load
声明这个固件在RAM中的加载地址,子固件需要被SPL拷贝到RAM中的对应地址;entry
表示二进制文件入口地址。
configurations
中声明你需要的配置选择项,可以是多个不同的配置。firmware
声明uboot标签名, loadables
声明可以跳转的其余固件,fdt
声明dtb的标签名。
在SPL 阶段,首先优先加载firmware
节点,将fdt
加载到紧跟着firmware
之后的位置,然后尝试加载kernel
节点;失败了再去加载loadables
节点里的固件。这里的加载是指加载到RAM的指定位置。
/dts-v1/;
/ {
description = "Configuration to load ATF before U-Boot";
#address-cells = <1>;
images {
uboot-1 {
description = "U-Boot (64-bit)";
data = /incbin/("u-boot-nodtb.bin");
type = "standalone";
arch = "arm64";
compression = "none";
load = <0x40200000>;
};
fdt-1 {
description = "evk";
data = /incbin/("evk.dtb");
type = "flat_dt";
compression = "none";
};
atf-1 {
description = "ARM Trusted Firmware";
data = /incbin/("bl31.bin");
type = "firmware";
arch = "arm64";
compression = "none";
load = <0x00970000>;
entry = <0x00970000>;
};
tee-1 {
description = "TEE firmware";
data = /incbin/("tee.bin");
type = "firmware";
arch = "arm64";
compression = "none";
load = <0x56000000>;
entry = <0x56000000>;
};
};
configurations {
default = "config-1";
config-1 {
description = "evk";
firmware = "uboot-1";
loadables = "atf-1", "tee-1";
fdt = "fdt-1";
};
};
};
1.2 示意图
下图是i.MX8MP平台在SPL阶段解包FIT后存放各bin文件的示意图。
2. soc.mk
最终的imx-boot文件由 soc.mk
制作。u-boot-spl-ddr.bin
声明了如何将DDR的固件和u-boot-spl.bin
拼接起来;u-boot.itb
声明了如何制作fit文件;flash_evk_no_hdmi
声明了如何制作最终的imx-boot-xxx
。
请自行理解这段Makefile语法。
SPL_LOAD_ADDR = 0x920000
SPL_FSPI_LOAD_ADDR = 0x920000
TEE_LOAD_ADDR = 0x56000000
ATF_LOAD_ADDR = 0x00970000
lpddr4_imem_1d = lpddr4_pmu_train_1d_imem$(LPDDR_FW_VERSION).bin
lpddr4_dmem_1d = lpddr4_pmu_train_1d_dmem$(LPDDR_FW_VERSION).bin
lpddr4_imem_2d = lpddr4_pmu_train_2d_imem$(LPDDR_FW_VERSION).bin
lpddr4_dmem_2d = lpddr4_pmu_train_2d_dmem$(LPDDR_FW_VERSION).bin
u-boot-spl-ddr.bin: u-boot-spl.bin $(lpddr4_imem_1d) $(lpddr4_dmem_1d) $(lpddr4_imem_2d) $(lpddr4_dmem_2d)
@objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(lpddr4_imem_1d) lpddr4_pmu_train_1d_imem_pad.bin
@objcopy -I binary -O binary --pad-to 0x4000 --gap-fill=0x0 $(lpddr4_dmem_1d) lpddr4_pmu_train_1d_dmem_pad.bin
@objcopy -I binary -O binary --pad-to 0x8000 --gap-fill=0x0 $(lpddr4_imem_2d) lpddr4_pmu_train_2d_imem_pad.bin
@cat lpddr4_pmu_train_1d_imem_pad.bin lpddr4_pmu_train_1d_dmem_pad.bin > lpddr4_pmu_train_1d_fw.bin
@cat lpddr4_pmu_train_2d_imem_pad.bin $(lpddr4_dmem_2d) > lpddr4_pmu_train_2d_fw.bin
@dd if=u-boot-spl.bin of=u-boot-spl-pad.bin bs=4 conv=sync
@cat u-boot-spl-pad.bin lpddr4_pmu_train_1d_fw.bin lpddr4_pmu_train_2d_fw.bin > u-boot-spl-ddr.bin
@rm -f u-boot-spl-pad.bin lpddr4_pmu_train_1d_fw.bin lpddr4_pmu_train_2d_fw.bin lpddr4_pmu_train_1d_imem_pad.bin lpddr4_pmu_train_1d_dmem_pad.bin lpddr4_pmu_train_2d_imem_pad.bin
u-boot.itb: $(dtb)
./$(PAD_IMAGE) $(TEE)
./$(PAD_IMAGE) bl31.bin
./$(PAD_IMAGE) u-boot-nodtb.bin $(dtb)
BL32=$(TEE) DEK_BLOB_LOAD_ADDR=$(DEK_BLOB_LOAD_ADDR) TEE_LOAD_ADDR=$(TEE_LOAD_ADDR) ATF_LOAD_ADDR=$(ATF_LOAD_ADDR) ../$(SOC_DIR)/mkimage_fit_atf.sh $(dtb) > u-boot.its
mkimage -E -p 0x3000 -f u-boot.its u-boot.itb
@rm -f u-boot.its $(dtb)
flash_evk_no_hdmi: $(MKIMG) u-boot-spl-ddr.bin u-boot.itb
./mkimage_imx8 -version $(VERSION) -fit -loader u-boot-spl-ddr.bin $(SPL_LOAD_ADDR) -second_loader u-boot.itb 0x40200000 0x60000 -out $(OUTIMG)