在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

關于升級uboot遇到的兩個問題

Q4MP_gh_c472c21 ? 來源:qb雜貨鋪 ? 作者:qb雜貨鋪 ? 2020-09-21 11:41 ? 次閱讀

背景

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

啟動失敗問題

問題簡述

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

消失的打印

為了明確卡住的位置,就去修改了庫的源碼,添加一些打印(此時還是在舊版本uboot下編譯的),結果發現卡住的位置或隨著添加打印的變化而變化,且有些打印語句,添加后未打印出來。 我決定先從這些神秘消失的打印入手。 分析下uboot中的printf實現,最底層就是寫寄存器,是一個同步的函數,也沒什么可疑的地方。 為了確認打印不出來的時候,到底有沒有調用到printf,我決定給printf增加一個計數器,在gd結構體中,增加一個printf_count字段,初始化為0,每次打印時執行printf_count++并打印出值。 設計這個試驗,本意是確認未打印出來時是否確實也調用到了printf,但卻有了別的發現,實驗結果中printf_count值會異常變化,不是按打印順序遞增,而是會突變成很大的異常值。 printf_count是gd結構體的成員,那就是gd的問題了。進一步將uboot全局結構體gd的地址打印出來。確認了原因是gd結構體的指針變化了。 這也可以解釋部分打印消失的現象,原因是我們在gd中有另一個字段,用于控制打印等級。當gd被改動了,printf就可能解析出錯,誤以為打印等級為0而提前返回。

gd的實現

那么好端端的,gd為什么會被改了呢?這就要先看看gd到底是怎么實現的了。 uboot中維護了一個全局的結構體gd。在代碼中加入

DECLARE_GLOBAL_DATA_PTR; 即可使用gd指針訪問這個全局結構體,許多地方都會借助gd來保存傳遞信息。 進一步看看這個宏的定義舊版本uboot: #defineDECLARE_GLOBAL_DATA_PTRregistervolatilegd_t*gdasm("r8") 新版本uboot: #defineDECLARE_GLOBAL_DATA_PTRregistervolatilegd_t*gdasm("r9") 居然不一樣,一個是將gd的值放到r8寄存器,一個是放在r9寄存器。 那么就可以猜測到,庫是在舊版本uboot中編譯出來的,可能使用了r9,那么放到新版本uboot中去,就會破壞r9寄存器中保存的gd值,導致一系列依賴gd的代碼不能正常工作。

驗證改動

為了求證,將庫反匯編出來,發現確實避開了r8寄存器,但使用了r9寄存器。 說明uboot在指定gd寄存器的同時,還有某種方法讓其他代碼不使用這個寄存器。 那是不是把舊uboot中的這個r8改成r9,重新編譯庫就可以了呢?試一下,還是不行。 那么禁止其他代碼使用r8寄存器肯定就是通過別的方式實現的了。簡單粗暴地在舊版本uboot下搜索r8,去掉.c .h等類型后,很容易發現了

./arch/arm/cpu/armv7/config.mkPLATFORM_RELFLAGS+=-fno-common-ffixed-r8-msoft-floa 將-ffixed-r8修改為-ffixed-r9,重新編譯出庫,這回就可以正常工作了,打印正常,啟動正常。反匯編出來也可以看到,新編譯出來的庫用了r8沒有用r9。 當然更好的改法,是直接在新版本的uboot中編譯,這是最可靠的。

追本溯源

話說回來,為什么兩個版本的uboot,會使用不同的寄存器呢?難道有什么坑? 這就得去翻一下git記錄了。

