坑!uboot升級(jí)過(guò)程遇到的兩個(gè)bug
背景
uboot
的升級(jí),當(dāng)時(shí)留下了一些記錄,本文摘錄其中比較有意思的兩個(gè)問(wèn)題。
啟動(dòng)失敗問(wèn)題
問(wèn)題簡(jiǎn)述
uboot
代碼中用到了一個(gè)庫(kù),考慮到庫(kù)本身跟
uboot
版本沒(méi)什么關(guān)系,就直接把舊的庫(kù)文件拷貝過(guò)來(lái)使用。結(jié)果編譯鏈接是沒(méi)問(wèn)題,啟動(dòng)卻會(huì)卡住。
消失的打印
uboot
下編譯的),結(jié)果發(fā)現(xiàn)卡住的位置或隨著添加打印的變化而變化,且有些打印語(yǔ)句,添加后未打印出來(lái)。
uboot
中的
printf
實(shí)現(xiàn),最底層就是寫(xiě)寄存器,是一個(gè)同步的函數(shù),也沒(méi)什么可疑的地方。
printf
,我決定給
printf
增加一個(gè)計(jì)數(shù)器,在
gd
結(jié)構(gòu)體中,增加一個(gè)
printf_count
字段,初始化為
0
,每次打印時(shí)執(zhí)行
printf_count++
并打印出值。
printf
,但卻有了別的發(fā)現(xiàn),實(shí)驗(yàn)結(jié)果中
printf_count
值會(huì)異常變化,不是按打印順序遞增,而是會(huì)突變成很大的異常值。
printf_count
是
gd
結(jié)構(gòu)體的成員,那就是
gd
的問(wèn)題了。進(jìn)一步將
uboot
全局結(jié)構(gòu)體
gd
的地址打印出來(lái)。確認(rèn)了原因是
gd
結(jié)構(gòu)體的指針變化了。
gd
中有另一個(gè)字段,用于控制打印等級(jí)。當(dāng)
gd
被改動(dòng)了,
printf
就可能解析出錯(cuò),誤以為打印等級(jí)為
0
而提前返回。
gd的實(shí)現(xiàn)
gd
為什么會(huì)被改了呢?這就要先看看
gd
到底是怎么實(shí)現(xiàn)的了。
uboot
中維護(hù)了一個(gè)全局的結(jié)構(gòu)體
gd
。在代碼中加入
DECLARE_GLOBAL_DATA_PTR;
gd
指針訪問(wèn)這個(gè)全局結(jié)構(gòu)體,許多地方都會(huì)借助
gd
來(lái)保存?zhèn)鬟f信息。
舊版本uboot:
#define?DECLARE_GLOBAL_DATA_PTR????????register?volatile?gd_t?*gd?asm?("r8")
新版本uboot:
#define?DECLARE_GLOBAL_DATA_PTR????????register?volatile?gd_t?*gd?asm?("r9")
gd
的值放到
r8
寄存器,一個(gè)是放在
r9
寄存器。
uboot
中編譯出來(lái)的,可能使用了
r9
,那么放到新版本
uboot
中去,就會(huì)破壞
r9
寄存器中保存的
gd
值,導(dǎo)致一系列依賴
gd
的代碼不能正常工作。
驗(yàn)證改動(dòng)
r8
寄存器,但使用了
r9
寄存器。
uboot
在指定
gd
寄存器的同時(shí),還有某種方法讓其他代碼不使用這個(gè)寄存器。
uboot
中的這個(gè)
r8
改成
r9
,重新編譯庫(kù)就可以了呢?試一下,還是不行。
r8
寄存器肯定就是通過(guò)別的方式實(shí)現(xiàn)的了。簡(jiǎn)單粗暴地在舊版本
uboot
下搜索
r8
,去掉
.c .h
等類型后,很容易發(fā)現(xiàn)了
./arch/arm/cpu/armv7/config.mk:24:PLATFORM_RELFLAGS?+=?-fno-common?-ffixed-r8?-msoft-floa
-ffixed-r8
修改為
-ffixed-r9
,重新編譯出庫(kù),這回就可以正常工作了,打印正常,啟動(dòng)正常。反匯編出來(lái)也可以看到,新編譯出來(lái)的庫(kù)用了
r8
沒(méi)有用
r9
。
uboot
中編譯,這是最可靠的。
追本溯源
uboot
,會(huì)使用不同的寄存器呢?難道有什么坑?
git
記錄了。
commit?fe1378a961e508b31b1f29a2bb08ba1dac063155
Author:?Jeroen?Hofstee?
Date:???Sat?Sep?21?14:04:41?2013?+0200
????ARM:?use?r9? for?gd
????
????To?be?more?EABI?compliant?and?as?a?preparation? for?building
????with?clang,?use?the?platform-specific?r9?register? for?gd
????instead?of?r8.
????
????note:?The?FIQ?is?not?updated?since?it?is?not?used? in?u-boot,
????and?under?discussion? for?the?time?being.
????
????The?following?checkpatch?warning?is?ignored:
????WARNING:?Use?of?volatile?is?usually?wrong:?see
????Documentation/volatile-considered-harmful.txt
????
????Signed-off-by:?Jeroen?Hofstee?
????cc:?Albert?ARIBAUD?
git
記錄中,也可以確認(rèn)完整地將
r8
切換到
r9
,都需要做哪些修改
diff?--git?a/arch/arm/config.mk?b/arch/arm/config.mk
index? 16c2e3d1e0..d0cf43ff41? 100644
---?a/arch/arm/config.mk
+++?b/arch/arm/config.mk
@@? -17, 7?+ 17, 7?@@?endif
?
?LDFLAGS_FINAL?+=?--gc-sections
?PLATFORM_RELFLAGS?+=?-ffunction-sections?-fdata-sections?\
-?????????????????????-fno-common?-ffixed-r8?-msoft- float
+?????????????????????-fno-common?-ffixed-r9?-msoft- float
?
?#?Support?generic?board?on?ARM
?__HAVE_ARCH_GENERIC_BOARD?:=?y
diff?--git?a/arch/arm/cpu/armv7/lowlevel_init.S?b/arch/arm/cpu/armv7/lowlevel_init.S
index? 82b2b86520. .69e3053a42? 100644
---?a/arch/arm/cpu/armv7/lowlevel_init.S
+++?b/arch/arm/cpu/armv7/lowlevel_init.S
@@? -22, 11?+ 22, 11?@@?ENTRY(lowlevel_init)
????????ldr?????sp,?=CONFIG_SYS_INIT_SP_ADDR
????????bic?????sp,?sp,?# 7? /*?8-byte?alignment?for?ABI?compliance?*/
?#ifdef?CONFIG_SPL_BUILD
-???????ldr?????r8,?=gdata
+???????ldr?????r9,?=gdata
?# else
????????sub?????sp,?#GD_SIZE
????????bic?????sp,?sp,?# 7
-???????mov?????r8,?sp
+???????mov?????r9,?sp
?#endif
???????? /*
?????????*?Save?the?old?lr(passed?in?ip)?and?the?current?lr?to?stack
diff?--git?a/arch/arm/include/asm/global_data.h?b/arch/arm/include/asm/global_data.h
index?79a9597419..e126436093?100644
---?a/arch/arm/include/asm/global_data.h
+++?b/arch/arm/include/asm/global_data.h
@@?-47,6?+47,6?@@?struct?arch_global_data?{
?
?#include?
?
-#define?DECLARE_GLOBAL_DATA_PTR?????register?volatile?gd_t?*gd?asm?("r8")
+#define?DECLARE_GLOBAL_DATA_PTR?????register?volatile?gd_t?*gd?asm?("r9")
?
?#endif?/*?__ASM_GBL_DATA_H?*/
diff?--git?a/arch/arm/lib/crt0.S?b/arch/arm/lib/crt0.S
index? 960d12e732..ac54b9359a? 100644
---?a/arch/arm/lib/crt0.S
+++?b/arch/arm/lib/crt0.S
@@? -69, 7?+ 69, 7?@@?ENTRY(_main)
????????bic?????sp,?sp,?# 7?????? /*?8-byte?alignment?for?ABI?compliance?*/
????????sub?????sp,?#GD_SIZE???? /*?allocate?one?GD?above?SP?*/
????????bic?????sp,?sp,?# 7?????? /*?8-byte?alignment?for?ABI?compliance?*/
-???????mov?????r8,?sp?????????? /*?GD?is?above?SP?*/
+???????mov?????r9,?sp?????????? /*?GD?is?above?SP?*/
????????mov?????r0,?# 0
????????bl??????board_init_f
?
@@? -81, 15?+ 81, 15?@@?ENTRY(_main)
??*? 'here'?but?relocated.
??*/
?
-???????ldr?????sp,?[r8,?#GD_START_ADDR_SP]????? /*?sp?=?gd->start_addr_sp?*/
+???????ldr?????sp,?[r9,?#GD_START_ADDR_SP]????? /*?sp?=?gd->start_addr_sp?*/
????????bic?????sp,?sp,?# 7?????? /*?8-byte?alignment?for?ABI?compliance?*/
-???????ldr?????r8,?[r8,?#GD_BD]???????????????? /*?r8?=?gd->bd?*/
-???????sub?????r8,?r8,?#GD_SIZE???????????????? /*?new?GD?is?below?bd?*/
+???????ldr?????r9,?[r9,?#GD_BD]???????????????? /*?r9?=?gd->bd?*/
+???????sub?????r9,?r9,?#GD_SIZE???????????????? /*?new?GD?is?below?bd?*/
?
????????adr?????lr,?here
-???????ldr?????r0,?[r8,?#GD_RELOC_OFF]????????? /*?r0?=?gd->reloc_off?*/
+???????ldr?????r0,?[r9,?#GD_RELOC_OFF]????????? /*?r0?=?gd->reloc_off?*/
????????add?????lr,?lr,?r0
-???????ldr?????r0,?[r8,?#GD_RELOCADDR]????????? /*?r0?=?gd->relocaddr?*/
+???????ldr?????r0,?[r9,?#GD_RELOCADDR]????????? /*?r0?=?gd->relocaddr?*/
????????b???????relocate_code
?here:
?
@@? -111, 8?+ 111, 8?@@?clbss_l:cmp?r0,?r1?????????????????? /*?while?not?at?end?of?BSS?*/
????????bl?red_led_on
?
???????? /*?call?board_init_r(gd_t?*id,?ulong?dest_addr)?*/
-???????mov?????r0,?r8?????????????????? /*?gd_t?*/
-???????ldr?????r1,?[r8,?#GD_RELOCADDR]? /*?dest_addr?*/
+???????mov?????r0,?r9?????????????????? /*?gd_t?*/
+???????ldr?????r1,?[r9,?#GD_RELOCADDR]? /*?dest_addr?*/
???????? /*?call?board_init_r?*/
????????ldr?????pc,?=board_init_r??????? /*?this?is?auto-relocated!?*/
啟動(dòng)慢問(wèn)題
問(wèn)題簡(jiǎn)述
uboot
可以啟動(dòng)到內(nèi)核了,但發(fā)現(xiàn)啟動(dòng)速度非常慢,內(nèi)核啟動(dòng)速度慢了接近
10
倍!明明是同一個(gè)內(nèi)核,為什么差異這么大。
排查寄存器
uboot
跳轉(zhuǎn)內(nèi)核前的一些關(guān)鍵寄存器,確實(shí)在兩個(gè)版本的
uboot中
有所不同,但具體去看這些不同,發(fā)現(xiàn)都不會(huì)影響速度,將一些驅(qū)動(dòng)對(duì)齊之后寄存器差異基本就消失了。
差異的分界
kernel
的速度有差異,
uboot
呢?在哪個(gè)時(shí)間點(diǎn)之后,速度開(kāi)始產(chǎn)生差異?
uboot
中插入一些操作,對(duì)比時(shí)間戳,發(fā)現(xiàn)兩個(gè)
uboot
在某個(gè)節(jié)點(diǎn)之后的速度確實(shí)有區(qū)別。
cache
操作之后,舊
uboot
的速度就會(huì)比新
uboot
快。嘗試將舊
uboot
的
cache
關(guān)掉,則二者基本一致。嘗試將舊
uboot
操作
cache
的代碼,移植到新
uboot
,未發(fā)生改變。
uboot
的開(kāi)
cache
有問(wèn)題。但覺(jué)得這個(gè)跟
kernel
啟動(dòng)慢沒(méi)關(guān)系。因?yàn)?
uboot
進(jìn)入
kernel
之前都會(huì)關(guān)
cache
,由
kernel
自己去重新打開(kāi)。
uboot
,也不管
uboot
中是否開(kāi)了
cache
,對(duì)
kernel
階段都應(yīng)該沒(méi)有影響才對(duì)。
uboot
的這個(gè)問(wèn)題,待后續(xù)修復(fù)。先繼續(xù)找
kernel
啟動(dòng)慢的原因。(注:現(xiàn)在看來(lái)當(dāng)時(shí)的做法是有問(wèn)題的,這里的異常這么明顯,應(yīng)該設(shè)法追蹤下去找出原因才對(duì))
鎖定uboot
uboot
的嫌疑非常大,但還不能完全確認(rèn),因?yàn)?
uboot
之前還有一級(jí)
spl
。是否會(huì)是
spl
的問(wèn)題呢?
新spl+舊uboot
,啟動(dòng)速度正常。而新
spl+新uboot
的啟動(dòng)速度則很慢,其他因素都不變,說(shuō)明問(wèn)題確實(shí)出在
uboot
階段。
多做or少做
uboot
的代碼不太現(xiàn)實(shí),差異太大了。
uboot
是多做了某件事情,還是少做了某件事情?
spl?-->?舊uboot?-->?kernel(速度快)
spl?-->?新uboot?-->?kernel(速度快)
A
還是情況
B
呢?
A:?spl(速度慢)?-->?舊uboot(做了某個(gè)會(huì)提升速度的操作)?-->?kernel(速度快)
???spl(速度慢)?-->?新uboot(少做了某個(gè)會(huì)提升速度的操作)?-->?kernel(速度慢)
B:?spl(速度快)?-->?舊uboot(沒(méi)做特殊操作)?-->?kernel(速度快)
???spl(速度快)?-->?新uboot(多做了某個(gè)會(huì)限制速度的操作)?-->?kernel(速度慢)
spl
直接啟動(dòng)內(nèi)核,看看內(nèi)核到底是快是慢。
spl
沒(méi)有能力加載這么大的
kernel
kernel
能完全啟動(dòng),只需要能加載啟動(dòng)一段,足以體現(xiàn)出啟動(dòng)速度是否正常即可,于是裁剪出一個(gè)非常小
kernel
來(lái)輔助實(shí)驗(yàn)。
kernel
需要
dtb
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE
選項(xiàng)。選上重新編譯。編譯后再用
dd
將
kernel
和
dtb
拼接到一起,作為新的
kernel
。這樣,
spl
就只需要加載一個(gè)文件并跳轉(zhuǎn)過(guò)去即可。
spl
啟動(dòng)的
kernel
和使用新
uboot
啟動(dòng)的
kernel
速度一致,均比舊
uboot
啟動(dòng)的
kernel
慢。
uboot
中做了某個(gè)關(guān)鍵操作,而新
uboot
沒(méi)做。
找出關(guān)鍵操作
uboot
中的這個(gè)關(guān)鍵操作了。
-
spl
加載kernel
和舊uboot
-
spl
跳轉(zhuǎn)到舊uboot
,此時(shí)kernel
其實(shí)已經(jīng)在dram
中準(zhǔn)備好了,隨時(shí)可以啟動(dòng) -
在舊
uboot
的啟動(dòng)流程各個(gè)階段,嘗試直接跳轉(zhuǎn)到kernel
,觀察啟動(dòng)速度 -
如果在舊
uboot
的A
點(diǎn)跳轉(zhuǎn)kernel
啟動(dòng)慢,B
點(diǎn)跳轉(zhuǎn)啟動(dòng)快,則說(shuō)明關(guān)鍵操作位于AB
點(diǎn)之間。
start.S
,進(jìn)一步在
start.S
中揪出了這段代碼
#if?defined(CONFIG_ARM_A7)
@ set?SMP?bit
????mrc?????p15,? 0,?r0,?c1,?c0,? 1
????orr????????r0,?r0,?#( 1<< 6)
????mcr????????p15,? 0,?r0,?c1,?c0,? 1
#endif
uboot
的
start.S
中沒(méi)有這段代碼,嘗試在新
uboot
的
start.S
中添加此操作,速度立馬恢復(fù)正常了。
uboot
中,套路是在
board_init
中進(jìn)行此項(xiàng)設(shè)置的,而這個(gè)平臺(tái)從舊版本移植過(guò)來(lái),就沒(méi)有設(shè)置
SMP bit
, 補(bǔ)上即可。
SMP bit是什么
SMP
是指對(duì)稱多處理器,看起來(lái)這個(gè)
bit
會(huì)影響多核的
cache
一致性,此處沒(méi)有再深入研究。
bit
才能正常使用
cache
。
arm
的圖和描述:
[6]?SMP?
Signals? if?the?Cortex-A9?processor?is?taking?part? in?coherency?or?not.
In?uniprocessor?configurations,? if?this?bit?is? set,? then?Inner?Cacheable?Shared?is?treated?as?Cacheable.?The?reset?value?is?zero.
kernel
的代碼,發(fā)現(xiàn)也是有地方調(diào)用了的。不過(guò)這個(gè)芯片是單核的,根本就沒(méi)配置
CONFIG_SMP
。
#ifdef?CONFIG_SMP
?ALT_SMP(mrc?p15,? 0,?r0,?c1,?c0,? 1)
?ALT_UP(mov?r0,?#( 1?< 6))??@?fake?it? for?UP
?tst?r0,?#( 1?< 6)???@?SMP/nAMP?mode?enabled?
?orreq?r0,?r0,?#( 1?< 6)??@?Enable?SMP/nAMP?mode
?orreq?r0,?r0,?r10???@?Enable?CPU-specific?SMP?bits
?mcreq?p15,? 0,?r0,?c1,?c0,? 1
#endif
總結(jié)
bug
,另一方面也是想記錄下當(dāng)時(shí)的一些操作。
bug
可能以后都不會(huì)碰到了,但解
bug
的方法和思路卻是可以積累復(fù)用的。
-END-
本文授權(quán)轉(zhuǎn)載自qb雜貨鋪,作者:瞎折騰的zqb
推薦閱讀
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!