背景
uboot的升級,當時留下了一些記錄,本文摘錄其中比較有意思的兩個問題。
啟動失敗問題
問題簡述
uboot代碼中用到了一個庫,考慮到庫本身跟
uboot版本沒什么關系,就直接把舊的庫文件拷貝過來使用。結果編譯鏈接是沒問題,啟動卻會卡住。
消失的打印
uboot下編譯的),結果發(fā)現(xiàn)卡住的位置或隨著添加打印的變化而變化,且有些打印語句,添加后未打印出來。
uboot中的
printf實現(xiàn),最底層就是寫寄存器,是一個同步的函數(shù),也沒什么可疑的地方。
printf,我決定給
printf增加一個計數(shù)器,在
gd結構體中,增加一個
printf_count字段,初始化為
0,每次打印時執(zhí)行
printf_count++并打印出值。
printf,但卻有了別的發(fā)現(xiàn),實驗結果中
printf_count值會異常變化,不是按打印順序遞增,而是會突變成很大的異常值。
printf_count是
gd結構體的成員,那就是
gd的問題了。進一步將
uboot全局結構體
gd的地址打印出來。確認了原因是
gd結構體的指針變化了。
gd中有另一個字段,用于控制打印等級。當
gd被改動了,
printf就可能解析出錯,誤以為打印等級為
0而提前返回。
gd的實現(xiàn)
gd為什么會被改了呢?這就要先看看
gd到底是怎么實現(xiàn)的了。
uboot中維護了一個全局的結構體
gd。在代碼中加入
DECLARE_GLOBAL_DATA_PTR;
gd指針訪問這個全局結構體,許多地方都會借助
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值,導致一系列依賴
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)核前的一些關鍵寄存器,確實在兩個版本的
uboot中有所不同,但具體去看這些不同,發(fā)現(xiàn)都不會影響速度,將一些驅(qū)動對齊之后寄存器差異基本就消失了。
差異的分界
kernel的速度有差異,
uboot呢?在哪個時間點之后,速度開始產(chǎn)生差異?
uboot中插入一些操作,對比時間戳,發(fā)現(xiàn)兩個
uboot在某個節(jié)點之后的速度確實有區(qū)別。
cache操作之后,舊
uboot的速度就會比新
uboot快。嘗試將舊
uboot的
cache關掉,則二者基本一致。嘗試將舊
uboot操作
cache的代碼,移植到新
uboot,未發(fā)生改變。
uboot的開
cache有問題。但覺得這個跟
kernel啟動慢沒關系。因為
uboot進入
kernel之前都會關
cache,由
kernel自己去重新打開。
uboot,也不管
uboot中是否開了
cache,對
kernel階段都應該沒有影響才對。
uboot的這個問題,待后續(xù)修復。先繼續(xù)找
kernel啟動慢的原因。(注:現(xiàn)在看來當時的做法是有問題的,這里的異常這么明顯,應該設法追蹤下去找出原因才對)
鎖定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中做了某個關鍵操作,而新
uboot沒做。
找出關鍵操作
uboot中的這個關鍵操作了。
-
spl加載kernel和舊uboot -
spl跳轉(zhuǎn)到舊uboot,此時kernel其實已經(jīng)在dram中準備好了,隨時可以啟動 -
在舊
uboot的啟動流程各個階段,嘗試直接跳轉(zhuǎn)到kernel,觀察啟動速度 -
如果在舊
uboot的A點跳轉(zhuǎn)kernel啟動慢,B點跳轉(zhuǎ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中添加此操作,速度立馬恢復正常了。
uboot中,套路是在
board_init中進行此項設置的,而這個平臺從舊版本移植過來,就沒有設置
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
總結
bug,另一方面也是想記錄下當時的一些操作。
bug可能以后都不會碰到了,但解
bug的方法和思路卻是可以積累復用的。
-END-
本文授權轉(zhuǎn)載自qb雜貨鋪,作者:瞎折騰的zqb
推薦閱讀
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!






