結合PXA270 Bootloader實例詳細分析ARM映象文件

結合PXA270 Bootloader實例詳細分析ARM映象文件

最近花了一個月的時間終於把PXA270的板子Bootloader 部分整出來了,頗費周折;其中的很長一段時間,一直被ARM可執行程序的執行機理迷惑:搞不懂ARM的映象文件組成、代碼重定位、地址重映射remap等,網上查了N多資料看了N多技術帖子總算整清楚。如今寫出來整理一下思路,也爲其它初始進入ARM系統設計的兄弟們提供點資料借鑑,少走些彎路是好。

    ARM學習過程中,初學者最難突破的應當是ARM映象文件形態和ARM啓動代碼分析了,本文將以我的Bootloader源碼爲例,力求作個透徹分析。

如下給出我的開發環境:

²        CpuINTEL PXA270 (ARM V5TE)

²        Board:INTEL MAINSTONE 2

²      Memory:64MByte SDRAM,32MByte NorFlash(Inte E28F128),32MByte NandFlash

²      Cross-complier:cross_3.3.2

一、關於映象文件和load regionexecute region

1.       ARM映象文件組成

我們在ADS中編譯源代碼文件後的生成文件有兩個:.axf和.bin文件。.bin文件是二進制格式執行文件,它纔是真正可下載到FLASH中運行的;.axf文件是ADS的調試文件,利用UltraEdit查看其二進制代碼,可以發現.axf其實是在.bin文件基礎上增加文件頭標識、文件尾表示(U-boot中的mkimage工具在映象文件中加入64kbyte的文件頭,以供U-Boot識別)、再插入ADS的調試符號。打開ADS的調試器,可對.axf文件調試。

2.       ARM映象文件加載域(load region)、運行域(execute region)

看了很多ARM教材這方面都沒怎麼涉及,有的書本提到感覺始終太過術語話,不太好明白。這裏我首先對些關鍵概念做個簡單名詞解釋,相信大家一看就懂:

²        RO:Read-only
RW:Read-write.
ZI:Zero-initialized

²        段(Section):描述映像文件的代碼或數據塊。

²        輸入段(input section):它包含着代碼,初始化數據或標記了在應用程序運行之前必須要初始化爲0的一段內存。

²        輸出段(output section):它包含了一系列具有相同的RO,RW或ZI屬性的輸入段。

²        域(Regions):在一個映像文件中,一個域包含了1至3個輸出段。1個或多個域(一般是一個)組織在一起,就構成了最終的映像文件。

²        加載時地址:是指映像文件位於存儲器(在該映像文件沒有運行時,如FLASH)中的地址。

²        運行時地址:是指映像文件在運行時的地址(映象文件內存中運行)。

其實舉個實例來分析:我的源代碼編譯後生成的二進制zybootloader.bin文件就是一個域,打開ADS的”Realese Settings”標籤頁“listing”,選中“Image map””Symbols”,編譯生成目標文件時,ADS就會生成映象、符號的地址表。觀察發現它由三個輸出段組成:RO、RW、ZI,各輸出段大小如圖:

二、 源代碼詳細分析

說了這麼多,拿我自己的Bootloader啓動代碼來給大家分析一下,就再清楚不過的了。

Bootloader在進入C代碼運行之前,先經歷一些代碼位置無關的順序初始化例程:

²        獲取外部目標頭文件,聲明外部變量

²        主程序入口,定義中斷向量表,跳轉到復位異常

²        設置處理器工作模式爲SVC,並禁止中斷(bootloader運行過程中一直都要禁止)

²        初始化GPIO、內存控制寄存器

²        初始化電源管理寄存器,設置CPU工作頻率時鐘

²        爲六大中斷分配堆棧空間

以上步驟大家結合datasheet可以對照看懂。

最後一步,最最關鍵的啦,Bootloader將要做個“乾坤大挪移”動作,然後對ZI區清零:

Step 1:複製RO到SDRAM,程序將無縫切換到SDRAM空間運行;

  Step 2:複製RW到SDRAM,這裏包括已初始化的全局變量;並且對ZI段未初始化的全局變量全部清零!OK,現在程序可以安全跳入C主函數運行了!下圖爲兩步的示意圖,其中:

|Image$$RO$$Base| ; RO段起始地址

|Image$$RO$$Limit| ; RO段結束地址加1

|Image$$RW$$Base| ; RW段起始地址

|Image$$RW$$Limit| ; RW段結束地址加1

|Image$$ZI$$Base| ; ZI段起始地址

|Image$$ZI$$Limit| ; ZI段結束地址加1

編譯器從R0_base 和RW_base來得到這些地址。

源代碼詳細分析:

;/************************************************************************ /

;Step 1 將FLASH的CODE拷貝到SDRAM中(RO_BASE指定的地址)

;===============================================

       ;bl     xlli_icache_enable   ; Enable I-Cache, D-Cache, BTB

       ;don't enable cache, make it's safe for download and boot!

       ;bl    LedFlash ;led flash test after xlli_icache_enable, hzh

       IF    RELOCATE_ROM=1

       adr   r0, MAIN

       ldr   r2, BaseOfROM

       cmp r0, r2

       ldreq       r0, TopOfROM

       beq  InitRam  

       ldr r3, TopOfROM

0    

       ldmia       r0!, {r4-r7}

       stmia       r2!, {r4-r7}

       cmp r2, r3

       bcc  %B0;無符號數小於

       sub  r2, r2, r3 ; r2 超出r3

       sub  r0, r0, r2 ;確保取得RW區精確起始地址

;Step 2:初始化SDRAM,將RW段拷貝到SDRAM

InitRam  

       ldr   r2, BaseOfBSS

       ldr   r3, BaseOfZero     

0

       cmp r2, r3

       ldrcc       r1, [r0], #4

       strcc       r1, [r2], #4

       bcc  %B0      

;對SDRAM ZI段清零

       mov r0,   #0

       ldr   r3,   EndOfBSS

1    

       cmp r2,   r3

       strcc       r0, [r2], #4

       bcc  %B1

;跳轉到C的主函數Main中

       ldr   pc, =GotoMain

GotoMain

       ;mov       r0, #3

       ;bl    LedSet

       ;IF :DEF: BOOTABLE

       ldr   r0, EndOfBSS

       ;ELSE

       ;ldr  r0,=|Image$$ZI$$Limit|

       ;

       bl     PlatformMain

       b     GotoMain

       ENDIF

BaseOfROM   DCD       |Image$$RO$$Base|

TopOfROM    DCD       |Image$$RO$$Limit|

BaseOfBSS     DCD       |Image$$RW$$Base|

BaseOfZero    DCD       |Image$$ZI$$Base|

EndOfBSS      DCD       |Image$$ZI$$Limit|

二、 後續

已經今天暫且寫到這裏,PXA270的Bootloader已經做成功了,後面將會結合自己的開發筆記陸續對U-Boot 1.1.6在我的開發板PXA270上的移植流程和LINUX內核啓動代碼作分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章