u-boot2013.01 smdk2410 启动第一阶段分析

时间:2021-03-22 16:32:03
u-boot2013.01 smdk2410  -->2440 启动分析
1.u-boot启动第一阶段
 start.S (arch\arm\cpu\arm920t)    
_start:    b    start_code 
    1.1 set the cpu to SVC32 mode
  
     mrs    r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0

    1.2 关闭看门狗
    
    #  define pWTCON    0x53000000
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]


    1.3 屏蔽中断 mask all IRQs by setting all bits in the INTMR - default
    
    #  define INTMSK    0x4A000008    /* Interrupt-Controller base addresses */
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
            //2410 部分 2440 没有
  
     # if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
   # endif

    
        1.4 设置时钟     ===========时钟设置有问题=================================================================
     
   /* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
    1.5cpu 底层初始化
 
   #ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit //在初始化内存之前没有进行时钟的设置
#endif
cpu_init_crit:
a.flush v4 I/D caches
b.disable MMU stuff and caches
c.bl lowlevel_init //底层的初始化
       
    1.6 跳转到     bl    _main
    
    bl    _main
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) //0x30000f80 看确定sp的值分析一节
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
==>        bic    sp, sp, #清低8位。
确定GD_SIZE的大小
    反汇编文件: 770:    e24dd080     sub    sp, sp, #128    ; 0x80    
        ==>GD_SIZE  = 128   = 0X80
        ===>sp = 0x30000f80 - 0x80 = 30000f00
     
       
mov r8, sp /* GD is above SP */
mov r0, #0
        ==> sp 的值为0x30000f00。这里的mov r8,sp 可以通过r8寄存器,来访问目前sp(0x30000f00) 这个地址空间
        mov r0,#0  这里的r0 是给 bl    board_init_f函数传递参数
        
        解释r8:
        DECLARE_GLOBAL_DATA_PTR;  Board.c \arch\arm\lib)
        #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")  Global_data.h(\arch\arm\include\asm)
        r8 是一个register 变量。在编译的时候,会通过  添加 编译选项 -ffix= r8 。表示r8 被占用。
        
        总结:在调用C语言之前,设置了栈指针sp 的地址。
        系统在初始化内存sdram之前,没有配置时钟。存在不合理的地方,移植2440的时候,需要进行改进
====================================================================================
2.u-boot
2.1 void board_init_f(ulong bootflag) 函数分析

        2.1.1
 
    gd->mon_len = _bss_end_ofs;    
_bss_end_ofs:的定义
.globl _bss_end_ofs
_bss_end_ofs:
.word __bss_end__ - _start
        __bss_end__:在u-boot.lds 中进行的定义
        从而可以得到 _bss_end_ofs 表示的是整个代码的大小
        2.1.2
        #elif defined CONFIG_OF_SEPARATE
        /* FDT is at end of image */
        gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
        #endif
        此处:CONFIG_OF_SEPARATE 并没有定义。
            这一行代码是做什么用的?
            const void    *fdt_blob;    /* Our device tree, NULL if none */
        这里是选择u-boot 是否支持设备树的选项
        这里也是关于设备树的
        /* Allow the early environment to override the fdt address */
        gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
                        (uintptr_t)gd->fdt_blob);
        2.1.3  函数数组的执行
        
  
     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}


        2.1.3.1 init_sequence
             
       arch_cpu_init,        /* basic arch cpu dependent setup */
mark_bootstage,
board_early_init_f,
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
print_cpuinfo, /* display cpu info (and speed) */
dram_init, /* configure available RAM banks */
NULL, //表示结束

        1):    arch_cpu_init,        /* basic arch cpu dependent setup
                  
     int arch_cpu_init(void)
__attribute__((weak, alias("__arch_cpu_init")));
int __arch_cpu_init(void)
{
return 0;
}

     2): board_early_init_f(void) //设置时钟
     3):timer_init,        /* initialize timer */ 设置定时器
     4):dram_init,        /* configure available RAM banks */ 设置内存 内存的大小
    
     2.1.4
    
               
      memset((void *)gd, 0, sizeof(gd_t));//初始化0x30000f00 到0x30000f80之前的内存单元。
#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1