commitfe1378a961e508b31b1f29a2bb08ba1dac063155 Author:JeroenHofstee Date:SatSep2114412013+0200 ARM:user9forgd TobemoreEABIcompliantandasapreparationforbuilding withclang,usetheplatform-specificr9registerforgd insteadofr8. note:TheFIQisnotupdatedsinceitisnotusedinu-boot, andunderdiscussionforthetimebeing. Thefollowingcheckpatchwarningisignored: WARNING:Useofvolatileisusuallywrong:see Documentation/volatile-considered-harmful.txt Signed-off-by:JeroenHofstee cc:AlbertARIBAUD 從git記錄中,也可以確認完整地將r8切換到r9,都需要做哪些修改diff--gita/arch/arm/config.mkb/arch/arm/config.mk index16c2e3d1e0..d0cf43ff41100644 ---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 #SupportgenericboardonARM __HAVE_ARCH_GENERIC_BOARD:=y diff--gita/arch/arm/cpu/armv7/lowlevel_init.Sb/arch/arm/cpu/armv7/lowlevel_init.S index82b2b86520..69e3053a42100644 ---a/arch/arm/cpu/armv7/lowlevel_init.S +++b/arch/arm/cpu/armv7/lowlevel_init.S @@-22,11+22,11@@ENTRY(lowlevel_init) ldrsp,=CONFIG_SYS_INIT_SP_ADDR bicsp,sp,#7/*8-bytealignmentforABIcompliance*/ #ifdefCONFIG_SPL_BUILD -ldrr8,=gdata +ldrr9,=gdata #else subsp,#GD_SIZE bicsp,sp,#7 -movr8,sp +movr9,sp #endif /* *Savetheoldlr(passedinip)andthecurrentlrtostack diff--gita/arch/arm/include/asm/global_data.hb/arch/arm/include/asm/global_data.h index79a9597419..e126436093100644 ---a/arch/arm/include/asm/global_data.h +++b/arch/arm/include/asm/global_data.h @@-47,6+47,6@@structarch_global_data{ #include -#defineDECLARE_GLOBAL_DATA_PTRregistervolatilegd_t*gdasm("r8") +#defineDECLARE_GLOBAL_DATA_PTRregistervolatilegd_t*gdasm("r9") #endif/*__ASM_GBL_DATA_H*/ diff--gita/arch/arm/lib/crt0.Sb/arch/arm/lib/crt0.S index960d12e732..ac54b9359a100644 ---a/arch/arm/lib/crt0.S +++b/arch/arm/lib/crt0.S @@-69,7+69,7@@ENTRY(_main) bicsp,sp,#7/*8-bytealignmentforABIcompliance*/ subsp,#GD_SIZE/*allocateoneGDaboveSP*/ bicsp,sp,#7/*8-bytealignmentforABIcompliance*/ -movr8,sp/*GDisaboveSP*/ +movr9,sp/*GDisaboveSP*/ movr0,#0 blboard_init_f @@-81,15+81,15@@ENTRY(_main) *'here'butrelocated. */ -ldrsp,[r8,#GD_START_ADDR_SP]/*sp=gd->start_addr_sp*/ +ldrsp,[r9,#GD_START_ADDR_SP]/*sp=gd->start_addr_sp*/ bicsp,sp,#7/*8-bytealignmentforABIcompliance*/ -ldrr8,[r8,#GD_BD]/*r8=gd->bd*/ -subr8,r8,#GD_SIZE/*newGDisbelowbd*/ +ldrr9,[r9,#GD_BD]/*r9=gd->bd*/ +subr9,r9,#GD_SIZE/*newGDisbelowbd*/ adrlr,here -ldrr0,[r8,#GD_RELOC_OFF]/*r0=gd->reloc_off*/ +ldrr0,[r9,#GD_RELOC_OFF]/*r0=gd->reloc_off*/ addlr,lr,r0 -ldrr0,[r8,#GD_RELOCADDR]/*r0=gd->relocaddr*/ +ldrr0,[r9,#GD_RELOCADDR]/*r0=gd->relocaddr*/ brelocate_code here: @@-111,8+111,8@@clbss_l:cmpr0,r1/*whilenotatendofBSS*/ blred_led_on /*callboard_init_r(gd_t*id,ulongdest_addr)*/ -movr0,r8/*gd_t*/ -ldrr1,[r8,#GD_RELOCADDR]/*dest_addr*/ +movr0,r9/*gd_t*/ +ldrr1,[r9,#GD_RELOCADDR]/*dest_addr*/ /*callboard_init_r*/ ldrpc,=board_init_r/*thisisauto-relocated!*/

