Chinaunix首页 | 论坛 | 博客
  • 博客访问: 445232
  • 博文数量: 78
  • 博客积分: 2030
  • 博客等级: 大尉
  • 技术积分: 1002
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-28 15:25
文章分类

全部博文(78)

文章存档

2012年(1)

2011年(1)

2010年(4)

2009年(12)

2008年(60)

我的朋友

分类: LINUX

2008-11-30 21:04:55

       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 : { *(.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异常向量的入口。

0x80000000ar9132平台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-bootrelocate到内存的最高端。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_ramrelocate后的内存高端)

注意到在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指针的作用。

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