gd->ram_size = PHYS_SDRAM_1_SIZE;

                                                                                                                     //引发一个问题:此时的gd为什么能够对结构体成员进行赋值呢?
                                                                                                                         //通过前后的分析。可以知道在第一阶段的末尾,设置的sp指针的地址。
                                                                                                                         // 0x30000f00 从这个地址增大128个字节的地方是输入GD 的。
                                                                                                                         //通过语句mov r8,sp ,能够推导出什么呢?ram_size的数据,是存储在
                                                                                                                         //0x30000f00 到0x30000f80之间的
                                                                                                                         //board_init_f 分析到最后,有    memcpy(id, (void *)gd, sizeof(gd_t));
                                                                                                                         //memcpy 是内存拷贝函数。表达的意思是将之前的gd的位置0x30000f00拷贝到高端 addr_sp  addr_sp -  sizeof (bd_t)  -  sizeof (gd_t)
                                                                                                                         //位置处。(此处的理解,需要结合后边的addr_sp的设定)
                 #define PHYS_SDRAM_1_SIZE    0x04000000 /* 64 MB */
        
         addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  

    D==> addr = 0x34000000  即SDRAM地址最高端
        
    
    /* reserve TLB table */
gd->tlb_size = 4096 * 4;
addr -= gd->tlb_size;

    ==>为页表保留
    D==>addr = 0x34000000 - 0x4000 = 0x33ffc000
            addr = 0x34000000 - TLB
            
            /* round down to next 64 kB limit */
        addr &= ~(0x10000 - 1);
    ==> address = addr & (0x10000-1)
                                addr & 0xffff
                                0x33ffc000 & 0xffff
                         ==>0x33ffc000
    D==>    addr = 0x33ffc000

        /* round down to next 4 kB limit */
        addr &= ~(4096 - 1);
    ==> addr = addr & 0xfff
                        =0x33ffc000 & 0xfff
    D==>addr = 0x33ffc000
      /*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
addr -= gd->mon_len;
addr &= ~(4096 - 1);
    ==>addr = addr -  _bss_end_ofs;    
        此时并不清楚_bss_end_ofs 多大    ====> 通过反汇编查找 _bss_end_ofs 可以得到 000bbfd8   == >751K
        
        假设_bss_end_ofs 为0x3000,为u-boot的code data bss 段保留这片空间。
        则
D==>addr = 0x33ff0000
    addr = 0x34000000 - TLB  -  _bss_end_ofs  = 33ff0000 - 0x000bbfd8
    ==》 33F34048
        addr &= ~(4096 - 1);
        ==> addr  = 0x33f34000
        /*
    * reserve memory for malloc() arena 保留malloc 空间
*/
addr_sp = addr - TOTAL_MALLOC_LEN;

#define TOTAL_MALLOC_LEN (CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE)
    ==>TOTAL_MALLOC_LEN =  0x410000 (详见TOTAL_MALLOC_LE 长度分析一节)
        
D==>addr_sp = 0X33BE0000     

    /*
* (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;
   
D==>addr_sp  =  addr_sp -  sizeof (bd_t)

  
  addr_sp -= sizeof (bd_t); //为board Info  保留一块空间
  
  bd = (bd_t *) addr_sp;    //堆addr_sp进行强制类型的转换。并复制给bd (bd 里边包含了bi_arch_number  见bd gd 结构体分析)    gd->bd = bd; //将bd 赋值给gd的成员bd。这样就可以通过gd这个全局 的寄存器变量来找到boadr info 信
      
  addr_sp -= sizeof (gd_t); //为gd_t 保留一块空间 为后续的将低端的GD数据拷贝到高端D==>addr_sp  addr_sp -  sizeof (bd_t)  -  sizeof (gd_t) 地址做准备



    id = (gd_t *) addr_sp;
    
D==>addr_sp   = addr_sp -  sizeof (bd_t)  -  sizeof (gd_t)

    //此段数据并没有起作用,但是还是有必要分析一些。    
    //这是一些关于设备树的一些操作。
    //主要是设备树这块数据的重定向。此处保留重定向的地址空间
  
  #if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)
/*
* If the device tree is sitting immediate above our image then we
* must relocate it. If it is embedded in the data section, then it
* will be relocated with other data.
*/
if (gd->fdt_blob) {
fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

addr_sp -= fdt_size;
new_fdt = (void *)addr_sp;
debug("Reserving %zu Bytes for FDT at: %08lx\n",
fdt_size, addr_sp);
}
#endif
        /* setup stackpointer for exeptions */
    gd->irq_sp = addr_sp; //将IRQ 的堆栈指针设置为addr_sp ( D==>addr_sp  = addr_sp -  sizeof (bd_t)  -  sizeof (gd_t) )
    
    
    /* leave 3 words for abort-stack    */
    addr_sp -= 12;  //保留12字节的 abort-stack  
    /* 8-byte alignment for ABI compliance */
    addr_sp &= ~0x07;     //清低8位
 D==>addr_sp =  addr_sp -  sizeof (bd_t)  -  sizeof (gd_t) - 12
 
 ==>addr_sp 为addr - 堆空间 -  addr_sp -  sizeof (bd_t)  -  sizeof (gd_t) - 12   
 
 ============内存空间分配结束=============================
     //设置波特率
     gd->bd->bi_baudrate = gd->baudrate;      init_baudrate   进行的波特率设置
      //设置内存的起始地址和大小
          dram_init_banksize();     
             
        
      #define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1

