S3C2440啟動代碼中應用程序執行環境的初始化
一、基礎知識
我們編寫的源文件(.c 或.s)經過ARM 編譯器的編譯生成ELF 格式的目標文件(后綴名為.o),目標文件經過ARM 連接器連接以后生成ELF 格式的映像文件(后綴名為.axf),此時的映像文件還包含一些調試信息,我們還需要通過fromelf 工具將其轉換成適合在ROM 或RAM 中運行的二進制代碼(后綴名為.bin),這時生成的二進制映像文件就可以被燒寫入目標板的ROM 或FLASH 中,當目標板上電后可以通過各種方式在ROM 或RAM 中運行。
一個可執行程序的映像文件由一個或多個域組成,域分為兩種:一種是映像文件在存儲器中存放的地址,稱為加載域;另一種是映像文件運行時的地址,稱為運行域。每個域由一個或3 個輸出段組成,每個輸出段則由一個或多個輸入段組成。輸入段包含程序代碼、已經初始化的數據、未經初始化的存儲區、被初始化為0 的存儲區,輸入段據此可分為三種屬性:RO(只讀,包括代碼和常量)、RW(可讀可寫,包括已經初始化的全局變量和靜態變量)、ZI(未初始化的變量,需初始化為0), 連接器根據屬性將輸入段分組,組成不同的輸出段。一個輸出段是有具有相同屬性的輸入段組成的,輸出段的屬性與其中輸入段的屬性相同,因而輸出段也分為三種。域由不同屬性的輸出段組成,輸出段在域中的排列順序為RO 輸出段排在最前,然后是RW 輸出段,RW 輸出段和RO 輸出段可以不連續,最后是ZI 輸出段,ZI 輸出段是緊接著RW 輸出段的(加載域只包含RO、RW 輸出段,原因見后述)。
可執行鏡像一開始一般是存儲在系統的ROM 或FLASH 中,RO 段是只讀的,在運行的時候我們不能改變它,所以RO 段在運行的時候可以駐留在ROM 或FLASH 中,也可以拷貝到運行速度更快的RAM 中;RW 段在運行的時候,我們需要對其讀寫,在運行前這一段必須被拷貝至RAM 中;ZI 段為未初始化的全局變量段,只需要在程序運行之前建立ZI 并將其所在區域全部清零即可,因此鏡像裝載域不必包含ZI 輸出段,但在運行域需要包含ZI,并且ZI 必須處于RAM。
通過以上說明,我們知道如果某個鏡像只有RO 段的話,程序可以不必拷貝至RAM,但是如果程序包含RW 段的話,RW 段是必需要拷貝至RAM 中的,如果有必要的話還需在RAM 中創建ZI 段,并將其清零。為保證程序的正確執行,而進行必要的數據拷貝和清零,就是應用程序執行環境的初始化。
二、S3C2440啟動的基本原理
Nand Flash啟動
當S3C2440 開發板采用的是Nand Flash 啟動,鏡像一開始是存儲在Nand Flash 中,而Nand Flash只能作為存儲程序和數據之用,無法在其中運行程序,所以S3C2440 開發板啟動代碼中應用環境初始化這一步和上述步驟稍有不同。S3C2440 鏡像文件加載和運行時的地址映射關系如下圖所示:

