close

u-boot的強大就在於它具有代碼relocate功能,運行時代碼在ram中跑,最明顯的一個好處就是u-boot可以自己替換自己固化在flash中的代碼。
        先看一下這套代碼中和relocate有關的幾個大名鼎鼎的參數:

board/ar7100/ap83/config.mk

# ROM version              

TEXT_BASE = 0xbf000000

# SDRAM version

#TEXT_BASE = 0x8020000

include/configs/ap83.h

#define CFG_MONITOR_BASE    TEXT_BASE

board/ar7100/ap83/u-boot.lds

OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")

OUTPUT_ARCH(mips)

ENTRY(_start)

SECTIONS

{

    . = 0x00000000;

 

    . = ALIGN(4);

    .text       :

    {

      *(.text)

    }

 

    . = ALIGN(4);

    .rodata  : { *(.rodata) }

 

    . = ALIGN(4);

    .data  : { *(.data) }

 

    . = ALIGN(4);

    .sdata  : { *(.sdata) }

 

    _gp = ALIGN(16);

 

    __got_start = .;

    .got  : { *(.got) }

    __got_end = .;

 

    .sdata  : { *(.sdata) }

 

    __u_boot_cmd_start = .;

    .u_boot_cmd : { *(.u_boot_cmd) }

    __u_boot_cmd_end = .;

 

    uboot_end_data = .;

    num_got_entries = (__got_end - __got_start) >> 2;

 

    . = ALIGN(4);

    .sbss  : { *(.sbss) }

    .bss  : { *(.bss) }

    uboot_end = .;

}

注釋:

0xbf000000 是mips 24kc Flash起始的位置,也是reset

0x80000000是ar9132平台DDR的起始位置。

鏈接腳本中的0x00000000會被這個TEXT_BASE替代,可以觀察編譯時候的輸出,你會發現有一個-DTEXT_BASE=0xbf000000的選項。

 

Relocate的代碼在start.S中。

啟動的大致順序如下,假設代碼固化於flash起始位置。

       CPU 上電

       Reset(初始化cp0寄存器)          

       設置GOT

       lowlevel_init(初始化SDRAM)

       初始化cache

       Relocate代碼

 

下面是代碼的入口

       la  t9, board_init_f

          j   t9

          nop

這個board_init_f定義在lib_mips/board.c中。

這個程序為下列元素分配合適的內存空間:

[1] u-boot代碼(.text .data .bss)

[2] malloc空間 (相當於heap)

[3] Board Info

[4] Global Data

[5] Stack

這里可以看出malloc的空間位於heap中,即內存的高端,而函數中的局部變量,都在stack中的,在內存低端。

                                         

void board_init_f(ulong bootflag)

{

       gd_t gd_data, *id;

       bd_t *bd;

       init_fnc_t **init_fnc_ptr;

       ulong addr, addr_sp, len = (ulong)&uboot_end - CFG_MONITOR_BASE;

       ulong *s;

 

       /* Pointer is writable since we allocated a register for it.

        */

       gd = &gd_data;

       /* compiler optimization barrier needed for GCC >= 3.4 */

       __asm__ __volatile__("": : :"memory");

 

       memset ((void *)gd, 0, sizeof (gd_t));

 

       for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

              if ((*init_fnc_ptr)() != 0) {

                     hang ();

              }

       }

 

       /*

        * Now that we have DRAM mapped and working, we can

        * relocate the code and continue running from DRAM.

        */

       addr = CFG_SDRAM_BASE + gd->ram_size;

 

       /* We can reserve some RAM "on top" here.

             */                         

 

       /* round down to next 4 kB limit.

        */

       addr &= ~(4096 - 1);

       debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);

 

       /* Reserve memory for U-Boot code, data & bss

        * round down to next 16 kB limit

        */

       addr -= len;

       addr &= ~(16 * 1024 - 1);

 

       debug ("Reserving %ldk for U-Boot at: %08lx\n", len >> 10, addr);

 

        /* Reserve memory for malloc() arena.

        */

       addr_sp = addr - TOTAL_MALLOC_LEN;

       debug ("Reserving %dk for malloc() at: %08lx\n",

                     TOTAL_MALLOC_LEN >> 10, addr_sp);

 

       /*

        * (permanently) allocate a Board Info struct

        * and a permanent copy of the "global" data

        */

       addr_sp -= sizeof(bd_t);

       bd = (bd_t *)addr_sp;

       gd->bd = bd;

       debug ("Reserving %d Bytes for Board Info at: %08lx\n",

                     sizeof(bd_t), addr_sp);

 

       addr_sp -= sizeof(gd_t);

       id = (gd_t *)addr_sp;

       debug ("Reserving %d Bytes for Global Data at: %08lx\n",

                     sizeof (gd_t), addr_sp);

 

      /* Reserve memory for boot params.

        */

       addr_sp -= CFG_BOOTPARAMS_LEN;

       bd->bi_boot_params = addr_sp;

       debug ("Reserving %dk for boot params() at: %08lx\n",

                     CFG_BOOTPARAMS_LEN >> 10, addr_sp);

 

       /*

        * Finally, we set up a new (bigger) stack.

        *

        * Leave some safety gap for SP, force alignment on 16 byte boundary

        * Clear initial stack frame

        */

       addr_sp -= 16;

       addr_sp &= ~0xF;

       s = (ulong *)addr_sp;

       *s-- = 0;

       *s-- = 0;

       addr_sp = (ulong)s;

       debug ("Stack Pointer at: %08lx\n", addr_sp);

 

      

 

       memcpy (id, (void *)gd, sizeof (gd_t));

 

       /* On the purple board we copy the code in a special way

        * in order to solve flash problems

        */