啟動慢問題

問題簡述

填了幾個坑之后,新的uboot可以啟動到內核了,但發現啟動速度非常慢,內核啟動速度慢了接近10倍!明明是同一個內核,為什么差異這么大。

排查寄存器

初步排查了下設備樹配置,以及uboot跳轉內核前的一些關鍵寄存器,確實在兩個版本的uboot中有所不同,但具體去看這些不同,發現都不會影響速度,將一些驅動對齊之后寄存器差異基本就消失了。

差異的分界

那再細看,kernel的速度有差異,uboot呢?在哪個時間點之后,速度開始產生差異? 嘗試在兩個版本的uboot中插入一些操作,對比時間戳,發現兩個uboot在某個節點之后的速度確實有區別。 進一步排查,原來是在打開cache操作之后,舊uboot的速度就會比新uboot快。嘗試將舊uboot的cache關掉,則二者基本一致。嘗試將舊uboot操作cache的代碼,移植到新uboot,未發生改變。 此時可確認新uboot的開cache有問題。但覺得這個跟kernel啟動慢沒關系。因為uboot進入kernel之前都會關cache,由kernel自己去重新打開。 也就是不管是用哪份uboot,也不管uboot中是否開了cache,對kernel階段都應該沒有影響才對。 于是記錄下來uboot的這個問題,待后續修復。先繼續找kernel啟動慢的原因。(注:現在看來當時的做法是有問題的,這里的異常這么明顯,應該設法追蹤下去找出原因才對)

鎖定uboot

uboot的嫌疑非常大,但還不能完全確認,因為uboot之前還有一級spl。是否會是spl的問題呢? 嘗試改用新spl+舊uboot,啟動速度正常。而新spl+新uboot的啟動速度則很慢,其他因素都不變,說明問題確實出在uboot階段。

多做or少做

當時到這一步就卡住了,直接比較兩份uboot的代碼不太現實,差異太大了。 后來我就給自己提了個問題,到底新uboot是多做了某件事情,還是少做了某件事情? 換個說法,目前已知

spl-->舊uboot-->kernel(速度快) spl-->新uboot-->kernel(速度快) 但到底是以下的情況A還是情況B呢?A:spl(速度慢)-->舊uboot(做了某個會提升速度的操作)-->kernel(速度快) spl(速度慢)-->新uboot(少做了某個會提升速度的操作)-->kernel(速度慢) B:spl(速度快)-->舊uboot(沒做特殊操作)-->kernel(速度快) spl(速度快)-->新uboot(多做了某個會限制速度的操作)-->kernel(速度慢) 為了驗證,我決定讓spl直接啟動內核,看看內核到底是快是慢。 支持過程碰到了一些小問題 1.spl沒有能力加載這么大的kernel 解決:此時不需要kernel能完全啟動,只需要能加載啟動一段,足以體現出啟動速度是否正常即可,于是裁剪出一個非常小kernel來輔助實驗。 2.kernel需要dtb 解決:內核有一個CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE選項。選上重新編譯。編譯后再用dd將kernel和dtb拼接到一起,作為新的kernel。這樣,spl就只需要加載一個文件并跳轉過去即可。 試驗結果,spl啟動的kernel和使用新uboot啟動的kernel速度一致,均比舊uboot啟動的kernel慢。 說明,舊uboot中做了某個關鍵操作,而新uboot沒做。

找出關鍵操作

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

spl加載kernel和舊uboot

spl跳轉到舊uboot,此時kernel其實已經在dram中準備好了,隨時可以啟動

在舊uboot的啟動流程各個階段,嘗試直接跳轉到kernel,觀察啟動速度