S3C2440 沒有上電之前映像文件存儲在Nand Flash 中,Nand Flash 有專門的控制器控制,不占用存儲器BANK。當開發板上電時,Nand Flash 的前4K 被復制到S3C2440 芯片內部的一塊容量為4K 的SRAM(被稱為“Steppingstone”),然后這塊SRAM 被映射到地址0x00000000 處,程序從此處開始運行。因為Nand Flash 中不能運行程序,所以在這4K 的代碼中必須包含一段代碼將Nand Flash 中的程序拷貝至S3C2440 的SDRAM 中(0x30000000 開始)。應用環境初始化應該包含這段代碼。
Nand Flash 中的映像文件被拷貝至從0x30000000 開始的SDRAM,這時候映像文件還沒有真正被執行,此時是加載狀態,加載域如上圖所示,包括所有RO 屬性的輸出段和RW 屬性的輸出段,ZI 屬性的輸出段此時還不存在。在映像文件運行時,會生成3 個運行域,如上圖所示,RO 和RW 屬性的運行域的起始地址和加載時是相同的,所以在應用程序執行環境初始化中不需要對其進行拷貝,ZI 運行域則需要在映像開始被執行前建立并被初始化為0,所以應用程序執行環境初始化中也要包含這類代碼。(注意:RO 和RW 屬性的運行域的起始地址和加載時是相同的,即拷貝到SDRAM后就不用再移動了。ADS中設置的RO Base和RW Base決定了程序的鏈接地址)
Nor Flash啟動
當S3C2440采用Nor Flash啟動時,代碼可以在上面直接運行。但為了運行的效率,還是把程序拷貝到SDRRAM中運行。加載時地址關系和運行時地址關系和Nand Flash的基本相似。Nand Flash啟動時,會將RO段和RW段同時拷貝到SDRAM中,然后再建立ZI段。從Nor Flash啟動時是先拷貝RO段,然后再拷貝RW段,最后建立ZI段。
三、相關啟動代碼分析
[plain]view plaincopyprint?
- ;一個arm程序是由R0,RW,ZI三個段組成。其中R0為代碼段,RW是已經初始化的全局變量,ZI是未
- ;初始化的全局變量,啟動代碼要將RO段和RW段復制到RAM中并將ZI段清零。編譯器使用下列變量
- ;來記錄各段的起始地址和結束地址。這些標號的值是通過編譯器的設定來確定的如ADS中對ro-base和
- ;rw-base的設定。
- IMPORT|Image$RO$Base|;BaseofROMcode
- IMPORT|Image$RO$Limit|;EndofROMcode(=startofROMdata)
- IMPORT|Image$RW$Base|;BaseofRAMtoinitialise
- IMPORT|Image$ZI$Base|;Baseandlimitofarea
- IMPORT|Image$ZI$Limit|;tozeroinitialise
- ;===========================================================
- ldrr0,=BWSCON
- ldrr0,[r0]
- andsr0,r0,#6;通過判斷OM[1:0]!=0,得知是NORFLashboot
- bnecopy_proc_beg;不用讀取nandflash
- adrr0,ResetEntry;OM[1:0]==0,從NANDFLash啟動
- cmpr0,#0;再比較入口是否為0地址處,如果不是則用了仿真器
- bnecopy_proc_beg;用仿真器的情況也不要用nandflash啟動
- ;nop
- ;===========================================================
- nand_boot_beg;這一段代碼完成從NAND讀代碼到RAM
- [{TRUE}
- blRdNF2SDRAM
- ]
- ldrpc,=copy_proc_beg;此時的PC已經在0x30000000以后,是copy_proc_beg連接時的地址
- ;這個標號下面的代碼完成的功能就是把norflash的內容拷貝到ram當中。
- ;===========================================================
- copy_proc_beg
- adrr0,ResetEntry;裝載地址,ResetEntry值->r0
- ldrr2,BaseOfROM;BaseOfROM值
- cmpr0,r2;比較RO,R2
- ldreqr0,TopOfROM;如果相等的話(說明在內存中運行),TopOfROM->r0當從NandFlash中啟動時r0=r2,當從NorFlash啟動時則不相等
- beqInitRam;同時跳到InitRam
- ;下面這個是針對代碼在NORFLASH時的拷貝方法
- ;功能為把從ResetEntry起,TopOfROM-BaseOfROM大小的數據拷到BaseOfROM
- ;TopOfROM和BaseOfROM為|Image$RO$Limit|和|Image$RO$Base|
- ;|Image$RO$Limit|和|Image$RO$Base|由連接器生成為生成的代碼的代碼段運行時的起啟和終止地址
- ;BaseOfBSS和BaseOfZero為|Image$RW$Base|和|Image$ZI$Base|
- ;|Image$RW$Base|和|Image$ZI$Base|也是由連接器生成,兩者之間就是初始化數據的存放地放
- ldrr3,TopOfROM
- 0
- ldmiar0!,{r4-r7}
- stmiar2!,{r4-r7}
- cmpr2,r3
- bcc%B0
- subr2,r2,r3;這兩句代碼是修正字非對齊的情況,因為是按4個字節拷貝的,但RO段大小不一定是4個字節對齊的
- subr0,r0,r2
- InitRam
- ldrr2,BaseOfBSS
- ldrr3,BaseOfZero
- 0
- cmpr2,r3
- ldrccr1,[r0],#4
- strccr1,[r2],#4
- bcc%B0;這一段是對ResetEntry里面定義好的數據拷貝到RW段。
- movr0,#0
- ldrr3,EndOfBSS
- 1
- cmpr2,r3
- strccr0,[r2],#4
- bcc%B1;初始化ZI段
- ldrpc,=%F2;gotocompileraddress
- 2
- ;[CLKDIV_VAL>1;meansFclk:Hclkisnot1:1.
- ;blMMU_SetAsyncBusMode
- ;|
- ;blMMU_SetFastBusMode;defaultvalue.
- ;]
- [:LNOT:THUMBCODE
- blMain;不要用main()因為main()是ADS默認入口,編譯器會添加其他代碼
- b.;跳轉到Main不成功則掛起
- ]
- [THUMBCODE;forstart-upcodeforThumbmode
- orrlr,pc,#1
- bxlr
- CODE16
- blMain;Donotusemain()because......
- b.
- CODE32
- ]
- BaseOfROMDCD|Image$RO$Base|
- TopOfROMDCD|Image$RO$Limit|
- BaseOfBSSDCD|Image$RW$Base|
- BaseOfZeroDCD|Image$ZI$Base|
- EndOfBSSDCD|Image$ZI$Limit|
評論