日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

u-boot 源码分析讲解

發布時間:2024/9/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 u-boot 源码分析讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介===>

1.U-Boot系統加載器

U-Boot是一個規模龐大的開源Bootloader軟件,最初是由denx(www.denx.de)發起。U-Boot的前身是PPCBoot,目前是SourceForge(www.sourceforge.net)的一個項目。

最初的U-Boot僅支持PowerPC架構的系統,稱做PPCBoot。從0.3.2官方版本之后開始逐步支 持多種架構的處理器,目前可以支持 PowerPC(MPC5xx、MPC8xx、MPC82xx、MPC7xx、MPC74xx)、ARM(ARM7、ARM9、StrongARM、 Xscale)、MIPS(4kc、5kc)、X86等處理器,支持的嵌入式操作系統有Linux、Vx-Works、NetBSD、QNX、 RTEMS、ARTOS、LynxOS等,是PowerPC、ARM9、Xscale、X86等系統通用的Boot方案。

U-Boot支持的處理器和操作系統很多,但是它對PowerPC系列處理器和Linux操作系統支持最好。U-Boot支持的功能也較多,對于嵌 入式開發常用的查看、修改內存,從網絡下載操作系統鏡像等功能都提供了很好的支持。U-Boot的項目更新較快,支持的目標板眾多,是學習底層開發很好的 示例。

2.ViVi系統加載器

ViVi是韓國的mizi公司專門針對ARM9處理器設計的一款Bootloader。它的特點是操作簡便,同時提供了完備的命令體系,目前在三星系列的ARM9處理器上ViVi也比較流行。

與U-Boot相比,由于ViVi支持的處理器單一,ViVi的代碼也要小很多。同時,ViVi的軟件架構和配置方法采用和Linux內核類似的風格,對于有過配置編譯Linux內核經驗的讀者,ViVi更容易上手。

與其他的Bootloader一樣,ViVi有兩種工作模式:啟動加載模式和下載模式。使用啟動加載模式,在目標板上電后,ViVi會從預先配置好 的Flash分區讀取Linux或者其他系統的鏡像并且啟動系統;使用下載模式,ViVi向用戶提供了一個命令行接口,通過該接口用戶可以使用ViVi提 供的命令。ViVi主要提供了5個命令如下:

Load:把二進制文件載入Flash或RAM。

Part:操作MTD分區信息。顯示、增加、刪除、復位、保存MTD分區。

Param:設置參數。

Boot:啟動系統。

Flash:管理Flash,如刪除Flash的數據。

與Linux內核的組織類似,ViVi的源代碼主要包括arch、init、lib、drivers和include等幾個目錄,共200多個代碼文件。各目錄的具體功能請參考ViVi相關的信息。

=====================================================================》》》

=====================================================================》》》

=====================================================================》》》

?

基本目錄分類:

common目錄?是與體系結構無關的文件,包括實現各種命令的C語言源代碼文件。

cpu目錄??????????存 放與CPU相關的文件,每種CPU需要的代碼文件存放在以CPU名稱命名的子目錄下,arm920t存放了arm920t為內核的 CPU相關的文件。在每個特定的子目錄下都包括cpu.c、interrupt.c和start.S這3個文件,這3個文件是CPU初始化以及配置中斷的 代碼。U-Boot自帶了很多CPU相關的代碼,用戶可以在現有CPU支持的基礎上修改自己所需要的配置。

通用設備的驅動程序存放在drivers目錄下。U-Boot自帶了許多設備的驅動,包括顯示芯片、網絡接口控制器、USB控制器、I2C器件等,對于大多數用戶而言已經夠用,用戶也可以按照自己的需求增加或者修改設備驅動。

fs????????????????? ??存放支持的文件系統代碼,U-Boot目前支持cramfs、ext2、fat、jffs、reiserfs、yaffs等多種常見的文件系統。

net目錄??????? ?是與網絡協議有關的代碼,比如BOOTP協議、TFTP協議、RARP協議等。

post????????????? ?存放與硬件自檢有關的代碼。

rtc目錄??????????存放與硬件實時時鐘相關的代碼。

tools目錄??????存放U-Boot編譯過程中用到的一些工具代碼。? // 例如:mkimage

==========================================

?

?
?
?




hao:
start_armboot => bootm.c
向量表在_start開始階段已經匯編搞定。

其實主要就是個寄存器和內存的基本處理。

===》》》
列出了U-Boot在ARM處理器啟動過程中的幾個關鍵點,
從圖中看出U-Boot的啟動代碼分布在start.S、low_level_init.S、 board.c和main.c文件中。

start.S????????????????????是U-Boot整個程序的入口,該文件使用匯編語言編寫,不同體系結構的啟動代碼是不同 的;

low_level_init.S????特定開發板的設置代碼

board.c??????????????????包含開發板底層設備驅動

main.c是一個與平臺無關的代碼,U-Boot應用程序的入口在此文件中

取出CPSR寄存器的值,CPSR寄存器保存當前系統狀態,

使用比特清除命令清空了CPSR寄存器的中斷控制位,表示清除 中斷。

設置了CPSR寄存器的處理器模式位為管理模式,然后在第117行寫入 CPSR的值強制切換處理器為超級保護模式。

定義看門狗控制器有關的變量,

根據平臺設置看門狗定時器。

設置時鐘分頻寄存器的值。

需要根據CONFIG_SKIP_LOWLEVEL_INIT宏的值是否跳轉到cpu_init_crit標號執行

