<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > bootloader和RO,RW,ZI在ARMC語言中

          bootloader和RO,RW,ZI在ARMC語言中

          作者: 時(shí)間:2016-11-10 來源:網(wǎng)絡(luò) 收藏
          Bootloader即引導(dǎo)加載程序,是系統(tǒng)加電后運(yùn)行的第一段軟件代碼。簡單的說它們都是bootloader,所完成的任務(wù)也大同小異。

          熟悉x86體系結(jié)構(gòu)的朋友肯定知道,x86平臺上bootloader是由BIOS和位于硬盤MBR中的OS Bootloader(比如Lilo和Grub)組成的。BIOS完成硬件的檢測和資源的分配后,將硬盤MBR中的bootloader讀到系統(tǒng)RAM中,之后此bootloader就會開始進(jìn)行主導(dǎo),將內(nèi)核搬到內(nèi)存中以及進(jìn)行一些必要的初始化工作,之后跳到內(nèi)核的入口地址來執(zhí)行,這樣內(nèi)核就開始啟動,也就是系統(tǒng)就啟動起來了。
          這里不得不插入一個(gè)話題,通過上面的介紹,細(xì)心的朋友就會產(chǎn)生一個(gè)疑問:為什么要有bootloader?既然bootloader只是作硬件的初始化并將內(nèi)核引導(dǎo)起來,那為什么不直接將這段代碼加到內(nèi)核中,直接啟動內(nèi)核就完成所有的工作?實(shí)際上要將bootloader與內(nèi)核整合在一起是完全可以做到的,但是如果這樣作的話,內(nèi)核就會失去他的通用性和靈活性,并且將bootloader與內(nèi)核分開會更有利于開發(fā)和管理,將啟動過程中與平臺硬件相關(guān)的代碼集合成bootloader,內(nèi)核就可以集中處理那些平臺通用的部分了(當(dāng)然實(shí)際上并沒有這么嚴(yán)格的劃分,內(nèi)核中還是會有一些平臺相關(guān)的代碼,不過已經(jīng)算是比較通用的了)。
          =============================================================================================================================================================================
          一個(gè)ARM程序包含3部分:RO,RWZI
          RO是程序中的指令和常量;RO就是readonly,
          RW是程序中的已初始化變量; RW就是read/write,
          (2) ARM映像文件的組成
          所謂ARM映像文件就是指燒錄到ROM中的bin文件,也成為image文件。以下用Image文件來稱呼它。Image文件包含了RO和RW數(shù)據(jù)。之所以Image文件不包含ZI數(shù)據(jù),是因?yàn)閆I數(shù)據(jù)都是0,沒必要包含,只要程序運(yùn)行之前將ZI數(shù)據(jù)所在的區(qū)域一律清零即可。包含進(jìn)去反而浪費(fèi)存儲空間。
          Q:為什么Image中必須包含RO和RW?
          A:因?yàn)镽O中的指令和常量以及RW中初始化過的變量是不能像ZI那樣“無中生有”的。
          實(shí)際上,ROM中的指令至少應(yīng)該有這樣的功能:
          1. 將RW從ROM中搬到RAM中,因?yàn)镽W是變量,變量不能存在ROM中。
          2. 將ZI所在的RAM區(qū)域全部清零,因?yàn)閆I區(qū)域并不在Image中,所以需要程序根據(jù)編譯器給出的ZI地址及大小來將相應(yīng)得RAM區(qū)域清零。ZI中也是變量,同理:變量不能存在ROM中.在程序運(yùn)行的最初階段,RO中的指令完成了這兩項(xiàng)工作后C程序才能正常訪問變量。否則只能運(yùn)行不含變量的代碼。
          下面我將給出幾個(gè)例子,最直觀的來說明RO,RW,ZI在C中是什么意思。
          1; RO
          看下面兩段程序,他們之間差了一條語句,這條語句就是聲明一個(gè)字符常量。因此按照我們之前說的,他們之間應(yīng)該只會在RO數(shù)據(jù)中相差一個(gè)字節(jié)(字符常量為1字節(jié))。
          Prog1:
          #include
          void main(void)
          {
          ;
          }

          Prog2:
          #include
          const char a = 5;
          void main(void)
          {
          ;
          }
          Prog1編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 60 0 96 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1008 ( 0.98kB)
          Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
          ================================================================================
          Prog2編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 61 0 96 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1009 ( 0.99kB)
          Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)
          ================================================================================
          以上兩個(gè)程序編譯出來后的信息可以看出:
          Prog1和Prog2的RO包含了Code和RO Data兩類數(shù)據(jù)。他們的唯一區(qū)別就是Prog2的RO Data比Prog1多了1個(gè)字節(jié)。這正和之前的推測一致。如果增加的是一條指令而不是一個(gè)常量,則結(jié)果應(yīng)該是Code數(shù)據(jù)大小有差別。
          2; RW
          同樣再看兩個(gè)程序,他們之間只相差一個(gè)“已初始化的變量”,按照之前所講的,已初始化的變量應(yīng)該是算在RW中的,所以兩個(gè)程序之間應(yīng)該是RW大小有區(qū)別。
          Prog3:
          #include
          void main(void)
          {
          ;
          }
          Prog4:
          #include
          char a = 5;
          void main(void)
          {
          ;
          }
          Prog3編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 60 0 96 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1008 ( 0.98kB)
          Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
          ================================================================================
          Prog4編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 60 1 96 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1008 ( 0.98kB)
          Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1009 ( 0.99kB)
          ================================================================================
          可以看出Prog3和Prog4之間確實(shí)只有RW Data之間相差了1個(gè)字節(jié),這個(gè)字節(jié)正是被初始化過的一個(gè)字符型變量“a”所引起的。
          再看兩個(gè)程序,他們之間的差別是一個(gè)未初始化的變量“a”,從之前的了解中,應(yīng)該可以推測,這兩個(gè)程序之間應(yīng)該只有ZI大小有差別。
          Prog3:
          #include
          void main(void)
          {
          ;
          }
          Prog4:
          #include
          char a;
          void main(void)
          {
          ;
          }
          Prog3編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 60 0 96 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1008 ( 0.98kB)
          Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
          ================================================================================
          Prog4編譯出來后的信息如下:
          ================================================================================
          Code RO Data RW Data ZI Data Debug
          948 60 0 97 0 Grand Totals
          ================================================================================
          Total RO Size(Code + RO Data) 1008 ( 0.98kB)
          Total RW Size(RW Data + ZI Data) 97 ( 0.09kB)
          Total ROM Size(Code + RO Data + RW Data) 1008 ( 0.98kB)
          ================================================================================
          編譯的結(jié)果完全符合推測,只有ZI數(shù)據(jù)相差了1個(gè)字節(jié)。這個(gè)字節(jié)正是未初始化的一個(gè)字符型變量“a”所引起的。
          注意:如果一個(gè)變量被初始化為0,則該變量的處理方法與未初始化華變量一樣放在ZI區(qū)域。
          即:ARM C程序中,所有的未初始化變量都會被自動初始化為0。
          總結(jié): 1; C中的指令以及常量被編譯后是RO類型數(shù)據(jù)。
          2; C中的未被初始化或初始化為0的變量編譯后是ZI類型數(shù)據(jù)。
          3; C中的已被初始化成非0值的變量編譯后市RW類型數(shù)據(jù)。
          RAM主要指:PSRAM,SDRAM,SRAM,DDRAM
          (5) Image$$??$$Limit 的含義
          =0x0c100000+Tatal RO size+1
          = 0x0c200000+0x37(4的倍數(shù),0到55,共56個(gè)單元)

          本文引用地址:http://www.ex-cimer.com/article/201611/317191.htm

          vivi是mizi開發(fā)的用于s3c241x/s3c244x 的linux bootloader,友善之臂移植了USB 下載功能后就成了現(xiàn)在看到的supervivi;u-boot是一個(gè)廣泛用于ARM平臺的bootloader, 目前也支持s3c241x/s3c244x,可以用來啟動Linux;Eboot是WinCE平臺下的bootloader。uboot就是通過usb來下載os image文件的bootloader; eboot就是通過ethernet下載os image的bootloader。

          嵌入式平臺上就跟x86不一樣了,但是很類似,而且因?yàn)椴煌钠脚_架構(gòu)本身的特點(diǎn),每種平臺對應(yīng)的bootloader做得事情會有所不同,相對x86平臺,一般不會有bios(但是這些都不是絕對的,有一些平臺也會有內(nèi)嵌類似bios的啟動程序),整個(gè)系統(tǒng)的引導(dǎo)加載都由存放在flash,rom等存儲設(shè)備特定位置的bootloader來完成。如arm平臺中的2410,2440,bootloader存在在flash中的0x0的地方,板子加電后,系統(tǒng)會將bootloader的最前面的4k代碼通過硬件邏輯自動的裝載到SRAM中,之后從SRAM中的0開始執(zhí)行,在這4k的程序中會完成基本的硬件的初始化,將完整的bootloader搬到內(nèi)存中,并跳轉(zhuǎn)到ram中的bootloader來進(jìn)行繼續(xù)執(zhí)行。

          回到之前所說的,bootloader啟動起來之后,通常會有兩種操作模式:

          啟動加載模式就是一上電,bootloader進(jìn)行相關(guān)的初始化之后就馬上把內(nèi)核啟動起來,注意關(guān)鍵的地方在整個(gè)過程中沒有用戶的參與,這種其實(shí)也就是bootloader的默認(rèn)處理,一般的產(chǎn)品設(shè)計(jì)ok進(jìn)行最后的發(fā)布時(shí),就會處于此種狀態(tài)。

          下載模這種模式,大家肯定非常熟悉,就是大家在進(jìn)行開發(fā)的時(shí)候所處的環(huán)境,我們經(jīng)常使用的tftp, erase, cp.b等命令將相關(guān)的bin,img文件燒到板子上,這種情況下其實(shí)就是處于bootloader的執(zhí)行環(huán)境下,所以一定意義來說,大多的bootloader其實(shí)就是一個(gè)嵌入式操作系統(tǒng),只是它的功能不強(qiáng),不像linux的結(jié)構(gòu)那么復(fù)雜,而且也不會支持多進(jìn)程多線程處理。

          bootloader種類和分類

          這里的分類實(shí)際上是依據(jù)上面的bootloader的操作模式來進(jìn)行劃分的,根據(jù)一個(gè)系統(tǒng)是否支持上面的下載模式我們這里將bootloader劃分為bootloader和monitor(這不是我劃分的,恩,是從別人的文章中引述過來的,不過我覺得他說的很有道理),這里”bootloader”是指只是引導(dǎo)設(shè)備與執(zhí)行主程序的固件,而”monitor”是指不僅擁有bootloader功能的,還能夠進(jìn)入下載模式的固件。

          (1)、ARM程序的組成

          此處所說的“ARM程序”是指在ARM系統(tǒng)中正在執(zhí)行的程序,而非保存在ROM中的bin映像(image)文件,這一點(diǎn)清注意區(qū)別。

          ZI是程序中的未初始化的變量;ZI就是zero;

          (3)ARM程序的執(zhí)行過程

          從以上兩點(diǎn)可以知道,燒錄到ROM中的image文件與實(shí)際運(yùn)行時(shí)的ARM程序之間并不是完全一樣的。因此就有必要了解ARM程序是如何從ROM中的image到達(dá)實(shí)際運(yùn)行狀態(tài)的。

          3; ZI

          (4) ROM主要指:NAND Flash,Nor Flash

          對于剛學(xué)習(xí)ARM的人來說,如果分析它的啟動代碼,往往不明白下面幾個(gè)變量的含義:|Image$$RO$$Limit|、|Image$$RW$$Base|、|Image$$ZI$$Base|。

          當(dāng)把程序編寫好以后,就要進(jìn)行編譯和鏈接了,在ADS1.2中選擇MAKE按鈕,會出現(xiàn)一個(gè)Errors and Warnings的對話框,在該欄中顯示編譯和鏈接的結(jié)果,如果沒有錯(cuò)誤,在文件的最后應(yīng)該能看到Image component sizes,后面緊跟的依次是Code,RO Data ,RW Data ,ZI Data ,Debug 各個(gè)項(xiàng)目的字節(jié)數(shù),最后會有他們的一個(gè)統(tǒng)計(jì)數(shù)據(jù):

          Code 163632 ,RO Data 20939 ,RW Data 53 ,ZI Data 17028

          Tatal RO size (Code+ RO Data) 184571 (180.25kB)

          Tatal RW size(RW Data+ ZI Data) 17081(16.68 kB)

          Tatal ROM size(Code+ RO Data+ RW Data) 184624(180.30 kB)

          后面的字節(jié)數(shù)是根據(jù)用戶不同的程序而來的,下面就以上面的數(shù)據(jù)為例來介紹那幾個(gè)變量的計(jì)算。

          在ADS的Debug Settings中有一欄是Linker/ARM Linker,在output選項(xiàng)中有一個(gè)RO base選項(xiàng),

          假如RO base設(shè)置為0x0c100000,后面的RW base 設(shè)置為0x0c200000,然后在Options選項(xiàng)中有Image entry point ,是一個(gè)初始程序的入口地址,設(shè)置為0x0c100000 。

          有了上面這些信息我們就可以完全知道這幾個(gè)變量是怎么來的了:

          |Image$$RO$$Base| = Image entry point =RO base =0x0c100000 ;表示程序代碼存放的起始地址

          |Image$$RO$$Limit|=程序代碼起始地址+代碼長度+1

          = 0x0c100000 + 184571 + 1 = 0x0c100000 +0x2D0FB + 1

          = 0x0c12d0fc

          |Image$$RW$$Base| = 0x0c200000=RW base 地址指定

          |Image$$RW$$Limit| =|Image$$RW$$Base|+ RW Data 53

          =0x0c200037

          |Image$$ZI$$Base| = |Image$$RW$$Limit| + 1 =0x0c200038

          |Image$$ZI$$Limit| = |Image$$ZI$$Base| + ZI Data 17028

          =0x0c200038 + 0x4284

          =0x0c2042bc

          也可以由此計(jì)算:

          |Image$$ZI$$Limit| = |Image$$RW$$Base| +TatalRWsize(RWData+ZIData) 17081

          =0x0c200000+0x42b9+3(要滿足4的倍數(shù))

          =0x0c2042bc



          關(guān)鍵詞: bootloaderRORWZIAR

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();