SPL-TPL 链式启动:spl.c 与CONFIG_TPL 三阶段加载

复杂 SoC(如 TI K3、NXP i.MX8)ROM 只能载入极小第一级 loader,U-Boot 用 TPL → SPL → Proper 三级镜像逐级初始化 DRAM 与外设。common/spl/spl.c 是 SPL 核心:spl_early_init()board_init_r()spl_load_image()spl_image_loader 注册表加载下一级,jump_to_image() 跳转到 U-Boot 或 Linux。与单级 SPL 相比,链式启动把 DDR training、PMIC、时钟树拆到 TPL,减轻 SPL 体积限制。

源码锚点

路径 关键符号 作用
common/spl/spl.c board_init_r() SPL 主逻辑
common/spl/spl.c spl_load_image() 加载下一级镜像
common/spl/spl.c jump_to_image() 跳转 Proper/内核
common/spl/spl.c spl_parse_image_header() 解析 mkimage
include/spl.h struct spl_image_info 加载结果
common/spl/spl_fat.c spl_load_image_fat() 从 FAT 加载
tpl/arch/... TPL 入口 第一级 C 代码

SPL board_init_r 骨架:

c 复制代码
/* common/spl/spl.c */
void board_init_r(gd_t *dummy1, ulong dummy2)
{
	u32 spl_boot_list[] = {
		BOOT_DEVICE_MMC1,
		BOOT_DEVICE_MMC2,
		BOOT_DEVICE_UART,
		...
	};

	if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC_SIMPLE))
		mem_malloc_init(SPL_MALLOC_BASE, SPL_MALLOC_SIZE);

	if (IS_ENABLED(CONFIG_SPL_DM))
		spl_dm_init();

	if (CONFIG_IS_ENABLED(LOAD_FIT)) {
		ret = spl_load_image(spl_boot_list, count, &spl_image);
	} else {
		ret = spl_load_image(spl_boot_list, count, &spl_image);
	}

	switch (spl_image.os) {
	case IH_OS_U_BOOT:
		jump_to_image(&spl_image);
		break;
	case IH_OS_LINUX:
		spl_board_prepare_for_boot();
		jump_to_image(&spl_image);
		break;
	default:
		hang();
	}
}

加载器查找:

c 复制代码
/* common/spl/spl.c */
static struct spl_image_loader *spl_ll_find_loader(uint boot_device)
{
	struct spl_image_loader *drv =
		ll_entry_start(struct spl_image_loader, spl_image_loader);
	const int n_ents = ll_entry_count(struct spl_image_loader,
					  spl_image_loader);

	for (; drv != drv + n_ents; drv++) {
		if (drv->boot_device == boot_device)
			return drv;
	}
	return NULL;
}

jump_to_image

c 复制代码
/* common/spl/spl.c */
__weak void __noreturn jump_to_image(struct spl_image_info *spl_image)
{
	typedef void __noreturn (*image_entry_t)(ulong, ulong, ulong);
	image_entry_t entry = (image_entry_t)spl_image->entry_point;

	debug("Jumping to image at %lx\n", spl_image->entry_point);
	cleanup_before_linux();
	entry(0, 0, 0);
}

TPL 跳 SPL(概念流程):

c 复制代码
/* tpl 完成 DDR 后 */
spl_image.entry_point = CONFIG_SPL_TEXT_BASE;
memcpy((void *)load_addr, u_boot_spl, spl_size);
/* 跳转 SPL reset vector */

调用链

复制代码
BootROM
  └── 加载 TPL @ SRAM
        └── board_init_f (TPL)
              └── 初始化最小时钟 + DDR
                    └── spl_load_image → 加载 SPL 到 SRAM/DDR
                          └── jump_to_image → SPL

SPL board_init_r
  ├── spl_early_init / spl_board_init
  ├── spl_load_image(spl_boot_list)
  │     ├── spl_mmc_load() / spl_fat_load() / spl_spi_load()
  │     └── spl_parse_image_header → spl_image.entry_point
  └── jump_to_image
        └── U-Boot Proper board_init_f
              或 Falcon: spl_direct_jump_linux()

重点知识

CONFIG_TPL vs CONFIG_SPL :Kconfig 独立开关;TPL 镜像更小、无完整 DM;SPL 可含 CONFIG_SPL_LIBCOMMON_SUPPORT、FAT、USB。三者 defconfig 各生成 u-boot-tpl.binu-boot-spl.binu-boot.bin

spl_boot_list 顺序 :板级 spl_boot_device() 或 eFUSE/strap 决定优先介质;失败则尝试下一项。量产常固定 eMMC,开发加 UART/YMODEM。

SPL_FIT / SPL_LEGACYCONFIG_SPL_LOAD_FIT 从 FIT 读 u-boot 子镜像;Legacy 裸二进制需 CONFIG_SPL_PAYLOAD 指定链接地址。

SPL size 限制 :SRAM 128KB 典型;用 CONFIG_SPL_MAX_SIZEu-boot-spl.map 检查。TPL 更小,DDR 代码必须进 SPL。

SPL_OS_BOOT :SPL 直接加载内核(Falcon)跳过 Proper;与完整 U-Boot 的 booti 能力互斥配置。

Handoff 数据spl_handoff 或 ATF BL31 传递 DRAM 参数;K3 等平台 SPL 先起 ATF 再起 U-Boot。

Checklist

  • 确认 ROM 支持的镜像格式与加载地址(Reference Manual)
  • TPL/SPL/Proper 各自 TEXT_BASE 不重叠
  • spl_boot_list 与硬件 boot pin 一致
  • FIT 中 u-boot、spl 节点 load/entry 正确
  • CONFIG_SPL_STACK 足够 DDR init 调用栈
  • 串口 log 区分 TPL/SPL 阶段 banner
  • 测量各阶段耗时(bootstage 在 SPL 可用性)
  • OTA 更新需同时升级 tpl/spl/proper 还是仅 spl+proper
相关推荐
布莱克60515 分钟前
链表详解:定义、作用、应用场景及与数组的区别(C/C++ 实战)
c语言·开发语言·c++·链表
2601_9669496523 分钟前
实时行情中的成交量 Volume 到底是什么?包含盘中撤单量吗?从交易数据语义到 QuantDash 实战解析
开发语言·人工智能·python·量化·quantdash·量化数据源
老当益壮梁奶奶1 小时前
Linux软件编程学习笔记(九):消息队列、共享内存与信号灯详解
linux·c语言·笔记·学习
开开心心就好1 小时前
电子教鞭工具支持画框写字插图片功能齐全
android·开发语言·前端·javascript·人工智能·pdf·html
小雪崩1 小时前
嵌入式学习 day35:进程间通信-消息队列、共享空间及有名信号量
linux·c语言·学习
zx_741484811 小时前
【Python入门】爬虫实战:Requests + XPath 从基础到实战
开发语言·爬虫·python
从零开始的嵌入式之旅1 小时前
day33
linux·c语言·经验分享·笔记·嵌入式硬件
吴声子夜歌1 小时前
Java——开发中通用的方法和准则(二)
java·开发语言·php
江屿风2 小时前
C++OJ题经验总结(竞赛)5
开发语言·c++