void __dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; //0x30000000
gd->bd->bi_dram[0].size = gd->ram_size; // 在board_init_f 进行的设置 大小为0x04000000 64M
}
void dram_init_banksize(void)
__attribute__((weak, alias("__dram_init_banksize")));

gd->relocaddr = addr; /* Start address of U-Boot in RAM */ //U-boot 在RAM的起始地址
gd->start_addr_sp = addr_sp; /* start_addr_stackpointer */ //栈指针的起始地址
gd->reloc_off = addr - _TEXT_BASE; //重定位的偏移量 即搬移后u-boot的首地址


        
         _TEXT_BASE 的值为0               
         addr的地址
         假设_bss_end_ofs 为0x3000,为u-boot的code data bss 段保留这片空间。
        D==>addr = 0x33ff0000             
        

            memcpy(id, (void *)gd, sizeof(gd_t)); //将低端的gd所在的数据,拷贝到高端id处   


            
        ---------------------------------            最顶端 0x34000000
    |                        TLB table                         |
    ----------------------------------|    0x34000000 - 0x4000 = 0x33ffc000                                                                     
    |        U-boot 的 code data bss             |     
    ----------------------------------|   addr = 0x34000000 - TLB  -  _bss_end_ofs  =   0x33f34000   
    | malloc 空间 (0x410000)                    |
    ----------------------------------|     addr_sp = addr - TOTAL_MALLOC_LEN;
    |        Board Info struct         bd_t            |
    ----------------------------------   addr_sp  =  addr_sp -  sizeof (bd_t)
    |    全局变量    gd_t                              |
    ----------------------------------|  (irq_sp)addr_sp  =  addr_sp -  sizeof (bd_t)  -sizeof(gd_t)
    |abort-stack  (12字节)                         |    
    ----------------------------------|        addr_sp  =  addr_sp -  sizeof (bd_t)  -sizeof(gd_t) - 12
    
2.2  准备 relocate_code   参考文献    http://blog.csdn.net/skyflying2012/article/details/25804209
 /*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_sp, gd, addr_moni). Trick here is that
 * we'll return 'here' but relocated.
 */
 
 首先看一下定义的宏  Generic-asm-offsets.h (\include\generated)     这些宏其实是一些偏移量的大小  http://www.cnblogs.com/woainilsr/p/3472409.html
                     
        #define GENERATED_GBL_DATA_SIZE (128) /* (sizeof(struct global_data) + 15) & ~15 */
