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

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

背景

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

啟動失敗問題

問題簡述

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

消失的打印

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

驗證改動

為了求證,將庫反匯編出來,發(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
當然更好的改法,是直接在新版本的 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快。嘗試將舊 ubootcache關掉,則二者基本一致。嘗試將舊 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)核到底是快是慢。
支持過程碰到了一些小問題
1. spl沒有能力加載這么大的 kernel
解決:此時不需要 kernel能完全啟動,只需要能加載啟動一段,足以體現(xiàn)出啟動速度是否正常即可,于是裁剪出一個非常小 kernel來輔助實驗。
2. kernel需要 dtb
解決:內(nèi)核有一個 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE選項。選上重新編譯。編譯后再用 ddkerneldtb拼接到一起,作為新的 kernel。這樣, spl就只需要加載一個文件并跳轉(zhuǎn)過去即可。
試驗結果, spl啟動的 kernel和使用新 uboot啟動的 kernel速度一致,均比舊 uboot啟動的 kernel慢。
說明,舊 uboot中做了某個關鍵操作,而新 uboot沒做。

找出關鍵操作

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

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

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

  4. 如果在舊ubootA點跳轉(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
ubootstart.S中沒有這段代碼,嘗試在新 ubootstart.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




推薦閱讀



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


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

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

嵌入式ARM

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

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

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅(qū)動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅(qū)動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅(qū)動性能的關鍵。

關鍵字: 工業(yè)電機 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅(qū)動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質(zhì)量和效率直接關系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅(qū)動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關鍵字: LED 驅(qū)動電源 開關電源

LED驅(qū)動電源是把電源供應轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅(qū)動電源
關閉