日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > > 嵌入式微處理器
[導(dǎo)讀]之前做過一次 uboot的升級,當(dāng)時留下了一些記錄,本文摘錄其中比較有意思的兩個問題。

背景

之前做過一次 uboot的升級,當(dāng)時留下了一些記錄,本文摘錄其中比較有意思的兩個問題。

啟動失敗問題

問題簡述

uboot代碼中用到了一個庫,考慮到庫本身跟 uboot版本沒什么關(guān)系,就直接把舊的庫文件拷貝過來使用。結(jié)果編譯鏈接是沒問題,啟動卻會卡住。

消失的打印

為了明確卡住的位置,就去修改了庫的源碼,添加一些打印(此時還是在舊版本 uboot下編譯的),結(jié)果發(fā)現(xiàn)卡住的位置或隨著添加打印的變化而變化,且有些打印語句,添加后未打印出來。
我決定先從這些神秘消失的打印入手。
分析下 uboot中的 printf實現(xiàn),最底層就是寫寄存器,是一個同步的函數(shù),也沒什么可疑的地方。
為了確認打印不出來的時候,到底有沒有調(diào)用到 printf,我決定給 printf增加一個計數(shù)器,在 gd結(jié)構(gòu)體中,增加一個 printf_count字段,初始化為 0,每次打印時執(zhí)行 printf_count++并打印出值。
設(shè)計這個試驗,本意是確認未打印出來時是否確實也調(diào)用到了 printf,但卻有了別的發(fā)現(xiàn),實驗結(jié)果中 printf_count值會異常變化,不是按打印順序遞增,而是會突變成很大的異常值。
printf_countgd結(jié)構(gòu)體的成員,那就是 gd的問題了。進一步將 uboot全局結(jié)構(gòu)體 gd的地址打印出來。確認了原因是 gd結(jié)構(gòu)體的指針變化了。
這也可以解釋部分打印消失的現(xiàn)象,原因是我們在 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的代碼不能正常工作。

驗證改動

為了求證,將庫反匯編出來,發(fā)現(xiàn)確實避開了 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
當(dāng)然更好的改法,是直接在新版本的 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)核,為什么差異這么大。

排查寄存器

初步排查了下設(shè)備樹配置,以及 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快。嘗試將舊 ubootcache關(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少做

當(dāng)時到這一步就卡住了,直接比較兩份 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)核到底是快是慢。
支持過程碰到了一些小問題
1. spl沒有能力加載這么大的 kernel
解決:此時不需要 kernel能完全啟動,只需要能加載啟動一段,足以體現(xiàn)出啟動速度是否正常即可,于是裁剪出一個非常小 kernel來輔助實驗。
2. kernel需要 dtb
解決:內(nèi)核有一個 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE選項。選上重新編譯。編譯后再用 ddkerneldtb拼接到一起,作為新的 kernel。這樣, spl就只需要加載一個文件并跳轉(zhuǎn)過去即可。
試驗結(jié)果, spl啟動的 kernel和使用新 uboot啟動的 kernel速度一致,均比舊 uboot啟動的 kernel慢。
說明,舊 uboot中做了某個關(guān)鍵操作,而新 uboot沒做。

找出關(guān)鍵操作

那接下來的任務(wù)就是,找出舊 uboot中的這個關(guān)鍵操作了。
怎么找呢?有了上一步的成果,我們可以使用以下方法來排查
  1. spl加載kernel和舊uboot

  2. spl跳轉(zhuǎn)到舊uboot,此時kernel其實已經(jīng)在dram中準(zhǔn)備好了,隨時可以啟動

  3. 在舊uboot的啟動流程各個階段,嘗試直接跳轉(zhuǎn)到kernel,觀察啟動速度

  4. 如果在舊ubootA點跳轉(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
ubootstart.S中沒有這段代碼,嘗試在新 ubootstart.S中添加此操作,速度立馬恢復(fù)正常了。
再全局搜索下,原來這個新版本 uboot中,套路是在 board_init中進行此項設(shè)置的,而這個平臺從舊版本移植過來,就沒有設(shè)置 SMP bit, 補上即可。

SMP bit是什么

SMP 是指對稱多處理器,看起來這個 bit 會影響多核的 cache一致性,此處沒有再深入研究。
但可以知道,對于單處理器的情況,也需要設(shè)置這個 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




推薦閱讀



【01】C語言內(nèi)存泄露很嚴(yán)重,如何應(yīng)對?
【02】編譯C語言程序,使用 gcc 指令,而C++程序則推薦使用 g++指令!
【03】C語言:優(yōu)雅的字符串函數(shù)庫
【04】在C 語言中,請一定記得初始化局部變量!
【05】嵌入式編程是否應(yīng)該用C++替代C語言


免責(zé)聲明:整理文章為傳播相關(guān)技術(shù),版權(quán)歸原作者所有,如有侵權(quán),請聯(lián)系刪除

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除( 郵箱:macysun@21ic.com )。
換一批
延伸閱讀
關(guān)閉