在嵌入式系統(tǒng)啟動(dòng)過程中,從按下電源鍵到操作系統(tǒng)開始運(yùn)行,中間藏著一系列精密的初始化步驟。今天我們就來拆解Rockchip平臺(tái)U-Boot中的TPL(Tiny Program Loader)階段核心代碼tpl.c,看看這個(gè)"啟動(dòng)第一棒"是如何為整個(gè)系統(tǒng)保駕護(hù)航的。

什么是TPL?為什么它如此重要?
TPL是U-Boot啟動(dòng)流程中最早執(zhí)行的階段之一,全稱Tiny Program Loader(小型程序加載器)。不同于后續(xù)的SPL(Secondary Program Loader)和U-Boot主體,TPL運(yùn)行在系統(tǒng)資源極其有限的環(huán)境中(通常依賴片內(nèi)SRAM),卻要完成最關(guān)鍵的硬件初始化工作。
可以把嵌入式啟動(dòng)比作一場接力賽:
?BootROM(芯片內(nèi)置的啟動(dòng)程序)是"發(fā)令員"
?TPL是"第一棒選手",負(fù)責(zé)啟動(dòng)最基礎(chǔ)的硬件
?SPL是"第二棒",完成更多初始化
?U-Boot主體則是"最后一棒",最終引導(dǎo)操作系統(tǒng)
而tpl.c正是"第一棒選手"的核心操作手冊。
代碼解析:TPL都做了些什么?
我們通過代碼結(jié)構(gòu),一步步揭開TPL的工作內(nèi)容:
1.最小化的"輸出系統(tǒng)":串口調(diào)試的基石
voidputs(constchar*str){while(*str)putc(*str++);}voidputc(charc){if(c =='n')NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1),'r');NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1), c);}
這段代碼實(shí)現(xiàn)了最基礎(chǔ)的字符串輸出功能。在TPL階段,系統(tǒng)還沒有加載完整的函數(shù)庫,因此需要直接操作NS16550串口控制器實(shí)現(xiàn)putc(輸出字符)和puts(輸出字符串)函數(shù)。
特別注意到對換行符n的處理——自動(dòng)轉(zhuǎn)換為rn(回車+換行),這是為了保證在串口終端上能正確換行,細(xì)節(jié)處體現(xiàn)了調(diào)試友好性。
2.時(shí)間管理:系統(tǒng)的"心跳"初始化
int__weaktimer_init(void){return0; }void__weak __udelay(unsignedlongusec){u64 i, j, count;asmvolatile("MRS %0, CNTPCT_EL0":"=r"(count));i = count;j = usec *24; // 24MHz計(jì)數(shù)器i += j;while(1) {asmvolatile("MRS %0, CNTPCT_EL0":"=r"(count));if(count > i)break;}}// 非ARM64架構(gòu)的延遲實(shí)現(xiàn)voidudelay(unsignedlongusec){ __udelay(usec); }
時(shí)間延遲是硬件初始化的關(guān)鍵需求(比如等待外設(shè)上電穩(wěn)定)。這段代碼通過直接操作CPU計(jì)數(shù)器寄存器:
?為ARM64架構(gòu)讀取CNTPCT_EL0寄存器
?為其他架構(gòu)使用mrrc p15指令
?基于24MHz的基準(zhǔn)頻率計(jì)算延遲時(shí)間
這種底層實(shí)現(xiàn)確保了在沒有操作系統(tǒng)支持的情況下,系統(tǒng)仍能獲得精確的微秒級延遲能力。
3.核心初始化流程:board_init_f的使命
作為TPL階段的主入口函數(shù),board_init_f串起了整個(gè)初始化流程:
voidboard_init_f(ulongdummy){rockchip_stimer_init(); // 系統(tǒng)定時(shí)器初始化arch_cpu_init(); // CPU架構(gòu)初始化debug_uart_init(); // 調(diào)試串口初始化printascii("U-Boot TPL "PLAIN_VERSION"...n"); // 版本信息打印timer_init(); // 定時(shí)器初始化// DRAM初始化(根據(jù)配置選擇設(shè)備模型或直接調(diào)用)ret = uclass_get_device(UCLASS_RAM,0, &dev);sdram_init();// 條件允許時(shí)返回BootROM執(zhí)行下一階段back_to_bootrom(BROM_BOOT_NEXTSTAGE);}
這個(gè)函數(shù)的執(zhí)行邏輯清晰展現(xiàn)了TPL的核心任務(wù):
1.初始化系統(tǒng)定時(shí)器,建立時(shí)間基準(zhǔn)
2.完成CPU架構(gòu)相關(guān)初始化
3.啟動(dòng)調(diào)試串口,輸出版本信息(關(guān)鍵的調(diào)試點(diǎn))
4.初始化DRAM(內(nèi)存),為后續(xù)階段提供運(yùn)行空間
5.交接控制權(quán)到下一階段
對啟動(dòng)流程的關(guān)鍵作用
TPL作為啟動(dòng)的"第一棒",其工作質(zhì)量直接決定了系統(tǒng)能否正常啟動(dòng):
1.硬件最小化初始化:在資源受限的環(huán)境下,優(yōu)先初始化串口、定時(shí)器、內(nèi)存等關(guān)鍵硬件,為后續(xù)階段鋪路
2.啟動(dòng)流程銜接:通過back_to_bootrom函數(shù)與BootROM協(xié)作,確保啟動(dòng)流程按順序推進(jìn)
3.兼容性適配:通過條件編譯(如CONFIG_ARM64、CONFIG_TPL_LIBCOMMON_SUPPORT)支持不同架構(gòu)和配置,提高代碼復(fù)用性
4.故障隔離:如果TPL階段失敗(如DRAM初始化出錯(cuò)),系統(tǒng)會(huì)在早期掛起,避免錯(cuò)誤擴(kuò)散
對調(diào)試工作的特殊意義
對于嵌入式開發(fā)者來說,TPL階段的調(diào)試支持堪稱"救命稻草":
1.早期日志輸出:通過debug_uart_init和printascii實(shí)現(xiàn)的早期打印,能幫助定位啟動(dòng)失敗的第一現(xiàn)場。想象一下,如果連"U-Boot TPL版本信息"都打印不出來,排查問題會(huì)有多困難!
2.時(shí)序問題排查:精確的udelay函數(shù)確保硬件初始化時(shí)序正確,減少因時(shí)序錯(cuò)誤導(dǎo)致的"偶發(fā)故障"
3.版本追溯:啟動(dòng)時(shí)打印的版本號(hào)(PLAIN_VERSION)和編譯時(shí)間,能快速確認(rèn)是否使用了正確的代碼版本
4.錯(cuò)誤定位:hang函數(shù)在出錯(cuò)時(shí)進(jìn)入死循環(huán),配合JTAG等工具可捕獲現(xiàn)場狀態(tài),避免系統(tǒng)"crash后無痕跡"
總結(jié):TPL——啟動(dòng)流程的"基石"
tpl.c雖然代碼量不大,卻承載了嵌入式系統(tǒng)啟動(dòng)最基礎(chǔ)也最關(guān)鍵的工作。它像一位嚴(yán)謹(jǐn)?shù)?/span>"系統(tǒng)初始化工程師",在資源極度有限的環(huán)境下,有條不紊地完成硬件喚醒、環(huán)境準(zhǔn)備和流程交接。
對于開發(fā)者而言,理解TPL代碼不僅能幫助我們快速定位啟動(dòng)問題,更能深入理解嵌入式系統(tǒng)從"斷電"到"運(yùn)行"的整個(gè)喚醒過程。下次調(diào)試啟動(dòng)故障時(shí),不妨先看看TPL階段的日志輸出——答案往往就藏在這些最早期的信息里。
-
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3747瀏覽量
133621 -
u-boot
+關(guān)注
關(guān)注
0文章
135瀏覽量
39747 -
代碼
+關(guān)注
關(guān)注
30文章
4967瀏覽量
73954
發(fā)布評論請先 登錄
嵌入式Linux啟動(dòng)時(shí)間優(yōu)化的秘密之五-Bootloader
嵌入式系統(tǒng)中U-Boot 基本特點(diǎn)及其移植方法
嵌入式系統(tǒng)中U-Boot 基本特點(diǎn)及其移植方法
U-Boot的啟動(dòng)及移植分析
一種在U-BOOT中嵌入千兆網(wǎng)絡(luò)功能的方法
嵌入式U-BOOT的啟動(dòng)流程及移植
基于ARM9的U-Boot自動(dòng)識(shí)別啟動(dòng)實(shí)現(xiàn)
u-boot學(xué)習(xí)指南
嵌入式Linux系統(tǒng)移植開發(fā)-(1)基于Yocto構(gòu)建嵌入式u-boot,內(nèi)核,文件系統(tǒng)
U-Boot架構(gòu)淺析
嵌入式系統(tǒng)中u-boot和bootloader詳解
解析Rockchip平臺(tái)U-Boot核心文件:boot_rkimg.c到底做了什么?
深入理解?RK3506 U-Boot?重定位:從代碼到原理
深入解析U-Boot image.c:RK平臺(tái)鏡像處理核心邏輯
深入解析U-Boot TPL代碼:嵌入式啟動(dòng)的“第一棒”背后的秘密
評論