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

S3C2440 沒(méi)有上電之前映像文件存儲在Nand Flash 中,Nand Flash 有專(zhuān)門(mén)的控制器控制,不占用存儲器BANK。當開(kāi)發(fā)板上電時(shí),Nand Flash 的前4K 被復制到S3C2440 芯片內部的一塊容量為4K 的SRAM(被稱(chēng)為“Steppingstone”),然后這塊SRAM 被映射到地址0x00000000 處,程序從此處開(kāi)始運行。因為Nand Flash 中不能運行程序,所以在這4K 的代碼中必須包含一段代碼將Nand Flash 中的程序拷貝至S3C2440 的SDRAM 中(0x30000000 開(kāi)始)。應用環(huán)境初始化應該包含這段代碼。
Nand Flash 中的映像文件被拷貝至從0x30000000 開(kāi)始的SDRAM,這時(shí)候映像文件還沒(méi)有真正被執行,此時(shí)是加載狀態(tài),加載域如上圖所示,包括所有RO 屬性的輸出段和RW 屬性的輸出段,ZI 屬性的輸出段此時(shí)還不存在。在映像文件運行時(shí),會(huì )生成3 個(gè)運行域,如上圖所示,RO 和RW 屬性的運行域的起始地址和加載時(shí)是相同的,所以在應用程序執行環(huán)境初始化中不需要對其進(jìn)行拷貝,ZI 運行域則需要在映像開(kāi)始被執行前建立并被初始化為0,所以應用程序執行環(huán)境初始化中也要包含這類(lèi)代碼。(注意:RO 和RW 屬性的運行域的起始地址和加載時(shí)是相同的,即拷貝到SDRAM后就不用再移動(dòng)了。ADS中設置的RO Base和RW Base決定了程序的鏈接地址)
Nor Flash啟動(dòng)
當S3C2440采用Nor Flash啟動(dòng)時(shí),代碼可以在上面直接運行。但為了運行的效率,還是把程序拷貝到SDRRAM中運行。加載時(shí)地址關(guān)系和運行時(shí)地址關(guān)系和Nand Flash的基本相似。Nand Flash啟動(dòng)時(shí),會(huì )將RO段和RW段同時(shí)拷貝到SDRAM中,然后再建立ZI段。從Nor Flash啟動(dòng)時(shí)是先拷貝RO段,然后再拷貝RW段,最后建立ZI段。
三、相關(guān)啟動(dòng)代碼分析
[plain]view plaincopyprint?
- ;一個(gè)arm程序是由R0,RW,ZI三個(gè)段組成。其中R0為代碼段,RW是已經(jīng)初始化的全局變量,ZI是未
- ;初始化的全局變量,啟動(dòng)代碼要將RO段和RW段復制到RAM中并將ZI段清零。編譯器使用下列變量
- ;來(lái)記錄各段的起始地址和結束地址。這些標號的值是通過(guò)編譯器的設定來(lái)確定的如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;通過(guò)判斷OM[1:0]!=0,得知是NORFLashboot
- bnecopy_proc_beg;不用讀取nandflash
- adrr0,ResetEntry;OM[1:0]==0,從NANDFLash啟動(dòng)
- cmpr0,#0;再比較入口是否為0地址處,如果不是則用了仿真器
- bnecopy_proc_beg;用仿真器的情況也不要用nandflash啟動(dòng)
- ;nop
- ;===========================================================
- nand_boot_beg;這一段代碼完成從NAND讀代碼到RAM
- [{TRUE}
- blRdNF2SDRAM
- ]
- ldrpc,=copy_proc_beg;此時(shí)的PC已經(jīng)在0x30000000以后,是copy_proc_beg連接時(shí)的地址
- ;這個(gè)標號下面的代碼完成的功能就是把norflash的內容拷貝到ram當中。
- ;===========================================================
- copy_proc_beg
- adrr0,ResetEntry;裝載地址,ResetEntry值->r0
- ldrr2,BaseOfROM;BaseOfROM值
- cmpr0,r2;比較RO,R2
- ldreqr0,TopOfROM;如果相等的話(huà)(說(shuō)明在內存中運行),TopOfROM->r0當從NandFlash中啟動(dòng)時(shí)r0=r2,當從NorFlash啟動(dòng)時(shí)則不相等
- beqInitRam;同時(shí)跳到InitRam
- ;下面這個(gè)是針對代碼在NORFLASH時(shí)的拷貝方法
- ;功能為把從ResetEntry起,TopOfROM-BaseOfROM大小的數據拷到BaseOfROM
- ;TopOfROM和BaseOfROM為|Image$RO$Limit|和|Image$RO$Base|
- ;|Image$RO$Limit|和|Image$RO$Base|由連接器生成為生成的代碼的代碼段運行時(shí)的起啟和終止地址
- ;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個(gè)字節拷貝的,但RO段大小不一定是4個(gè)字節對齊的
- 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默認入口,編譯器會(huì )添加其他代碼
- 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|
評論