#ifdef CONFIG_PURPLE

       copy_code(addr);

#endif

 

       relocate_code (addr_sp, id, addr);

 

       /* NOTREACHED - relocate_code() does not return */

}

 

從代碼中可以看出,U-boot被relocate到內存的最高端。Relocate的實際部分在start.S中,通過relocate_code (addr_sp, id, addr)進入匯編,mips體系中函數參數被保存在a0,a1,a2中,所以看start.S中的注釋有:

/*

 * void relocate_code (addr_sp, gd, addr_moni)

 *                                       

 * This "function" does not return, instead it continues in RAM

 * after relocating the monitor code.

 *

 * a0 = addr_sp

 * a1 = gd

 * a2 = destination address

 */

Relocate的核心代碼如下,分析一下能體會到mips匯編的delay branch

relocate_code:

    move    sp, a0      /* Set new stack pointer        */

 

    li  t0, CFG_MONITOR_BASE

    la  t3, in_ram       

    lw  t2, -12(t3) /* t2 <-- uboot_end_data    */

move    t1, a2       

 

/*

     * t0 = source address

     * t1 = target address

     * t2 = source end address

     */

    /* On the purple board we copy the code earlier in a special way

     * in order to solve flash problems

     */

1:

    lw  t3, 0(t0)

    sw  t3, 0(t1)

    addu    t0, 4

    ble t0, t2, 1b

    addu    t1, 4           /* delay slot           */

 

    /* If caches were enabled, we would have to flush them here.

     */

    /* Jump to where we've relocated ourselves.

     */

    addi    t0, a2, in_ram - _start

    j   t0

    nop

上面計算u-boot end地址lw  t2, -12(t3)是因為有下面的定義,

    .word   uboot_end_data

    .word   uboot_end

    .word   num_got_entries

in_ram:                  

一個word四個字節,所以是in_ram的位置-12個字節。拷貝代碼的時候,增加target指針位置的代碼放在跳轉代碼之后,就是由於mips的流水線。等拷貝完代碼之后,就跳轉到ram中執行了。也就是in_ram的地方(此時的in_ram在relocate后的內存高端)。

注意到在u-boot的連接腳本里面專門有一個.u_boot_cmd段,專門設置這樣一個段有什麼好處呢?可以看一下find_cmd這個函數,就可以理解了,通過把所有cmd結構指針放在一個統一的段里面在查找起來非常方便,要添加新的命令,也不用改變原來的結構。看看它是怎麼定義的吧:

原理:
每個命令都有一個命令結構體
struct cmd_tbl_s {
char*name;  /* Command Name*/
intmaxargs; /* maximum number of arguments*/
intrepeatable; /* autorepeat allowed?*/
int       (*cmd)(struct cmd_tbl_s *, int, int, char *[]);   /* Implementation function*/
char*usage;/* Usage message(short)*/
char*help;/* Help  message(long)*/
};
去定義它。Cmd為要調用的命令函數!name為該命令名字符串。

在u-boot里面有這樣的宏
#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

宏U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)就是將
cmd_tbl_s{
name,
maxargs,
rep,
cmd,
usage,
help
}這樣的一個命令結構體放入內存.u_boot_cmd這個區域,.u_boot_cmd這個域在board/smdk2410/u-boot.lds中定義!在U-boot中的shell中,根據用戶輸入的命令,就會在.u_boot_cmd這個內存區域中查找,當.u_boot_cmd中某一個cmd_tbl_s命令結構體的cmd_tbl_s.name和輸入的命令字符串相符時,就調用該命令
結構體的cmd_tbl_s.cmd( ….)函數!

這里有一個要注意的是,cmd是一個函數指針,由於u-boot代碼是要relocate的,所以在代碼relocate之后,每個這樣的指針也要加上相應的偏移才能正常動作,代碼在board_init_r函數中。

 

 

最后是板子上電啟動時的輸出信息,看了很有幫助。

 

U-Boot 1.1.4-RAM VSC7395@MAC1 (Mar 21 2008 - 15:57:42)

 

AP83 (ar9100 with SPI flash)

DRAM:  16 MB

Top of RAM usable for U-Boot at: 81000000

Reserving 263k for U-Boot at: 80fbc000

Reserving 192k for malloc() at: 80f8c000

Reserving 56 Bytes for Board Info at: 80f8bfc8

Reserving 36 Bytes for Global Data at: 80f8bfa4

Reserving 128k for boot params() at: 80f6bfa4

Stack Pointer at: 80f6bf88

Now running in RAM - U-Boot at: 80fbc000

        Found MXIC Flash. ID c22018

Flash: 16 MB

 

Relocate代碼中還包含PIC GOT的東西,學懂了也要分析一下。

從代碼調試中的一個小地方可以看出GOT的作用,你只要把代碼relocate前后的&__u_boot_cmd_start的值打印出來,你會發現它們是不一樣的,這就是我們在start.S中修改GOT指針的作用。

本文来自: (www.91linux.com) 详细出处参考:http://www.91linux.com/html/article/qianrushiyingyong/20081201/14171.html

大頭 / Xuite日誌 / 回應(0) / 引用(0)
沒有上一則|日誌首頁|沒有下一則