坑!uboot升級(jí)過程遇到的兩個(gè)bug
背景
uboot的升級(jí),當(dāng)時(shí)留下了一些記錄,本文摘錄其中比較有意思的兩個(gè)問題。
啟動(dòng)失敗問題
問題簡述
uboot代碼中用到了一個(gè)庫,考慮到庫本身跟
uboot版本沒什么關(guān)系,就直接把舊的庫文件拷貝過來使用。結(jié)果編譯鏈接是沒問題,啟動(dòng)卻會(huì)卡住。
消失的打印
uboot下編譯的),結(jié)果發(fā)現(xiàn)卡住的位置或隨著添加打印的變化而變化,且有些打印語句,添加后未打印出來。
uboot中的
printf實(shí)現(xiàn),最底層就是寫寄存器,是一個(gè)同步的函數(shù),也沒什么可疑的地方。
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的問題了。進(jìn)一步將
uboot全局結(jié)構(gòu)體
gd的地址打印出來。確認(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指針訪問這個(gè)全局結(jié)構(gòu)體,許多地方都會(huì)借助
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寄存器,一個(gè)是放在
r9寄存器。
uboot中編譯出來的,可能使用了
r9,那么放到新版本
uboot中去,就會(huì)破壞
r9寄存器中保存的
gd值,導(dǎo)致一系列依賴
gd的代碼不能正常工作。
驗(yàn)證改動(dòng)
r8寄存器,但使用了
r9寄存器。
uboot在指定
gd寄存器的同時(shí),還有某種方法讓其他代碼不使用這個(gè)寄存器。
uboot中的這個(gè)
r8改成
r9,重新編譯庫就可以了呢?試一下,還是不行。
r8寄存器肯定就是通過別的方式實(shí)現(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,重新編譯出庫,這回就可以正常工作了,打印正常,啟動(dòng)正常。反匯編出來也可以看到,新編譯出來的庫用了
r8沒有用
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)慢問題
問題簡述
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)之后,速度開始產(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的開
cache有問題。但覺得這個(gè)跟
kernel啟動(dòng)慢沒關(guān)系。因?yàn)?
uboot進(jìn)入
kernel之前都會(huì)關(guān)
cache,由
kernel自己去重新打開。
uboot,也不管
uboot中是否開了
cache,對(duì)
kernel階段都應(yīng)該沒有影響才對(duì)。
uboot的這個(gè)問題,待后續(xù)修復(fù)。先繼續(xù)找
kernel啟動(dòng)慢的原因。(注:現(xiàn)在看來當(dāng)時(shí)的做法是有問題的,這里的異常這么明顯,應(yīng)該設(shè)法追蹤下去找出原因才對(duì))
鎖定uboot
uboot的嫌疑非常大,但還不能完全確認(rèn),因?yàn)?
uboot之前還有一級(jí)
spl。是否會(huì)是
spl的問題呢?
新spl+舊uboot,啟動(dòng)速度正常。而新
spl+新uboot的啟動(dòng)速度則很慢,其他因素都不變,說明問題確實(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(沒做特殊操作)?-->?kernel(速度快)
???spl(速度快)?-->?新uboot(多做了某個(gè)會(huì)限制速度的操作)?-->?kernel(速度慢)
spl直接啟動(dòng)內(nèi)核,看看內(nèi)核到底是快是慢。
spl沒有能力加載這么大的
kernel
kernel能完全啟動(dòng),只需要能加載啟動(dòng)一段,足以體現(xiàn)出啟動(dòng)速度是否正常即可,于是裁剪出一個(gè)非常小
kernel來輔助實(shí)驗(yàn)。
kernel需要
dtb
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE選項(xiàng)。選上重新編譯。編譯后再用
dd將
kernel和
dtb拼接到一起,作為新的
kernel。這樣,
spl就只需要加載一個(gè)文件并跳轉(zhuǎn)過去即可。
spl啟動(dòng)的
kernel和使用新
uboot啟動(dòng)的
kernel速度一致,均比舊
uboot啟動(dòng)的
kernel慢。
uboot中做了某個(gè)關(guān)鍵操作,而新
uboot沒做。
找出關(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)快,則說明關(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中沒有這段代碼,嘗試在新
uboot的
start.S中添加此操作,速度立馬恢復(fù)正常了。
uboot中,套路是在
board_init中進(jìn)行此項(xiàng)設(shè)置的,而這個(gè)平臺(tái)從舊版本移植過來,就沒有設(shè)置
SMP bit, 補(bǔ)上即可。
SMP bit是什么
SMP 是指對(duì)稱多處理器,看起來這個(gè)
bit 會(huì)影響多核的
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)用了的。不過這個(gè)芯片是單核的,根本就沒配置
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),如有問題,請(qǐng)聯(lián)系我們,謝謝!