如果在舊uboot的A點跳轉kernel啟動慢,B點跳轉啟動快,則說明關鍵操作位于AB點之間。

方法有了,很快就鎖定到start.S,進一步在start.S中揪出了這段代碼

#ifdefined(CONFIG_ARM_A7) @setSMPbit mrcp15,0,r0,c1,c0,1 orrr0,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 SignalsiftheCortex-A9processoristakingpartincoherencyornot. Inuniprocessorconfigurations,ifthisbitisset,thenInnerCacheableSharedistreatedasCacheable.Theresetvalueiszero. 搜下kernel的代碼,發現也是有地方調用了的。不過這個芯片是單核的,根本就沒配置CONFIG_SMP。#ifdefCONFIG_SMP ALT_SMP(mrcp15,0,r0,c1,c0,1) ALT_UP(movr0,#(1<

總結

整理出來一方面是記錄這兩個bug,另一方面也是想記錄下當時的一些操作。 畢竟同樣的bug可能以后都不會碰到了,但解bug的方法和思路卻是可以積累復用的。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編譯
    +關注

    關注

    0

    文章

    659

    瀏覽量

    32900
  • Uboot
    +關注

    關注

    4

    文章

    125

    瀏覽量

    28253

原文標題:坑!uboot升級過程遇到的兩個bug

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    使用TVP7002現在遇到兩個問題求解答

    我們使用TVP7002現在遇到兩個問題(VGA轉YCbCr 4:2:2,embedded sync, 參考外部27MHz時鐘) 1 輸入信號1080P的情況下,有些電腦輸出的1080P圖像很正常
    發表于 01-01 07:41

    用AD8338做AGC遇到兩個問題求解

    我們用AD8338做AGC,但是遇到兩個問題,特此請教一下 1、C61 如果接電容,則終端信號沒有輸出,接電阻才可以,不知道為什么 2、我們如果把R59去掉,R57,R60 換成47R電阻,在C57
    發表于 12-19 06:50

    音頻DSP TLV320AIC3254調試遇到兩個問題求解答

    關于TI 音頻DSP TLV320AIC3254的調試我們這邊遇到兩個問題謝謝幫忙看一下: AIC3254的差分Mic用AIC3254_C工具配置一直沒有成功,現在我們只能使用單端的配置,幫忙
    發表于 10-24 07:21

    ad如何設置兩個元器件的距離

    在Altium Designer(簡稱AD)中設置兩個元器件之間的距離,主要是通過設置元器件間的安全間距(Clearance)規則來實現的。這個規則定義了元器件之間、元器件與走線之間以及其他設計元素
    的頭像 發表于 09-02 15:31 ?7582次閱讀

    觸發器的兩個穩定狀態分別是什么

    觸發器作為數字電路中的基本邏輯單元,具有兩個穩定狀態,這兩個狀態通常用于表示二進制數碼中的0和1。
    的頭像 發表于 08-12 11:01 ?1414次閱讀

    雙穩態電路的兩個穩定狀態是什么

    雙穩態電路是一種具有兩個穩定狀態的電子電路,廣泛應用于數字電路、通信系統、存儲器等領域。 雙穩態電路的基本概念 雙穩態電路是一種具有兩個穩定狀態的電路,即在沒有外部輸入信號的情況下,電路可以保持在
    的頭像 發表于 08-11 15:00 ?1559次閱讀

    雙穩態觸發器的兩個基本性質是什么

    雙穩態觸發器(Bistable Trigger)是一種具有兩個穩定狀態的邏輯電路,廣泛應用于數字電路設計中。它具有兩個基本性質:記憶性和切換性。 一、雙穩態觸發器的基本概念 1.1 雙穩態觸發器
    的頭像 發表于 08-11 10:08 ?741次閱讀

    使用esp-iot-bridge遇到兩個疑問求解

    AP了,點擊掃描時,提示錯誤;log顯示一直在連接AP,能不能設置重試多少次之后暫停? 2、打開了usb和ap共享網絡模式,兩個接口獲取到的網絡段都不一樣,和無線路由器那邊的IP段也不一樣。我使用到的場景是固定IP通信的,設備端的IP和無線路由器不在同一網段,沒辦法通信。請問要如何解決?
    發表于 06-27 06:05

    請問ad9171的兩個輸出端口是否支持同時輸出兩個不同的頻率?

    你好,關于AD9171芯片我有一問題 ,數據手冊顯示該芯片具有兩個輸出通道,芯片內部有DAC0和DAC1共兩個DAC通道,那么這兩個通道是
    發表于 05-28 06:20

    兩個銅片可以形成原電池嗎

    兩個銅片本身不能形成原電池,因為原電池的工作原理依賴于兩個不同電位的電極材料之間的氧化還原反應。
    的頭像 發表于 05-21 16:23 ?1020次閱讀

    STM32 IAP升級,KEIL如何一份代碼運行于兩個APP區?

    校驗。目前的問題是,沒辦法使用一份代碼運行兩個APP。兩個APP,則IAP跳轉不同的APP,跳轉的地址不一樣,則代碼中需要設置的中斷向量表及鏈接地址。這樣,一份代碼就不行了,而且份代碼還需要注意當前到底應該
    發表于 03-26 07:20

    使用CYUSB3014-BZXI時遇到兩個疑問求解

    在使用 CYUSB3014-BZXI 的時候出現如下兩個問題,不知道你們是否有遇到?有沒有相應的解決方案? 1.在使用cypress 過程中,發現有時候(極小概率),插入USB之后,Windows
    發表于 02-29 06:20

    關于PSDR和DSPR遇到兩個問題求解

    PSPR 主要用途放置靜態函數,提示高函數數執行效率 DSPR 主要用途于全局變量、場景保護的上下文管理與等數據 以上是我找到的關于 PSPR 和 DSPR 的解析,我有兩個問題: 1。PSPR
    發表于 02-26 07:57

    arcgis中如何關聯兩個屬性表

    在ArcGIS中,關聯兩個屬性表是一重要的操作,可以通過此操作將兩個表中的數據關聯起來,以便進行分析和查詢。下面是詳細介紹如何在ArcGIS中實現屬性表的關聯。 首先,我們需要明確兩個
    的頭像 發表于 02-25 11:01 ?4310次閱讀

    兩個電位器地控制一變頻器,如何接線?

    兩個電位器地控制一變頻器,如何接線? 接線方式如下: 1. 首先,明確需要使用的電器設備。在這個場景中,我們需要兩個電位器(即可變電阻器)和一
    的頭像 發表于 02-05 10:13 ?5448次閱讀
    主站蜘蛛池模板: 欧美xxxxx精品| 噜噜啪啪| 亚洲色图综合| 伊人9| 四虎成人欧美精品在永久在线| 婷婷综合七月激情啪啪| 日韩在线网| 猛操女人| 成年在线视频| 天天草视频| 操操干| 中文字幕一区二区三区在线不卡| 亚洲视频 欧美视频| 一级毛片免费毛片一级毛片免费| 亚洲国产高清人在线| 日本黄色影片| 黄页网址免费观看18网站| 99精品国产高清自在线看超| 四虎comwww最新地址| 五月激情网站| 国产精品色婷婷在线观看| 色老头在线视频| 久久99精品久久久久久久不卡| 999毛片免费观看| 好吊色37pao在线观看| 亚洲一区在线视频| 性欧美暴力猛交69hd| 免费的毛片| 午夜影视在线观看| 在线另类| 伊人婷婷色香五月综合缴激情| 日本三级免费看| 成人a毛片视频免费看| 狼人久久尹人香蕉尹人| 亚洲综合色在线观看| 婷婷免费视频| 国产在线永久视频| 久久精品免费| 久热99| 日本a级三级三级三级久久| 99精品久久久久久久婷婷|