网站建设公司企业网站,wordpress if else,全球影响力最大的人,wordpress租车对于i.MX平台上的SPL来说#xff0c;其不会直接跳转到Uboot#xff0c;而是在SPL阶段借助BOOTROM跳转到ATF#xff0c;然后再通过ATF跳转到Uboot。
board_init_f会初始化设备相关的硬件#xff0c;最后进入board_init_r为镜像跳转做准备。下面是board_init_r调用的核心函数…对于i.MX平台上的SPL来说其不会直接跳转到Uboot而是在SPL阶段借助BOOTROM跳转到ATF然后再通过ATF跳转到Uboot。
board_init_f会初始化设备相关的硬件最后进入board_init_r为镜像跳转做准备。下面是board_init_r调用的核心函数流程接下来我们会对其中的函数进行详细分析。
spl_board_init //board/freescale/imx93_evk/spl.c
board_boot_order(spl_boot_list)//spl_boot_device获取SPL启动设备 arch/arm/mach-imx/imx8/cpu.c
spl_boot_device//arch/arm/mach-imx/spl.c-spl_board_boot_device//board/freescale/imx93_evk/spl.c
spl_return_to_bootrom
board_return_to_bootrom//arch/arm/mach-imx/spl_imx_romapi.c1、spl_board_init
对于i.MX93芯片来说spl_board_init启动ELE了引擎。这里不对ELE进行详细分析。
//board/freescale/imx93_evk/spl.c
void spl_board_init(void)
{int ret;puts(Normal Boot\n);ret ahab_start_rng();if (ret)printf(Fail to start RNG: %d\n, ret);
}2、board_boot_order
spl_boot_device根据boot配置获取当前的启动设备。对于使用SCU的芯片需要特殊处理BOOT_DEVICE_SPI类型的设备。
//arch/arm/mach-imx/imx8/cpu.c适用于93
void board_boot_order(u32 *spl_boot_list)
{spl_boot_list[0] spl_boot_device();if (spl_boot_list[0] BOOT_DEVICE_SPI) {/* Check whether we own the flexspi0, if not, use NOR boot */if (!sc_rm_is_resource_owned(-1, SC_R_FSPI_0))spl_boot_list[0] BOOT_DEVICE_NOR;}
}从spl_board_boot_device函数内容可以看出i.MX8以及i.MX9系列芯片的SPL跳转皆是由BOOTROM辅助实现的因为这里直接返回了BOOT_DEVICE_BOOTROM。
//arch/arm/mach-imx/spl.c
u32 spl_boot_device(void)
{enum boot_device boot_device_spl get_boot_device();return spl_board_boot_device(boot_device_spl);
}int spl_board_boot_device(enum boot_device boot_dev_spl)
{
#ifdef CONFIG_SPL_BOOTROM_SUPPORTreturn BOOT_DEVICE_BOOTROM;
#elseswitch (boot_dev_spl) {case SD1_BOOT:case MMC1_BOOT:return BOOT_DEVICE_MMC1;case SD2_BOOT:case MMC2_BOOT:return BOOT_DEVICE_MMC2;default:return BOOT_DEVICE_NONE;}
#endif
}
3、spl_return_to_bootrom
由于上面返回的boot设备是BOOT_DEVICE_BOOTROM因此这里各家定义的board_return_to_bootrom用于辅助跳转。
通过ROM API查询当前的启动设备和启动阶段启动阶段可以分为Primary bootSecondary bootRecovery boot和USB boot打印对应的启动阶段信息最后使用ROM API将Uboot搬运到DDR的对应位置。
int board_return_to_bootrom(struct spl_image_info *spl_image,struct spl_boot_device *bootdev)
{volatile gd_t *pgd gd;int ret;u32 boot, bstage;ret g_rom_api-query_boot_infor(QUERY_BT_DEV, boot,((uintptr_t)boot) ^ QUERY_BT_DEV);ret | g_rom_api-query_boot_infor(QUERY_BT_STAGE, bstage,((uintptr_t)bstage) ^ QUERY_BT_STAGE);set_gd(pgd);if (ret ! ROM_API_OKAY) {puts(ROMAPI: failure at query_boot_info\n);return -1;}printf(Boot Stage: );switch (bstage) {case BT_STAGE_PRIMARY:printf(Primary boot\n);break;case BT_STAGE_SECONDARY:printf(Secondary boot\n);break;case BT_STAGE_RECOVERY:printf(Recovery boot\n);break;case BT_STAGE_USB:printf(USB boot\n);break;default:printf(Unknow (0x%x)\n, bstage);}//USB下载模式if (is_boot_from_stream_device(boot))return spl_romapi_load_image_stream(spl_image, bootdev);return spl_romapi_load_image_seekable(spl_image, bootdev, boot);
}4、spl_romapi_load_image_seekable
下面我们将分析ROM API是如何将Uboot搬运到指定位置的。 通过query_boot_infor查询IVT的偏移量、pagesize和image_offset。 获取header的位置 header (struct image_header *)(CONFIG_SPL_IMX_ROMAPI_LOADADDR);//0x48000000 内存地址获取Uboot在MMC介质中的偏移量将其存储在offset0x41400中。 offset spl_romapi_get_uboot_base(image_offset, rom_bt_dev);ulong spl_romapi_get_uboot_base(u32 image_offset, u32 rom_bt_dev)
{ulong end;image_offset spl_arch_boot_image_offset(image_offset, rom_bt_dev);end get_imageset_end((void *)(ulong)image_offset, ROM_API_DEV);end ROUND(end, SZ_1K);printf(Load image from 0x%lx by ROM_API\n, end);return end;
}使用download_image函数从MMC中的0x41400处下载header信息到DDR中的0x48000000处后续需要对header里的信息进行判断image_get_magic(header) FDT_MAGIC。这个header由mkimage_imx8.c写入。 g_rom_api-download_image((u8 *)header, offset, size,((uintptr_t)header) ^ offset ^ size);设置其他固件的信息对于93/8ulp来说调用的是spl_load_imx_container函数其余芯片为spl_load_simple_fit函数。spl_load_simple_fit这个函数会解析itb文件获取里面的配置信息填充spl_image_info和spl_load_info中的信息加载ATF做好跳转之前的准备。
5、spl_load_simple_fit
在进入之前设置了load.read为spl_romapi_read_seekable然后spl_simple_fit_read会调用传入的read函数和上一节而最后读取到内存的header读取整个fit固件。这个是后续读取固件的核心函数。
if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) image_get_magic(header) FDT_MAGIC) {struct spl_load_info load;memset(load, 0, sizeof(load));load.bl_len pagesize;load.read spl_romapi_read_seekable;load.priv pagesize;return spl_load_simple_fit(spl_image, load, offset / pagesize, header);
}spl_load_simple_fit_fix_load使用ROM API读取itb到内存中然后解析/configurations节点其中的default配置名称和images的偏移量。
5.1、解析uboot
解析默认configconfig-1下面的firmware所指向的名称这里解析出uboot-1然后返回出这个uboot节点在itb文件中的偏移量。一个config只有一个firmware可以是uboot也可以是kernel其余均为external数据。
spl_load_fit_image根据解析出的加载地址将u-boot-nodtb.bin放到加载地址处。然后填充spl_image_info中的load_addr等信息。
#define FIT_FIRMWARE_PROP firmware
node spl_fit_get_image_node(ctx, FIT_FIRMWARE_PROP, 0);ret spl_load_fit_image(info, sector, ctx, node, spl_image);5.2、解析fdt
spl_fit_append_fdt首先也是解析出its中关于设备树的相关信息然后使用fdt_overlay_apply_verbose-fdt_overlay_apply将its中需要overlay的部分覆盖进原始dtb中。
if (os_takes_devicetree(spl_image-os)) {ret spl_fit_append_fdt(spl_image, info, sector, ctx);
}overlay dtb格式1
/dts-v1/;
/plugin/;/ {fragment0 {target-path /;__overlay__ {/*在此添加要插入的节点*/.......};};fragment1 {target XXXXX;__overlay__ {/*在此添加要插入的节点*/.......};};.......};overlay dtb格式2
/dts-v1/;
/plugin/;{/} {/*此处在根节点/下,添加要插入的节点或者属性*/
};XXXXX {/*此处在节点XXXXX下,添加要插入的节点或者属性*/
};5.3、解析loadables
和解析加载uboot类似先找到its节点中的信息然后根据这些信息将atf和tee放到指定位置。
for (; ; index) {uint8_t os_type IH_OS_INVALID;node spl_fit_get_image_node(ctx, loadables, index);image_info.load_addr 0;ret spl_load_fit_image(info, sector, ctx, node, image_info);/* Record our loadables into the FDT */if (spl_image-fdt_addr)spl_fit_record_loadable(ctx, index,spl_image-fdt_addr,image_info);}如果firmware属性中未定义entry值那么将第一个loadables的entry作为跳转入口spl_image-entry_point。从its中我们可以知道第一个loadables就是atf。
6、跳转至ATF
直接跳转进spl_image-entry_point所定义的地址也就是进入ATF中。
arch/arm/mach-imx/spl.c
/** ------------ 0x0 (DDR_UIMAGE_START) -* | Header | |* ------------ 0x40 |* | | |* | | |* | | |* | | |* | Image Data | |* . | |* . | Stuff to be authenticated ----* . | | |* | | | |* | | | |* ------------ | |* | | | |* | Fill Data | | |* | | | |* ------------ Align to ALIGN_SIZE | |* | IVT | | |* ------------ IVT_SIZE - |* | | |* | CSF DATA | ---------------------------------------------------------* | |* ------------* | |* | Fill Data |* | |* ------------ CSF_PAD_SIZE*/__weak void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
{typedef void __noreturn (*image_entry_noargs_t)(void);uint32_t offset;image_entry_noargs_t image_entry (image_entry_noargs_t)(unsigned long)spl_image-entry_point;debug(image entry point: 0x%lX\n, spl_image-entry_point);if (spl_image-flags SPL_FIT_FOUND) {image_entry();} else {/** HAB looks for the CSF at the end of the authenticated* data therefore, we need to subtract the size of the* CSF from the actual filesize*/offset spl_image-size - CONFIG_CSF_SIZE;if (!imx_hab_authenticate_image(spl_image-load_addr,offset IVT_SIZE CSF_PAD_SIZE, offset)) {image_entry();} else {panic(spl: ERROR: image authentication fail\n);}}
}附录1its表
/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;};};
};
附录2启动log
i.MX93
U-Boot SPL 2022.04-lf_v2022.04g1734965341 (Jun 30 2023 - 10:23:49 0000)
SOC: 0xa0009300
LC: 0x40010
M33 prepare ok
SPL: board_init_r()
spl_init
Normal Boot
Trying to boot from BOOTROM
Boot Stage: Primary boot
image offset 0x0, pagesize 0x200, ivt offset 0x0
Load image from 0x41400 by ROM_API
Unsupported OS image.. Jumping nevertheless..
image entry point: 0x204e0000i.MX8MP
U-Boot SPL 2023.04-lf_v2023.04gaf7d004eaf (Aug 14 2023 - 03:48:45 0000)
DDRINFO: start DRAM init
DDRINFO: DRAM rate 4000MTS
DDRINFO:ddrphy calibration done
DDRINFO: ddrmix config done
SPL: board_init_r()
spl_init
SEC0: RNG instantiated
Normal Boot
Trying to boot from BOOTROM
Boot Stage: Primary boot
image offset 0x0, pagesize 0x200, ivt offset 0x0
Jumping to U-Boot...
image entry point: 0x970000