===========cpu_init_crit==========

????????????????????????????????????????????????????????????????cpu_init_crit標號處的代碼初始化ARM處理器關鍵的寄存器


  • 228?/* ?
  • 229??***************************************************************** ?
  • 230??* ?
  • 231??*?CPU_init_critical?registers ?
  • 232??* ?
  • 233??*?setup?important?registers ?
  • 234??*?setup?memory?timing ?
  • 235??* ?
  • 236??****************************************************************** ?
  • 237??*/ ?
  • 238? ?
  • 239? ?
  • 240?#ifndef?CONFIG_SKIP_LOWLEVEL_INIT ?
  • 241?cpu_init_crit: ?
  • 242???/* ?
  • 243????*?flush?v4?I/D?caches ?
  • 244????*/ ?
  • 245???mov?r0,?#0 ?
  • 246???mcr?p15,?0,?r0,?c7,?c7,?0?/*?flush?v3/v4?cache?*/?????//?1.刷新cache ?
  • 247???mcr?p15,?0,?r0,?c8,?c7,?0?/*?flush?v4?TLB?*/??????????//?2.刷新TLB ?
  • 248? ?
  • 249???/* ?
  • 250????*?disable?MMU?stuff?and?caches???????????????????????//?3.關閉MMU??
  • 251????*/ ?
  • 252???mrc?p15,?0,?r0,?c1,?c0,?0 ?
  • 253???bic?r0,?r0,?#0x00002300?@?clear?bits?13,?9:8?(--V-?--RS) ?
  • 254???bic?r0,?r0,?#0x00000087?@?clear?bits?7,?2:0?(B---?-CAM) ?
  • 255???orr?r0,?r0,?#0x00000002?@?set?bit?2?(A)?Align ?
  • 256???orr?r0,?r0,?#0x00001000?@?set?bit?12?(I)?I-Cache ?
  • 257???mcr?p15,?0,?r0,?c1,?c0,?0 ?
  • 258? ?
  • 259???/* ?
  • 260????*?before?relocating,?we?have?to?setup?RAM?timing ?
  • 261????*?because?memory?timing?is?board-dependend,?you?will ?
  • 262????*?find?a?lowlevel_init.S?in?your?board?directory. ?
  • 263????*/ ?
  • 264???mov?ip,?lr ?
  • 265???bl??lowlevel_init???//?跳轉到lowlevel_init ?
  • 266???mov?lr,?ip ?
  • 267???mov?pc,?lr ?
  • 268?#endif?/*?CONFIG_SKIP_LOWLEVEL_INIT?*/?
  • ?

    ?

    ==>2.

    TLB的作用是在處理器訪問內存數據的時候做地址轉換。TLB的全稱是Translation Lookaside Buffer,可以翻譯做旁路緩沖。

    TLB中存放了一些頁表文件,文件中記錄了虛擬地址和物理地址的映射關系。當應用程序訪問一個虛擬地址的時候,會從 TLB中查詢出對應的物理地址,然后訪問物理地址。TLB通常是一個分層結構,使用與Cache類似的原理。處理器使用一定的算法把最常用的頁表放在最先 訪問的層次。

    ==>3.

    程序第252~257行關閉MMU。MMU是內存管理單元(Memory Management Unit)的縮寫。在現代計算機體系結構上,MMU被廣泛應用。使用MMU技術可以向應用程序提供一個巨大的虛擬地址空間。在U-Boot初始化的時候, 程序看到的地址都是物理地址,無須使用MMU。

    ?

    ?


    =========================lowlevel_init=========================??

    位于board/smdk2410/lowlevel_init.S文件 ???????????????????????????????????????? 開發板相關的初始化配置

  • 133?lowlevel_init: ?
  • 134???/*?memory?control?configuration?*/ ?
  • 135???/*?make?r0?relative?the?current?location?so?that?it?*/ ?
  • 136???/*?reads?SMRDATA?out?of?FLASH?rather?than?memory?!?*/ ?
  • 137???ldr???? ?r0, ? =SMRDATA??????????????????????//?讀取SMRDATA變量地址 ?
  • 138???ldr ?r1,? _TEXT_BASE????????????????????????//?讀取_TEXT_BASE變量地址 ?
  • 139???sub????r0, ?r0, r1?????????????????????????????????// 得出相對偏移
  • 140???ldr ???? r1, ?=BWSCON????????????????????????// 主要是了解BANK的位寬,16位
  • 141???add????r2,?????r0,? #13*4??? ????????????????? //?得到SMRDATA占用的大小,結尾處的偏移
  • 142?0: ?
  • 143???ldr?????r3,?[r0],?#4????????????????? ?????????????//?加載SMRDATA到內存 ?,相當于一個while循環
  • 144???str?????r3,?[r1],?#4 ?
  • 145???cmp?????r2,?r0 ?
  • 146???bne?????0b??????????????????????????????????????? // 循環,相當于while循環
  • 147? ?
  • 148???/*?everything?is?fine?now?*/ ?
  • 149???mov?pc,?lr ?
  • 152?/*?the?literal?pools?origin?*/ ?
  • 153? ?
  • 154?SMRDATA:????????????//?定義SMRDATA值 ?
  • 155?????.word?(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON? ?
  • ????????<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) ?
  • 156?????.word?((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_?Tcoh<<6)+ ?
  • ????????(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ?
  • 157?????.word?((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+? ?
  • ????????(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ?
  • 158?????.word?((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+? ?
  • ????????(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ?
  • 159?????.word?((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+? ?
  • ????????(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ?
  • 160?????.word?((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+? ?
  • ????????(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ?
  • 161?????.word?((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+? ?
  • ????????(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ?
  • 162?????.word?((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ?
  • 163?????.word?((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ?
  • 164?????.word?((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+? ?
  • ????????(Tchr<<16)+REFCNT) ?
  • 165?????.word?0x32 ?
  • 166?????.word?0x30 ?
  • 167?????.word?0x30?
  • 程序第137~141行計算SMRDATA需要加載的內存地址和大小。首先在137行讀取SMRDATA的變量地址,之后計算存放的內存地址并且記錄在r0寄存器,然后根據總線寬度計算需要加載的SMRDATA大小,并且把加載結束地址存放在r2寄存器。

    程序第142~146行復制SMRDATA到內存SMRDATA是開發板上內存映射的配置

    正式開始了第二階段:

    relocate部分的代碼負責把U-Boot Stage2的代碼從Flash存儲器加載到內存,代碼如下:

  • 163?#ifndef?CONFIG_SKIP_RELOCATE_UBOOT ?
  • 164?relocate:???????/*?relocate?U-Boot?to?RAM?????*/ ?
  • 165???adr? r0,? _start???? /*?r0?<-?current?position?of?code???*/?? ?
  • ???????????????????????????//?獲取當前代碼存放地址 ?00000000
  • 166???ldr ?r1, _TEXT_BASE????/*?test?if?we?run?from?flash?or?RAM?*/??
  • ?????????????????????????????//?獲取內存存放代碼地址 ?33f80000
  • 167???cmp?????r0,? r1????????/*?don't?reloc?during?debug?????????*/ ?
  • ?????????????????????????????//地址相同說明程序已經在內存中?則不需要加載??
  • 168???beq?????stack_setup??
  • 169???//開始加載
  • 170???ldr? r2,?_armboot_start????//?獲取stage2代碼存放地址??
  • 171???ldr r3,? _bss_start??????????//?獲取內存代碼段起始地址 ?
  • 172???sub ?r2, ?r3, r2?? ??????? /*?r2?<-?size?of?armboot??*/?? ?
  • ?????????????????????????????????// 不包括向量表,U-BOOT的整個大小?
  • 173???add ?r2, ?r0, ?r2??? /*?r2?<-?source?end?address?????????*/?? ?
  • ???????????????????????33f80000 size???????? //?計算stage2代碼結束地址?
  • 174? ?
  • 175?copy_loop: ?
  • 176???ldmia ?r0!, ?{r3-r10}?? /*?copy?from?source?address?[r0]????*/ ?
  • ??????????????????????????????//?從Flash復制代碼到內存 ?
  • 177???stmia r1!, ?{r3-r10}??? /*?copy?to???target?address?[r1]????*/ ?
  • 178???cmp? r0, ?r2???? ?????? /*?until?source?end?addreee?[r2]????*/ ?
  • 179???ble ?copy_loop ?
  • 180?#endif? ?/*?CONFIG_SKIP_RELOCATE_UBOOT?*/??
  • 181? ?
  • 182?? /*?Set?up?the?stack?*/?? ?
  • ??????//?在內存中建立堆棧 ?
  • 183?stack_setup: ?
  • 184???ldr?r0,?_TEXT_BASE???????????????/*?upper?128?KiB:?relocated?uboot???*/ ?
  • 185???sub?r0,?r0,?#CFG_MALLOC_LEN ? ?? /*?malloc?area????*/??//?分配內存區域 ?
  • 186???sub?r0,?r0,?#CFG_GBL_DATA_SIZE ? /*?bdinfo??*/ ?
  • 187?#ifdef?CONFIG_USE_IRQ ?
  • 188???sub?r0,?r0,?#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) ?
  • 189?#endif ?
  • 190???sub?sp,?r0,?#12??? ? /*?leave?3?words?for?abort-stack????*/ ?
  • 191? ?
  • 192?clear_bss:?????????????????//?初始化內存bss段內容為0 ?
  • 193???ldr?r0,?_bss_start???? ? /*?find?start?of?bss?segment????????*/ ?
  • ???????????????????????????????//?查找bss段起始地址 ?
  • 194???ldr? r1,? _bss_end??? ?? /*?stop?here??????*/??//?查找bss段結束地址 ?
  • 195???mov???r2,? #0x00000000???/*?clear???*/?//?清空bss段內容 ?
  • 196? ?
  • 197? clbss_l: str?r2,?[r0]???? /*?clear?loop...????????????????????*/ ?
  • 198???add ?r0, ?r0, ?#4 ?
  • 199???cmp ?r0, ?r1 ?
  • 200???ble? clbss_l ?
  • 223???ldr? pc,? _start_armboot?? ??//?設置程序指針為start_armboot()函數地址 ?
  • 224? ?
  • 225?_start_armboot:
  • .word??start_armboot //這里是個C的函數名字,也就是入口地址
  • 代碼解釋:

    ????程序首先在165~168行檢查當前是否在內存中執行代碼,根據結果決定是否需要從Flash存儲器加載代碼。程序通過獲取_start和_TEXT_BASE所在的地址比較,如果地址相同說明程序已經在內存中,無須加載。

    ??? 程序第170~173行計算要加載的Stage2代碼起始地址和長度,然后在第176~179行循環復制Flash的數據到內存,每次可以復制8個字長的數據。

    ??? Stage2程序復制完畢后,程序第184~190行設置系統堆棧,最后在第193~200行清空內存bss段的內容。

    ??? relocate程序最后在223行設置程序指針寄存器為start_armboot()函數地址,程序跳轉到Stage2部分執行。請注意第 225行的定義,_start_armboot全局變量的值是C語言函數start_armboot()函數的地址,使用這種方式可以在匯編中調用C語言?編寫的函數。???

    這里就是之前啟動的C的函數:start_armboot()
    <lib_arm/board.c>
    start_armboot()函數主要初始化ARM系統的硬件和環境變量,包括Flash存儲器、FrameBuffer、網卡等,最后進入U-Boot應用程序主循環

    =========================================

  • 236?void?start_armboot?(void) ?
  • 237?{ ?
  • 238????init_fnc_t?**init_fnc_ptr; ?
  • 239??? char?*s; ?
  • 240?#ifndef?CFG_NO_FLASH ?
  • 241?? ulong?size; ?
  • 242?#endif ?
  • 243?#if?defined(CONFIG_VFD)?||?defined(CONFIG_LCD) ?
  • 244?? ?unsigned?long?addr; ?
  • 245?#endif ?
  • 246? ?
  • 247???/*?Pointer?is?writable?since?we?allocated?a?register?for?it?*/??
  • 248???gd?=?(gd_t*)(_armboot_start?-?CFG_MALLOC_LEN?-?sizeof(gd_t)); ?//全局的系統初始化參數
  • 249???/*?compiler?optimization?barrier?needed?for?GCC?>=?3.4?*/??
  • 250???__asm__?__volatile__("":?:?:"memory"); ?
  • 251? ?
  • 252???memset( (void*)gd, ?0,? sizeof?(gd_t) ); ?
  • 253???gd->bd?=?(bd_t*)( (char*)gd ?- ?sizeof(bd_t) ); ?
  • 254???memset?( gd->bd,? 0, ?sizeof?(bd_t) ); ??//初始化了板子的參數
  • 255? ?
  • 256???monitor_flash_len?=?_bss_start?-?_armboot_start; ?
  • 257? ?
  • 258???for?(init_fnc_ptr?=?init_sequence; ?*init_fnc_ptr; ?++init_fnc_ptr)?{ ?
  • 259???? ?if?((*init_fnc_ptr)()?!=?0)?{ ?
  • 260??????? hang?(); ?
  • 261?????} ?
  • 262???} ?
  • 263? ?
  • 264?#ifndef?CFG_NO_FLASH ?
  • 265???/*?configure?available?FLASH?banks?*/ ?
  • 266?? ?size?=?flash_init?();????????? //?初始化?Flash存儲器?配置 ?
  • 267??? display_flash_config?(size);?? //?顯示?Flash存儲器?配置 ?
  • 268?#endif?/*?CFG_NO_FLASH?*/ ?
  • 269? ?
  • 270?#ifdef?CONFIG_VFD??
  • 271?#?ifndef?PAGE_SIZE ?
  • 272?#???define?PAGE_SIZE?4096 ?
  • 273?#?endif ?
  • 274???/* ?
  • 275????*?reserve?memory?for?VFD?display?(always?full?pages) ?
  • 276????*/ ?
  • 277???/*?bss_end?is?defined?in?the?board-specific?linker?script?*/ ?
  • 278???addr?=?(_bss_end?+?(PAGE_SIZE?-?1))?&?~(PAGE_SIZE?-?1); ?
  • ????????????????????????????????????????????//?計算FrameBuffer?內存地址??
  • 279???size?=?vfd_setmem?(addr);?????????????//?設置FrameBuffer?占用內存大小?
  • 280???gd->fb_base?=?addr;???????????????? ?//?設置FrameBuffer?內存起始地址??
  • 281?#endif?/*?CONFIG_VFD?*/??
  • 282? ?
  • 283?#ifdef?CONFIG_LCD??
  • 284?#?ifndef?PAGE_SIZE ?
  • 285?#???define?PAGE_SIZE?4096 ?
  • 286?#?endif ?
  • 287???/* ?
  • 288????*?reserve?memory?for?LCD?display?(always?full?pages) ?
  • 289????*/ ?
  • 290???/*?bss_end?is?defined?in?the?board-specific?linker?script?*/ ?
  • 291???addr?=?(_bss_end?+?(PAGE_SIZE?-?1))?&?~(PAGE_SIZE?-?1); ?
  • ????????????????????????????????????????????//?計算FrameBuffer內存地址 ?
  • 292???size?=?lcd_setmem?(addr);?????????????//?設置FrameBuffer大小 ?
  • 293???gd->fb_base?=?addr;?????????????????? //?設置FrameBuffer內存起始地址 ?
  • 294?#endif?/*?CONFIG_LCD?*/??
  • 295? ?
  • 296???/*?armboot_start?is?defined?in?the?board-specific?linker?script?*/ ?
  • 297???mem_malloc_init?(_armboot_start?-?CFG_MALLOC_LEN); ?
  • 298? ?
  • 299?#if?(CONFIG_COMMANDS?&?CFG_CMD_NAND) ?
  • 300?? ?puts?("NAND:??"); ?
  • 301?? nand_init();????/*?go?init?the?NAND?*/??? ?//?初始化NAND?Flash存儲器 ?
  • 302?#endif ?
  • 303? ?
  • 304?#ifdef?CONFIG_HAS_DATAFLASH ?
  • 305???AT91F_DataflashInit();???????????????? //?初始化Hash表??
  • 306???dataflash_print_info(); ?
  • 307?#endif ?
  • 308? ?
  • 309???/*?initialize?environment?*/ ?
  • 310???env_relocate?();?????????????????????????????????? //?重新設置環境變量??
  • 311????? ?
  • 312?#ifdef?CONFIG_VFD ?
  • 313???/*?must?do?this?after?the?framebuffer?is?allocated?*/ ?
  • 314???drv_vfd_init();?????????????????????????????????? ?//?初始化虛擬顯示設備 ?
  • 315?#endif?/*?CONFIG_VFD?*/ ?
  • 316? ?
  • 317???/*?IP?Address?*/ ?
  • 318???gd->bd->bi_ip_addr?=?getenv_IPaddr?("ipaddr");???? //?設置網卡的IP地址 ?
  • 319? ?
  • 320???/*?MAC?Address?*/ ?
  • 321???{ ?
  • 322?????int?i; ?
  • 323?????ulong?reg; ?
  • 324?????char?*s,?*e; ?
  • 325?????char?tmp[64]; ?
  • 326? ?
  • 327?????i?=?getenv_r?("ethaddr",?tmp,?sizeof?(tmp));??? ? //?從網卡寄存器讀取 ?MAC地址 ?
  • 328?????s?=?(i?>?0)???tmp?:?NULL; ?
  • 329? ?
  • 330?????for?(reg?=?0;?reg?<?6;?++reg)?{ ?
  • 331???????gd->bd->bi_enetaddr[reg]?=?s???simple_strtoul?(s,?&e,?16)?:?0; ?
  • 332???????if?(s) ?
  • 333?????????s?=?(*e)???e?+?1?:?e; ?
  • 334?????} ?
  • 335? ?
  • 336?#ifdef?CONFIG_HAS_ETH1 ?
  • 337?????i?=?getenv_r?("eth1addr",?tmp,?sizeof?(tmp));?? ?//?讀取Hash值 ?
  • 338?????s?=?(i?>?0)???tmp?:?NULL; ?
  • 339? ?
  • 340?????for?(reg?=?0;?reg?<?6;?++reg)?{ ?
  • 341???????gd->bd->bi_enet1addr[reg]?=?s???simple_strtoul?(s,?&e,?16)?:?0; ?
  • 342???????if?(s) ?
  • 343?????????s?=?(*e)???e?+?1?:?e; ?
  • 344?????} ?
  • 345?#endif ?
  • 346???} ?
  • 347? ?
  • 348???devices_init?();?? /*?get?the?devices?list?going.?*/ ?
  • ??????????????????????????????????????????//?初始化開發板上的設備??
  • 349? ?
  • 350?#ifdef?CONFIG_CMC_PU2 ?
  • 351???load_sernum_ethaddr?(); ?
  • 352?#endif?/*?CONFIG_CMC_PU2?*/ ?
  • 353? ?
  • 354???jumptable_init?();???????????????? //?初始化跳轉表??
  • 355? ?
  • 356???console_init_r?();?? /*?fully?init?console?as?a?device?*/ ?
  • ?????????????????????????? //?初始化控制臺??
  • 357? ?
  • 358?#if?defined(CONFIG_MISC_INIT_R) ?
  • 359???/*?miscellaneous?platform?dependent?initialisations?*/ ?
  • 360???misc_init_r?();??????????????????? //?初始化其他設備??
  • 361?#endif ?
  • 362? ?
  • 363???/*?enable?exceptions?*/ ?
  • 364???enable_interrupts?();????????????? //?打開中斷??
  • 365? ?
  • 366???/*?Perform?network?card?initialisation?if?necessary?*/ ?
  • 367?#ifdef?CONFIG_DRIVER_CS8900??
  • 368???cs8900_get_enetaddr?(gd->bd->bi_enetaddr);????//?獲取CS8900網卡MAC地址 ?
  • 369?#endif??
  • 370? ?
  • 371?#if?defined(CONFIG_DRIVER_SMC91111)?||?defined?(CONFIG_DRIVER_? ?
  • LAN91C96) ?
  • 372???if?(getenv?("ethaddr"))?{ ?
  • 373?????smc_set_mac_addr(gd->bd->bi_enetaddr);??????//?設置SMC網卡MAC地址 ?
  • 374???} ?
  • 375?#endif?/*?CONFIG_DRIVER_SMC91111?||?CONFIG_DRIVER_LAN91C96?*/ ?
  • 376? ?
  • 377???/*?Initialize?from?environment?*/ ?
  • 378???if?((s?=?getenv?("loadaddr"))?!=?NULL)?{ ?
  • 379?????load_addr?=?simple_strtoul?(s,?NULL,?16); ?
  • 380???} ?
  • 381?#if?(CONFIG_COMMANDS?&?CFG_CMD_NET) ?
  • 382???if?((s?=?getenv?("bootfile"))?!=?NULL)?{ ?
  • 383?????copy_filename?(BootFile,?s,?sizeof?(BootFile)); ?//?保存FrameBuffer ?
  • 384???} ?
  • 385?#endif??/*?CFG_CMD_NET?*/ ?
  • 386? ?
  • 387?#ifdef?BOARD_LATE_INIT ?
  • 388???board_late_init?();?????????????????????????? //?開發板相關設備初始化 ?
  • 389?#endif ?
  • 390?#if?(CONFIG_COMMANDS?&?CFG_CMD_NET) ?
  • 391?#if?defined(CONFIG_NET_MULTI) ?
  • 392???puts?("Net:???"); ?
  • 393?#endif ?
  • 394???eth_initialize(gd->bd); ?
  • 395?#endif ?
  • 396???/*?main_loop()?can?return?to?retry?autoboot,?if?so?just?run?it?again.?*/ ?
  • 397???for?(;;)?{ ?
  • 398?????main_loop?();???????????????????????????????//?進入主循環 ?
  • 399???} ?
  • 400? ?
  • 401???/*?NOTREACHED?-?no?way?out?of?command?loop?except?booting?*/ ?
  • 402?}?
  • ??? start_armboot()函數代碼里有許多的宏開關,供用戶根據自己開發板的情況進行配置。在start_armboot()函數第388行調用board_late_init()函數,該函數是開發板提供的,供不同的開發板做一些特有的初始化工作。

    ??? 在start_armboot()函數中,使用宏開關括起來的代碼是在各種開發板上最常用的功能,如 CS8900網卡配置。整個函數配置完畢后,進 入一個for死循環,調用main_loop()函數。請讀者注意,在main_loop()函數中也有一個for死循環。 start_armboot()函數使用死循環調用main_loop()函數,作用是防止main_loop()函數開始的初始化代碼如果調用失敗后重 新執行初始化操作,保證程序能進入到U-Boot的命令行。

    ??? main_loop()函數做的都是與具體平臺無關的工作,主要包括初始化啟動次數限制機制、設置軟件版本號、打印啟動信息、解析命令等。

    (1)設置啟動次數有關參數。在進入main_loop()函數后,首先是根據配置加載已經保留的啟動次數,并且根據配置判斷是否超過啟動次數。代碼如下:

  • 295?void?main_loop?(void) ?
  • 296?{ ?
  • 297?#ifndef?CFG_HUSH_PARSER ?
  • 298???static?char?lastcommand[CFG_CBSIZE]?=?{?0,?}; ?
  • 299???int?len; ?
  • 300???int?rc?=?1; ?
  • 301???int?flag; ?
  • 302?#endif ?
  • 303? ?
  • 304?#if?defined(CONFIG_BOOTDELAY)?&&?(CONFIG_BOOTDELAY?>=?0) ?
  • 305???char?*s; ?
  • 306???int?bootdelay; ?
  • 307?#endif ?
  • 308?#ifdef?CONFIG_PREBOOT ?
  • 309???char?*p; ?
  • 310?#endif ?
  • 311?#ifdef?CONFIG_BOOTCOUNT_LIMIT ?
  • 312???unsigned?long?bootcount?=?0; ?
  • 313???unsigned?long?bootlimit?=?0; ?
  • 314???char?*bcs; ?
  • 315???char?bcs_set[16]; ?
  • 316?#endif?/*?CONFIG_BOOTCOUNT_LIMIT?*/ ?
  • 317? ?
  • 318?#if?defined(CONFIG_VFD)?&&?defined(VFD_TEST_LOGO) ?
  • 319???ulong?bmp?=?0;????/*?default?bitmap?*/ ?
  • 320???extern?int?trab_vfd?(ulong?bitmap); ?
  • 321? ?
  • 322?#ifdef?CONFIG_MODEM_SUPPORT ?
  • 323???if?(do_mdm_init) ?
  • 324?????bmp?=?1;??/*?alternate?bitmap?*/ ?
  • 325?#endif ?
  • 326???trab_vfd?(bmp); ?
  • 327?#endif??/*?CONFIG_VFD?&&?VFD_TEST_LOGO?*/ ?
  • 328? ?
  • 329?#ifdef?CONFIG_BOOTCOUNT_LIMIT ?
  • 330???bootcount?=?bootcount_load();?????????//?加載保存的啟動次數 ?
  • 331???bootcount++;????????????????????????? //?啟動次數加1 ?
  • 332???bootcount_store?(bootcount);??????????//?更新啟動次數 ?
  • 333???sprintf?(bcs_set,?"%lu",?bootcount);??//?打印啟動次數 ?
  • 334???setenv?("bootcount",?bcs_set); ?
  • 335???bcs?=?getenv?("bootlimit"); ?
  • 336???bootlimit?=?bcs???simple_strtoul?(bcs,?NULL,?10)?:?0; ?
  • ??????????????????????????????????????????? //?轉換啟動次數字符串為UINT類型 ?
  • 337?#endif?/*?CONFIG_BOOTCOUNT_LIMIT?*/?
  • 第329~337行是啟動次數限制功能,啟動次數限制可以被用戶設置一個啟動次數,然后保存在Flash存儲器的特定位置,當到達啟動次數后,U-Boot無法啟動。該功能適合一些商業產品,通過配置不同的License限制用戶重新啟動系統。

    (2)程序第339~348行是Modem功能。如果系統中有Modem,打開該功能可以接受其他用戶通過電話網絡的撥號請求。Modem功能通常供一些遠程控制的系統使用,代碼如下:

  • 339?#ifdef?CONFIG_MODEM_SUPPORT ?
  • 340???debug?("DEBUG:?main_loop:???do_mdm_init=%d\n",?do_mdm_init); ?
  • 341???if?(do_mdm_init)?{????????????????????????????//?判斷是否需要初始化Modem ?
  • 342?????char?*str?=?strdup(getenv("mdm_cmd"));??????//?獲取Modem參數 ?
  • 343?????setenv?("preboot",?str);??/*?set?or?delete?definition?*/??
  • 344?????if?(str?!=?NULL) ?
  • 345???????free?(str); ?
  • 346?????mdm_init(); ??/*?wait?for?modem?connection?*/?//?初始化Modem ?
  • 347???} ?
  • 348?#endif???/*?CONFIG_MODEM_SUPPORT?*/
  • (3)接下來設置U-Boot的版本號初始化命令自動完成功能等。代碼如下:

  • 350?#ifdef?CONFIG_VERSION_VARIABLE ?
  • 351???{ ?
  • 352?????extern?char?version_string[]; ?
  • 353? ?
  • 354?????setenv?("ver",?version_string);???/*?set?version?variable?*/? ?
  • ?????????????????????????????????????????????//?設置版本號??
  • 355???} ?
  • 356?#endif?/*?CONFIG_VERSION_VARIABLE?*/ ?
  • 357? ?
  • 358?#ifdef?CFG_HUSH_PARSER ?
  • 359???u_boot_hush_start?();?????????????????//?初始化Hash功能 ?
  • 360?#endif ?
  • 361? ?
  • 362?#ifdef?CONFIG_AUTO_COMPLETE??
  • 363???install_auto_complete();??????????????//?初始化命令自動完成功能??
  • 364?#endif??
  • 365? ?
  • 366?#ifdef?CONFIG_PREBOOT ?
  • 367???if?((p?=?getenv?("preboot"))?!=?NULL)?{ ?
  • 368?#?ifdef?CONFIG_AUTOBOOT_KEYED ?
  • 369?????int?prev?=?disable_ctrlc(1);???/*?disable?Control?C?checking?*/ ?
  • ???????????????????????????????????????????//?關閉Crtl+C組合鍵?
  • 370?#?endif ?
  • 371? ?
  • 372?#?ifndef?CFG_HUSH_PARSER ?
  • 373?????run_command?(p,?0);??//?運行Boot參數 ?
  • 374?#?else ?
  • 375?????parse_string_outer(p,?FLAG_PARSE_SEMICOLON?| ?
  • 376?????????????FLAG_EXIT_FROM_LOOP); ?
  • 377?#?endif ?
  • 378? ?
  • 379?#?ifdef?CONFIG_AUTOBOOT_KEYED ?
  • 380?????disable_ctrlc(prev);??/*?restore?Control?C?checking?*/ ?
  • ???????????????????????????????????????????//?恢復Ctrl+C組合鍵 ?
  • 381?#?endif ?
  • 382???} ?
  • 383?#endif?/*?CONFIG_PREBOOT?*/?
  • 程序第350~356行是動態版本號功能支持代碼,version_string變量是在其他文件定義的一個字符串變量,當用戶改變U-Boot版本的時候會更新該變量。打開動態版本支持功能后,U-Boot在啟動的時候會顯示最新的版本號。

    程序第363行設置命令行自動完成功能,該功能與Linux的shell類似,當用戶輸入一部分命令后,可以通過按下鍵盤上的Tab鍵補全命令的剩 余部分

    main_loop()函數不同的功能使用宏開關控制不僅能提高代碼模塊化,更主要的是針對嵌入式系統Flash存儲器大小設計的。在嵌入式系統 上,不同的系統Flash存儲空間不同。對于一些Flash空間比較緊張的設備來說,通過宏開關關閉一些不是特別必要的功能如命令行自動完成,可以減小 U-Boot編譯后的文件大小。

    ?

    (4)在進入主循環之前,如果配置了啟動延遲功能,需要等待用戶從串口或者網絡接口輸入。如果用戶按下任意鍵打斷,啟動流程,會向終端打印出一個啟動菜單。代碼如下:

  • 385?#if?defined(CONFIG_BOOTDELAY)?&&?(CONFIG_BOOTDELAY?>=?0) ?
  • 386???s?=?getenv?("bootdelay"); ?
  • 387???bootdelay?=?s???(int)simple_strtol(s,?NULL,?10)?:?CONFIG_BOOTDELAY; ?
  • ?????????????????????????????????????????????????????????//?啟動延遲 ?
  • 388? ?
  • 389???debug?("###?main_loop?entered:?bootdelay=%d\n\n",?bootdelay); ?
  • 390? ?
  • 391?#?ifdef?CONFIG_BOOT_RETRY_TIME ?
  • 392???init_cmd_timeout?();????? ? //?初始化命令行超時機制 ?
  • 393?#?endif ?/*?CONFIG_BOOT_RETRY_TIME?*/ ?
  • 394? ?
  • 395?#ifdef?CONFIG_BOOTCOUNT_LIMIT??????? //一般不會檢查這破玩意。
  • 396???if?(bootlimit?&&?(bootcount?>?bootlimit))?{ ?//?檢查是否超出啟動次數限制 ?
  • 397?????printf?("Warning:?Bootlimit?(%u)?exceeded.?Using?altbootcmd.\n", ?
  • 398?????????????(unsigned)bootlimit); ?
  • 399?????s?=?getenv?("altbootcmd"); ?
  • 400???} ?
  • 401???else ?
  • 402?#endif ?/*?CONFIG_BOOTCOUNT_LIMIT?*/ ?
  • 403?????s?=?getenv?("bootcmd"); ?//?獲取啟動命令參數 ?
  • 404? ?
  • 405???debug?("###?main_loop:?bootcmd=\"%s\"\n",?s???s?:?"<UNDEFINED>"); ?
  • 406? ?
  • 407???if?(bootdelay?>=?0?&&?s?&&?!abortboot?(bootdelay))?{?? ?
  • ??????????????????????????????????????????????????? ?//檢查是否支持啟動延遲功能 ?
  • 408?#?ifdef?CONFIG_AUTOBOOT_KEYED ?
  • 409?????int?prev?=?disable_ctrlc(1);??/*?disable?Control?C?checking?*/?? ?
  • ?????????????????????????????????????????????????? ? //?關閉Ctrl+C組合鍵 ?
  • 410?#?endif ?
  • 411? ?
  • 412?#?ifndef?CFG_HUSH_PARSER ?
  • 413?????run_command?(s,?0);????? //?運行啟動命令行 ?
  • 414?#?else ?
  • 415?????parse_string_outer(s,?FLAG_PARSE_SEMICOLON?| ?
  • 416?????????????FLAG_EXIT_FROM_LOOP); ?
  • 417?#?endif ?
  • 418? ?
  • 419?#?ifdef?CONFIG_AUTOBOOT_KEYED ?
  • 420?????disable_ctrlc(prev);?? /*?restore?Control?C?checking?*/ ?
  • ???????????????????????????????????????????????????? //?打開Ctrl+C組合鍵 ?
  • 421?#?endif ?
  • 422???} ?
  • 423? ?
  • 424?#?ifdef?CONFIG_MENUKEY ?
  • 425???if?(menukey?==?CONFIG_MENUKEY)?{? ?//?檢查是否支持菜單鍵 ?
  • 426???????s?=?getenv("menucmd"); ?
  • 427???????if?(s)?{ ?
  • 428?#?ifndef?CFG_HUSH_PARSER ?
  • 429?????run_command?(s,?0); ?
  • 430?#?else ?
  • 431?????parse_string_outer(s,?FLAG_PARSE_SEMICOLON?| ?
  • 432?????????????FLAG_EXIT_FROM_LOOP); ?
  • 433?#?endif ?
  • 434???????} ?
  • 435???} ?
  • 436?#endif?/*?CONFIG_MENUKEY?*/ ?
  • 437?#endif??/*?CONFIG_BOOTDELAY?*/ ?
  • 438? ?
  • 439?#ifdef?CONFIG_AMIGAONEG3SE ?
  • 440???{ ?
  • 441???????extern?void?video_banner(void); ?
  • 442???????video_banner();???????????????//?打印啟動圖標??
  • 443???} ?
  • 444?#endif?
  • (5)在各功能設置完畢后,程序第454行進入一個for死循環,該循環不斷使用readline()函數(第463行)從控制臺(一般是串口)讀 取用戶的輸入,然后解析。有關如何解析命令請參考U-Boot代碼中run_command()函數的定義,

  • 446???/* ?
  • 447????*?Main?Loop?for?Monitor?Command?Processing??
  • 448????*/?
  • 449?#ifdef?CFG_HUSH_PARSER ?
  • 450???parse_file_outer(); ?
  • 451???/*?This?point?is?never?reached?*/ ?
  • 452???for?(;;); ?
  • 453?#else ?
  • 454???for?(;;)?{????????????????????????//?進入命令行循環?
  • 455?#ifdef?CONFIG_BOOT_RETRY_TIME??
  • 456?????if?(rc?>=?0)?{ ?
  • 457???????/*?Saw?enough?of?a?valid?command?to ?
  • 458????????*?restart?the?timeout. ?
  • 459????????*/ ?
  • 460???????reset_cmd_timeout();??????????//?設置命令行超時 ?
  • 461?????}??
  • 462?#endif ?
  • 463?????len?=?readline?(CFG_PROMPT);????//?讀取命令 ?
  • 464? ?
  • 465?????flag?=?0;?/*?assume?no?special?flags?for?now?*/ ?
  • 466?????if?(len?>?0) ?
  • 467???????strcpy?(lastcommand,?console_buffer);?
  • 468?????else?if?(len?==?0) ?
  • 469???????flag?|=?CMD_FLAG_REPEAT; ?
  • 470?#ifdef?CONFIG_BOOT_RETRY_TIME ?
  • 471?????else?if?(len?==?-2)?{ ?
  • 472???????/*?-2?means?timed?out,?retry?autoboot ?
  • 473????????*/ ?
  • 474???????puts?("\nTimed?out?waiting?for?command\n"); ?
  • 475?#?ifdef?CONFIG_RESET_TO_RETRY ?
  • 476???????/*?Reinit?board?to?run?initialization?code?again?*/ ?
  • 477???????do_reset?(NULL,?0,?0,?NULL); ?
  • 478?#?else ?
  • 479???????return;???/*?retry?autoboot?*/ ?
  • 480?#?endif?
  • 481?????} ?
  • 482?#endif ?
  • 483? ?
  • 484?????if?(len?==?-1) ?
  • 485???????puts?("<INTERRUPT>\n"); ?
  • 486?????else ?
  • 487???????rc?=?run_command?(lastcommand,?flag);?????//?運行命令?
  • 488? ?
  • 489?????if?(rc?<=?0)?{ ?
  • 490???????/*?invalid?command?or?not?repeatable,?forget?it?*/ ?
  • 491???????lastcommand[0]?=?0; ?
  • 492?????} ?
  • 493???}???// dead loop
  • 494?#endif?/*CFG_HUSH_PARSER*/ ?
  • 495?}?
  • U-BOOT的功能設計 基本就在這里。


    總結

    以上是生活随笔為你收集整理的u-boot 源码分析讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。