背景
uboot
的升級,當(dāng)時留下了一些記錄,本文摘錄其中比較有意思的兩個問題。
啟動失敗問題
問題簡述
uboot
代碼中用到了一個庫,考慮到庫本身跟
uboot
版本沒什么關(guān)系,就直接把舊的庫文件拷貝過來使用。結(jié)果編譯鏈接是沒問題,啟動卻會卡住。
消失的打印
uboot
下編譯的),結(jié)果發(fā)現(xiàn)卡住的位置或隨著添加打印的變化而變化,且有些打印語句,添加后未打印出來。
uboot
中的
printf
實現(xiàn),最底層就是寫寄存器,是一個同步的函數(shù),也沒什么可疑的地方。
printf
,我決定給
printf
增加一個計數(shù)器,在
gd
結(jié)構(gòu)體中,增加一個
printf_count
字段,初始化為
0
,每次打印時執(zhí)行
printf_count++
并打印出值。
printf
,但卻有了別的發(fā)現(xiàn),實驗結(jié)果中
printf_count
值會異常變化,不是按打印順序遞增,而是會突變成很大的異常值。
printf_count
是
gd
結(jié)構(gòu)體的成員,那就是
gd
的問題了。進一步將
uboot
全局結(jié)構(gòu)體
gd
的地址打印出來。確認了原因是
gd
結(jié)構(gòu)體的指針變化了。
gd
中有另一個字段,用于控制打印等級。當(dāng)
gd
被改動了,
printf
就可能解析出錯,誤以為打印等級為
0
而提前返回。
gd的實現(xiàn)
gd
為什么會被改了呢?這就要先看看
gd
到底是怎么實現(xiàn)的了。
uboot
中維護了一個全局的結(jié)構(gòu)體
gd
。在代碼中加入
DECLARE_GLOBAL_DATA_PTR;
gd
指針訪問這個全局結(jié)構(gòu)體,許多地方都會借助
gd
來保存?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
寄存器,一個是放在
r9
寄存器。
uboot
中編譯出來的,可能使用了
r9
,那么放到新版本
uboot
中去,就會破壞
r9
寄存器中保存的
gd
值,導(dǎo)致一系列依賴
gd
的代碼不能正常工作。
驗證改動
r8
寄存器,但使用了
r9
寄存器。
uboot
在指定
gd
寄存器的同時,還有某種方法讓其他代碼不使用這個寄存器。
uboot
中的這個
r8
改成
r9
,重新編譯庫就可以了呢?試一下,還是不行。
r8
寄存器肯定就是通過別的方式實現(xià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
,重新編譯出庫,這回就可以正常工作了,打印正常,啟動正常。反匯編出來也可以看到,新編譯出來的庫用了
r8
沒有用
r9
。
uboot
中編譯,這是最可靠的。
追本溯源
uboot
,會使用不同的寄存器呢?難道有什么坑?
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
記錄中,也可以確認完整地將
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!?*/
啟動慢問題
問題簡述
uboot
可以啟動到內(nèi)核了,但發(fā)現(xiàn)啟動速度非常慢,內(nèi)核啟動速度慢了接近
10
倍!明明是同一個內(nèi)核,為什么差異這么大。
排查寄存器
uboot
跳轉(zhuǎn)內(nèi)核前的一些關(guān)鍵寄存器,確實在兩個版本的
uboot中
有所不同,但具體去看這些不同,發(fā)現(xiàn)都不會影響速度,將一些驅(qū)動對齊之后寄存器差異基本就消失了。
差異的分界
kernel
的速度有差異,
uboot
呢?在哪個時間點之后,速度開始產(chǎn)生差異?
uboot
中插入一些操作,對比時間戳,發(fā)現(xiàn)兩個
uboot
在某個節(jié)點之后的速度確實有區(qū)別。
cache
操作之后,舊
uboot
的速度就會比新
uboot
快。嘗試將舊
uboot
的
cache
關(guān)掉,則二者基本一致。嘗試將舊
uboot
操作
cache
的代碼,移植到新
uboot
,未發(fā)生改變。
uboot
的開
cache
有問題。但覺得這個跟
kernel
啟動慢沒關(guān)系。因為
uboot
進入
kernel
之前都會關(guān)
cache
,由
kernel
自己去重新打開。
uboot
,也不管
uboot
中是否開了
cache
,對
kernel
階段都應(yīng)該沒有影響才對。
uboot
的這個問題,待后續(xù)修復(fù)。先繼續(xù)找
kernel
啟動慢的原因。(注:現(xiàn)在看來當(dāng)時的做法是有問題的,這里的異常這么明顯,應(yīng)該設(shè)法追蹤下去找出原因才對)
鎖定uboot
uboot
的嫌疑非常大,但還不能完全確認,因為
uboot
之前還有一級
spl
。是否會是
spl
的問題呢?
新spl+舊uboot
,啟動速度正常。而新
spl+新uboot
的啟動速度則很慢,其他因素都不變,說明問題確實出在
uboot
階段。
多做or少做
uboot
的代碼不太現(xiàn)實,差異太大了。
uboot
是多做了某件事情,還是少做了某件事情?
spl?-->?舊uboot?-->?kernel(速度快)
spl?-->?新uboot?-->?kernel(速度快)
A
還是情況
B
呢?
A:?spl(速度慢)?-->?舊uboot(做了某個會提升速度的操作)?-->?kernel(速度快)
???spl(速度慢)?-->?新uboot(少做了某個會提升速度的操作)?-->?kernel(速度慢)
B:?spl(速度快)?-->?舊uboot(沒做特殊操作)?-->?kernel(速度快)
???spl(速度快)?-->?新uboot(多做了某個會限制速度的操作)?-->?kernel(速度慢)
spl
直接啟動內(nèi)核,看看內(nèi)核到底是快是慢。
spl
沒有能力加載這么大的
kernel
kernel
能完全啟動,只需要能加載啟動一段,足以體現(xiàn)出啟動速度是否正常即可,于是裁剪出一個非常小
kernel
來輔助實驗。
kernel
需要
dtb
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE
選項。選上重新編譯。編譯后再用
dd
將
kernel
和
dtb
拼接到一起,作為新的
kernel
。這樣,
spl
就只需要加載一個文件并跳轉(zhuǎn)過去即可。
spl
啟動的
kernel
和使用新
uboot
啟動的
kernel
速度一致,均比舊
uboot
啟動的
kernel
慢。
uboot
中做了某個關(guān)鍵操作,而新
uboot
沒做。
找出關(guān)鍵操作
uboot
中的這個關(guān)鍵操作了。
-
spl
加載kernel
和舊uboot
-
spl
跳轉(zhuǎn)到舊uboot
,此時kernel
其實已經(jīng)在dram
中準(zhǔn)備好了,隨時可以啟動 -
在舊
uboot
的啟動流程各個階段,嘗試直接跳轉(zhuǎn)到kernel
,觀察啟動速度 -
如果在舊
uboot
的A
點跳轉(zhuǎn)kernel
啟動慢,B
點跳轉(zhuǎn)啟動快,則說明關(guān)鍵操作位于AB
點之間。
start.S
,進一步在
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
中沒有這段代碼,嘗試在新
uboot
的
start.S
中添加此操作,速度立馬恢復(fù)正常了。
uboot
中,套路是在
board_init
中進行此項設(shè)置的,而這個平臺從舊版本移植過來,就沒有設(shè)置
SMP bit
, 補上即可。
SMP bit是什么
SMP
是指對稱多處理器,看起來這個
bit
會影響多核的
cache
一致性,此處沒有再深入研究。
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)用了的。不過這個芯片是單核的,根本就沒配置
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)時的一些操作。
bug
可能以后都不會碰到了,但解
bug
的方法和思路卻是可以積累復(fù)用的。
-END-
本文授權(quán)轉(zhuǎn)載自qb雜貨鋪,作者:瞎折騰的zqb
推薦閱讀
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!