#define GENERATED_BD_INFO_SIZE (32) /* (sizeof(struct bd_info) + 15) & ~15 */
#define GD_SIZE (128) /* sizeof(struct global_data) */
#define GD_BD (0) /* offsetof(struct global_data, bd) */
#define GD_RELOCADDR (52) /* offsetof(struct global_data, relocaddr) */
#define GD_RELOC_OFF (72) /* offsetof(struct global_data, reloc_off) */
#define GD_START_ADDR_SP (68) /* offsetof(struct global_data, start_addr_sp) */
        ldr    sp, [r8, #GD_START_ADDR_SP]    /* r8 = gd->start_addr_sp */        
        //设置sp指针的位置。设置为多少呢?取出r8寄存器的地址,同时加上 GD_START_ADDR_SP (68) 地址单元的值,就是sp指针
  
     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
ldr r8, [r8, #GD_BD] /* r8 = gd->bd */
sub r8, r8, #GD_SIZE /* new GD is below bd */ 此时r8指向的空间为bd的首地址

adr lr, here //在重定位完成后,返回地址
ldr r0, [r8, #GD_RELOC_OFF] /* lr = gd->start_addr_sp */ [r8, #GD_RELOC_OFF] 得到重定位的偏移量
add lr, lr, r0 //在here的基础上加上重定位的偏移量
ldr r0, [r8, #GD_START_ADDR_SP] /* r0 = gd->start_addr_sp */ //void relocate_code (addr_sp, gd, addr_moni) 重定位代码的第一个参数
mov r1, r8 /* r1 = gd */ //第二个参数
ldr r2, [r8, #GD_RELOCADDR] /* r2 = gd->relocaddr */ //第三个参数,即重定位的位置
        跳转到重定位relocate_code 代码去    

2.3 重定位代码 relocate_code
第一个参数:addr_sp   空间中去掉abort-stack后的地址位置。也就是栈指针的首地址。栈是往下进行增长的
第二个参数    gd_t             全局变量参数的首地址,保存了数据信息
第三个参数:addr_moni   重定位的地址
  
     mov    r4, r0    /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
     adr    r0, _start   //伪指令代码adl 的分析 见https://www.douban.com/note/331036776/    
                                         //把 _start地址读出来,而且这个地址是相对当前pc的  
     cmp    r0, r6  比较 _start 的地址和定位的目标地址是否相等,
     如果相等,则跳出。即代码已经在目标地址。不需要进行数据的搬移
     moveq    r9, #0        /* no relocation. relocation offset(r9) = 0 */
    beq    relocate_done        /* skip relocation */
    如果不相等。即需要进行代码的搬移操作。搬移到目标地址,高端的物理内存空间
    mov    r1, r6            /* r1 <- scratch for copy_loop */    r1 表示代码搬移的目的地址
  ldr    r3, _bss_start_ofs                                                                r3 表示 bss 段的开始。也就是说仅仅包含了代码段和数据段 连接脚本中有相应的定义  . = 0x00000000; 预示着 _bss_start_ofs 表示代码段和数据段的长度。不包括bss段。
    add    r2, r0, r3        /* r2 <- source end address        */   r2 = r0 +r3 = 代码的起始地址+ _bss_start_ofs =  搬移地址的末地址。
  
 
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */ 从r0单元中读出8个字节的数据存在r9 r10 中,同时r0 自动加8
stmia r1!, {r9-r10} /* copy to target address [r1] */ 将刚才读出的数据放入r1单元的8个
cmp r0, r2 /* until source end address [r2] */ 比较数据源地址和 目的地址的尾地址是否相同
blo copy_loop //小于则跳转 也就是数据搬移还没有结束
    =================从NOR FLASH 拷贝到SDRAM 完成 ===========================
    程序的链接地址是0 。访问全局变量,静态变量和调用函数时。是基于0 地址编译而得到的地址
    现在把程序赋值到SDRAM中,此时处于修改代码
    把原来的是基于0 地址编译而得到的地址 。改为新地址
    本来访问nor flash 中的变量。可以直接通过 0x100 访问。现在变量在sdram中,那么就需要使用新的地址来访问
    ========================================================================
    重定位-->修改代码的地址  
    有些变量
    /*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */ 读内存指令
//r0 = 0 //代码段的基地址

sub r9, r6, r0 /* r9 <- relocation offset */
//r9 = r6 -r0 = 代码搬移的目标地址 - 代码段的基地址 = 重定位的偏移量
//r9 = 0x33f34000 - 0 = 0x33f34000

ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
//r10 = 符号表的首地址,这个地址是连接脚本中相对于链接脚本中的地址量。
//r10 = 0x0007cb24 (反汇编得到)

add r10, r10, r0 /* r10 <- sym table in FLASH */
//r10 = r10 +r0 = 代码段的基地址 + 符号表的地址 = 符号表在flash 中的地址
//r10 = 0x0007cb24 + 0 = 0007cb24

ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
//r2 = rel_dyn的首地址。 这个地址是连接脚本中相对于链接脚本中的地址量。
//r2 = 0x00073b9c

add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
//r2 = r2 +r0 = 在flash中rel_dyn的地址
//r2 = 0x00073b9c

ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
//在flash中 rel_dyn_end d地址
// r3 = 0007cb24

fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
//将r2单元的数据读到r0 。即rel_dyn在flash的地址
//第一次循环:r0 = [r2] = [0x00073b9c] = 0x00000020

add r0, r0, r9 /* r0 <- location to fix up in RAM */
// r0 = r0+r9 = 代码段的基地址 + 重定位的偏移量 = 在RAM中的地址
//第一次循环: r0= r0 + r9 = 0x00000020 + 0x33f34000 = 0x33f34020

ldr r1, [r2, #4]
//r1 = *(r2 +4) = 取出rel_dyn + 4 单元的数据到r1中
//第一次循环: r1+= [r1 +4 ] = [0x00073b9c +4 ] = [0x00073ba0] = 00000017

and r7, r1, #0xff
//第一次循环: r7 = r1 & 0xff = 00000017

cmp r7, #23 /* relative fixup? */
//第一次循环: 比较r7是否等于23 ==>等于

beq fixrel
//第一次循环:跳转到fixrel

cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
//第一此循环:r1 = [r0] = [0x000020 ] = 000001a0 //此处的r0 为什么是0x000020 而不是 0x33f34020
//此处实际的[r0] 应当是0x33f34020.实际中 0x000020 和0x33f34020单元里边的内容值是一样的。都是取出来。然后进行修改里边的代码。
add r1, r1, r9
// 第一此循环: r1 = r1 + r9 = 0x000001a0 + 0x33f34000 = 0x33F341A0

fixnext:
str r1, [r0]
//第一此循环: [0x33f34020] = 0x33F341A0

add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
//第一此循环: r2 = r2 +8 = 0x00073b9c + 8 = 0x00073ba4

cmp r2, r3
// 第一此循环: 0x0x00073ba4 != 0x0007cb24
blo fixloop
// 第一此循环: 小于继续跳转 到fixloop



//此处还有待于完善
======  相对动态段的反汇编代码
Disassembly of section .rel.dyn:
00073b9c <__image_copy_end>:
73b9c: 00000020 andeq r0, r0, r0, lsr #32 //第一次循环
73ba0: 00000017 andeq r0, r0, r7, lsl r0 // 17 表示的是一个标号。
73ba4: 00000024 andeq r0, r0, r4, lsr #32 //第二次循环
73ba8: 00000017 andeq r0, r0, r7, lsl r0
73bac: 00000028 andeq r0, r0, r8, lsr #32
73bb0: 00000017 andeq r0, r0, r7, lsl r0
73bb4: 0000002c andeq r0, r0, ip, lsr #32
  
   ===============
       mov    pc, lr
       将lr的值给pc  
      程序跳转到here
       
here:
/* Set up final (full) environment */

bl c_runtime_cpu_setup /* we still call old routine here */

ldr r0, =__bss_start /* this is auto-relocated! */
ldr r1, =__bss_end__ /* this is auto-relocated! */

mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l


//清楚bss段


为调用 boadr_init_r 做准备

    /* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r8 /* gd_t */
ldr r1, [r8, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
ldr pc, =board_init_r /* this is auto-relocated! */
   
    汇编调用C语言,函数由两个参数 gd_t  和dest_addr
void board_init_r(gd_t *id, ulong dest_addr)

对应的反汇编代码:
       7d8:    e1a00008     mov    r0, r8
7dc: e5981034 ldr r1, [r8, #52] ; 0x34
7e0: e59ff008 ldr pc, [pc, #8] ; 7f0 <clbss_l+0x30>
pc = pc +8 +8 = 0x7f0


     7f0:    000008ac     andeq    r0, r0, ip, lsr #17


     //跳转到0x000008ac处执行 board_init_r
  
000008ac <board_init_r>:
8ac: e5982004 ldr r2, [r8, #4]
8b0: e92d4008 push {r3, lr}
8b4: e59f30b4 ldr r3, [pc, #180] ; 970 <board_init_r+0xc4>
8b8: e3822001 orr r2, r2, #1
8bc: e5882004 str r2, [r8, #4]
8c0: e5932000 ldr r2, [r3]
8c4: e59f30a8 ldr r3, [pc, #168] ; 974 <board_init_r+0xc8>
8c8: e1a04001 mov r4, r1
8cc: e5832000 str r2, [r3]
8d0: eb0001ad bl f8c <__enable_caches>
8d4: eb01729f bl 5d358 <board_init>

====board_init_r 调用第二阶段=======