Chinaunix首页 | 论坛 | 博客
  • 博客访问: 127434
  • 博文数量: 33
  • 博客积分: 948
  • 博客等级: 准尉
  • 技术积分: 380
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-19 20:47
文章分类

全部博文(33)

文章存档

2012年(2)

2011年(30)

2010年(1)

分类:

2011-10-22 14:29:39

U-Boot:Startup Code - Relocation

發表於 February 8, 2007 10:22 PM

 延續前一則日記的介紹,我們繼續以 s3c2410 的平臺為例。U-Boot 的 startup code(hardware bring-up code)for s3c2410 位於 cpu/arm920t/start.S,此部份的研究重心如下:

  • Monitor relocation.
  • Stack setup.
  • BSS clearing.
  • Jump to high-level language.

基本概念分述如後。不過,在開始前,必須具備幾個基本背景知識:

  • 您必須先學會 ARM assembly 後再來閱讀此部份。
  • 必須知道什麼叫「symbol(符號)」以及「memory address」。
  • 能區分 symbol 與 variable 的差異。
  • 一定要能看得懂 symbol table,以 U-Boot 為例,在編譯好 U-Boot 後便會產生檔名為 System.map 的 symbol table。

1. Monitor relocation.

一開始 U-Boot 是在 SMDK2410 的 nor flash 執行,所以 U-Boot 心須把自己由 nor flash 搬到 RAM,才能執行接下來的工作,這個動作就稱為 relocation。相關的程式片斷如下:

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:                               /* relocate U-Boot to RAM           */
        adr     r0, _start              /* r0 <- current position of code   */
        ldr     r1, _TEXT_BASE          /* test if we run from flash or RAM */
        cmp     r0, r1                  /* don't reloc during debug         */
        beq     stack_setup

        ldr     r2, _armboot_start
        ldr     r3, _bss_start
        sub     r2, r3, r2              /* r2 <- size of armboot            */
        add     r2, r0, r2              /* r2 <- source end address         */

copy_loop:
        ldmia   r0!, {r3-r10}           /* copy from source address [r0]    */
        stmia   r1!, {r3-r10}           /* copy to   target address [r1]    */
        cmp     r0, r2                  /* until source end addreee [r2]    */
        ble     copy_loop
#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */

程式裡有相當詳細的註解。首先,U-Boot 先把 symbol _start 載到 register r0,再把 symbol _TEXT_BASE 載到 register r1,然後比較 r0 是否等於 r1。如果 r0 等於 r1,表示 U-Boot 目前是在 RAM 裡頭,所以不必做 relocation。

symbol 代表一個記憶體位址(memory address),所以要找出 _start symbol 的 memory address,方式是由 board 的 linker script 來看,所以把 board/smdk2410/u-boot.lds 叫出來瞧瞧:

...
ENTRY(_start)
SECTIONS
{
        . = 0x00000000;

        . = ALIGN(4);
        .text      :
        {
          cpu/arm920t/start.o   (.text)
          *(.text)
        }
        ...
}

看懂 linker script 是您的功課,不過這個部份其實很直覺。程式的進入點(ENTRY command)定義為 _start symbol,而程式一開始的 value to current address(看到沒,就是 SECTIONS 後的那個小點點!)為 0x00000000,所以 _start symbol 代表的是 memory address 0x0請不要用 _start 等於 0x0 的方式來解說,因為 _start 壓根兒就是一個 symbol 並不是 variable。

Linker script 的 "." 稱為 location counter,這是一個指定運算子,也就是「assign value to symbol」的意思。因此,_start symbol 為 address 0x0,且 value to _start symbol 為 0x00000000。

所以,總結來看 "adr     r0, _start" 把 symbol _start 的 memory address 放到 r0,adr 是 ARM 的 pseudo-instruction;"ldr     r1, _TEXT_BASE" 把 symbol _TEXT_BASE 的值放到 r1,ldr 是 ARM 的 memory addressing 指令,這裡用到的 addressing mode 是 direct addressing。

回頭找一下 symbol _TEXT_BASE_TEXT_BASE 可就不在 linker script 裡頭了。把 start.S 程式移到開頭,就可以找到 _TEXT_BASE

_TEXT_BASE:
        .word   TEXT_BASE

這是一個 symbol 的定義與 GNU assembly 的 variable 宣告語法,所以 symbol _TEXT_BASE 所代表的 memory address  之處,放了一個值(value),其值為 TEXT_BASETEXT_BASE 便是一個變數,此變數是 linking 階段(GNU ld)所定義的,以 U-Boot for SMDK2410 為例,便是 0x33F80000(board/smdk2410/config.mk):

TEXT_BASE = 0x33F80000

接下來的程式是:

        ldr     r2, _armboot_start
        ldr     r3, _bss_start
        sub     r2, r3, r2              /* r2 <- size of armboot            */
        add     r2, r0, r2              /* r2 <- source end address         */

這裡做的是「計算程式長度」的動作。把 _armboot_start 放到 r2、_bss_start 放到 r3,然後 r2 = r3 - r2 算出要 relocation 的長度,此時 r2 放的便是 U-Boot 後面「要 relocate 到 RAM 的程長度」。下一行做 r2 = r0 + r2,很清楚,再把程式尾段的 memory address 算出來,所以 r2 最後放的是「source end address」。

這個時候就要把 symbol table 請出來看了

先在 start.S找到 _armboot_start

.globl _armboot_start
_armboot_start:
        .word _start

對照 System.map

33f80000 t $a
33f80000 T _start
33f80020 t $d
...

不過,_bss_start 可就不是對照 System.map 就能解決的了。概念上,_bss_start 是 linker script 所定義的 symbol,可用來表示程式「實體程式碼」的 end address;概念上來說雖然簡單,不過仍強烈建議了解 ELF 的格式與 .bss section 的整體觀念,畢道這是基本功,不可不練。

可在 U-Boot 程式碼裡頭找到這行宣告:

extern ulong _bss_start; /* code + data end == BSS start */

剩下來的部份就容易了,只要以上這些觀念都能確實掌握,startup code 並沒有什麼困難的地方。

延伸閱讀

--jollen

阅读(1076) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~