U-Boot:Startup Code - Relocation

来源:岁月联盟 编辑:zhuzhu 时间:2008-10-23
U-Boot:Startup Code - Relocation内容简介:U-Boot:Startup Code - Relocation发表于 February 8, 2007 10:22 PM 延续前一则日记的介绍,我们继续以 s3c2410 的平台为例。U-Boot 的 startup code(hardware bring-up code)for s3c2410 位于 cpu/arm920t/s 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
程式裡有相当详细的注解。首先,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
这裡做的是「计算程式长度」的动作。把 _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