有關bootloader的链接的memory layout的疑惑

我們生活周遭存在太多太多的 embedded system ,過去 embedded system 有專屬的 OS,現在 linux 也可以應用在嵌入式環境,不過本版將廣泛討論所有嵌入式系統不只 linux 喔,歡迎有這方面經驗或有興趣的朋友一同進來討論。

版主: chester

有關bootloader的链接的memory layout的疑惑

文章aaronwong » 週一 7月 23, 2007 2:43 am

最近想研究一下bootloader,我們都知道bootloader的memory layout是要通過一個自己攥寫的鏈接腳本(linker script)來指定的。我的開發板的linker script檔案boot.lds如下:
代碼: 選擇全部
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS {
   . = 0xa3f00000;
   __boot_start = .;
   .start      ALIGN(4) : {
      *(.text.start)
   }

   .setup      ALIGN(4) : {
      setup_block = .;
      *(.setup)
      setup_block_end = .;
   }

   .text      ALIGN(4) : {
      *(.text)
   }

   .rodata      ALIGN(4) : {
      *(.rodata)
   }

   .data      ALIGN(4) : {
      *(.data)
   }

   .got      ALIGN(4) : {
      *(.got)
   }
   __boot_end = .;

   .bss      ALIGN(16) : {
      bss_start = .;
      *(.bss)
      *(COMMON)
      bss_end = .;


   stack_point = __boot_start + 0x00100000;
   loader_size = __boot_end - __boot_start;
   setup_size  = setup_block_end - setup_block;
}

上面的地址0xa3f00000是SDRAM的(TOP ADDRESS-1MB)
而第一個啟動程式start.S的代碼如下:
代碼: 選擇全部
#include <config.h>
#include <hardware.h>
#define eth_base 0x0c00030e

.section .text.start
.global _start
_start :
   b      start

.section .text
start :
   bl      define_gpio
   bl      clock_enable
   bl      setup_memory      @ setup static and dynamic memory

   @ copy bootloader to dynamic memory area
   ldr      r0, =0x00
   ldr      r1, =__boot_start
   ldr      r2, =__boot_end
 1:   ldmia   r0!, {r3-r10}
   stmia   r1!, {r3-r10}
   cmp      r1, r2
   blt      1b

   @ clear bss area
   mov      r3, #0x00
   mov      r4, #0x00
   mov      r5, #0x00
   mov      r6, #0x00
   ldr      r0, =bss_start
   ldr      r1, =bss_end
 1:   stmia   r0!, {r3-r6}
   cmp      r0, r1
   blt      1b

        ldr r0, =eth_base
        ldr r1, [r0]


   @ set stack point
   ldr      sp, =stack_point-4

   @ jump to c code
   ldr      pc, =main

我們知道,ARM的第一條指令是從地址0x0開始執行的,那么_start所標記的第一條指令所在的section .text.start應當被relocate到地址0x0(ROM地址空間),而在linker script中卻被指定到地址0xa3f00000(SDRAM address space),那么所得到的executable image檔中,第一條指令的地址就是0xa3f00000,使用objdump和readelf可得到如下信息:
代碼: 選擇全部
[aaronwong@localhost src]$ objdump -h boot.elf32 | grep ".start"
  0 .start        00000004  a3f00000  a3f00000  00008000  2**0
[aaronwong@localhost src]$ readelf -s boot.elf32 | grep "_start"
   142: a3f04364   352 FUNC    LOCAL  DEFAULT    3 tftp_start
   263: a3f00000     0 NOTYPE  GLOBAL DEFAULT  ABS __boot_start
   279: a3f00000     0 NOTYPE  GLOBAL DEFAULT    1 _start
   290: a3f09390     0 NOTYPE  GLOBAL DEFAULT   13 bss_start

也就是說,第一條指令的地址被標記為0xa3f00000,其他的label symbol也都是相對于它而言的,這樣的boot image如果download到FLASH MEMORY,怎么能正常執行呢?還是說我理解錯了呢?謝謝指點!
aaronwong
可愛的小學生
可愛的小學生
 
文章: 4
註冊時間: 週六 6月 23, 2007 11:01 pm
來自: Shanghai

文章mingchi » 週一 7月 23, 2007 10:59 pm

代碼: 選擇全部
   @ copy bootloader to dynamic memory area
   ldr      r0, =0x00
   ldr      r1, =__boot_start
   ldr      r2, =__boot_end
 1:   ldmia   r0!, {r3-r10}
   stmia   r1!, {r3-r10}
   cmp      r1, r2
   blt      1b
...

這一段就是把bootloader整個copy到sdram(0xa3f00000)中執行了。
所以一開始bootloader雖然放在0x0位址,啟動後將自己複製到sdram,
最後
ldr pc, =main
可以實現全區跳躍,跳到SDRAM中的main位址執行。
(為何不用b指令呢?因為branch不能跳那麼遠,所以用ldr)
mingchi
可愛的小學生
可愛的小學生
 
文章: 11
註冊時間: 週二 5月 08, 2007 5:58 pm
來自: 展翊電子

文章aaronwong » 週二 7月 24, 2007 12:58 pm

mingchi 寫:
代碼: 選擇全部
   @ copy bootloader to dynamic memory area
   ldr      r0, =0x00
   ldr      r1, =__boot_start
   ldr      r2, =__boot_end
 1:   ldmia   r0!, {r3-r10}
   stmia   r1!, {r3-r10}
   cmp      r1, r2
   blt      1b
...

這一段就是把bootloader整個copy到sdram(0xa3f00000)中執行了。

這一段的確是把bootloader從地址0x0處拷貝到__boot_start(0xa3f00000)處。但您說的“一開始bootloader雖然放在0x0位址”我還是不能理解,因爲根據boot.lds來看,
代碼: 選擇全部
ENTRY(_start)
SECTIONS {
   . = 0xa3f00000;
   __boot_start = .;
   .start      ALIGN(4) : {
      *(.text.start)
   }

ENTRY(_start)入口第一條指令的地址=0xa3f00000=__boot_start,但無論如何,第一條指令應該從地址0x0開始才對啊?根據我的理解,按照這個boot.lds,最後得到的boot映象檔案的memory layout如下圖所示:
圖檔
圖中最底端即地址最小處是ENTRY(_start),在boot.lds中被設置成0xa3f00000開始,幷且等于__boot_start,第一個output section是.start段,它又是由源代碼start.S中的input section .text.start組成,那麽也就是第一條指令“b start”,這條指令本來應該在地址0x0處才對,而現在按照boot.lds的設置(如上圖),卻被安排到了0xa3f00000處,這不是不對了嗎?
而且如果映象的memory真如上圖一樣,那麽0x0開始的地方根本就不存在bootloader的映象,從0x0處拷貝bootloader到__boot_start開始的SDRAM空間也就無從談起了啊?
我的疑問還是在于:
(1)第一條指令應該是從0x0開始,但是從boot.lds來看卻并不是這樣,是不是我對linker script的認識不對呢?
(2)按照boot.lds來看,最終映象的memory layout是不是應該和上圖一致呢?是上圖有錯誤,還是boot.lds有問題?
謝謝!
aaronwong
可愛的小學生
可愛的小學生
 
文章: 4
註冊時間: 週六 6月 23, 2007 11:01 pm
來自: Shanghai

文章yasachi » 週四 8月 09, 2007 2:27 pm

其實您上面寫了好多東西, 可是偶只看得懂您的二個疑問, 剛好上個星期在k那個bootloader,所以您這個問題偶可能大蓋可以告訴您為什麼~~~~

因為他是把flash的bootloader copy到sdram去執行, 這樣如果您有改什麼東西才不會直接改到flash 另外如果您想要偷偷的把bootloader蓋掉,也可以偷偷的蓋掉。為什麼要偷偷的蓋掉呢?因為您不會希望您程式跑到一半的時候他跟您說找不到下一個指令吧, 所以他要先copy一份到sdram再從sdram執行, 然後再去對flash做手腳。這樣就不會因為您在flash中執行程式, 結果卻因為您下了一個flash errase後就找不到下一個指令了。
yasachi
可愛的小學生
可愛的小學生
 
文章: 15
註冊時間: 週一 5月 10, 2004 12:03 pm

文章訪客 » 週五 8月 10, 2007 2:00 pm

to aaronwong:

每個平台,都有不同的開機作法,一般要去參照硬體的規格書才能夠了解其方式。
以我自己遇過的平台,大都是在0x0的位置,配置了一個hard code,這個hard code就是一個jump指令,
jump到flash在memory map的開始位置,去執行flash中的程式。

而flash一般會使用NOR flash,做為儲存裝置,但nor flash一般都不能直接執行程式,僅有最開頭的小小8k/16k的sector是可以執行
(這就要參考每份flash的規格書才能知道到底有多少sector可執行),
所以bootloader一般都會在最開始初始化cpu / ram 後,將自身某些部份copy到 ram中,再執行後續的動作。
而初始化cpu/ram及copy至ram,就是在那flash 最開頭的小小sector中執行的。

所以,你可能要去參考硬體規格書才能比較了解該平台的運作方式。
訪客
 


回到 embedded system

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 1 位訪客