u-boot第一阶段初始化流程(反汇编分析)

1.设置中断向量表
为了更清楚,彻底的理解u-boot,我会全部从反汇编的代码去分析
忘记的朋友先补下课啦,提示:arm-linux-objdump -D u-boot>u-boot.s
====================================================================================================
.globl _start
_start:    b       start_code
    ldr    pc, _undefined_instruction
    ldr    pc, _software_interrupt
    ldr    pc, _prefetch_abort
    ldr    pc, _data_abort
    ldr    pc, _not_used
    ldr    pc, _irq
    ldr    pc, _fiq

_undefined_instruction:    .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:        .word not_used
_irq:            .word irq
_fiq:            .word fiq

    .balignl 16,0xdeadbeef
====================================================================================================
33f80000 <_start>:
33f80000:    ea000012     b    33f80050
33f80004:    e59ff014     ldr    pc, [pc, #20]    ; 33f80020 <_undefined_instruction>
33f80008:    e59ff014     ldr    pc, [pc, #20]    ; 33f80024 <_software_interrupt>
33f8000c:    e59ff014     ldr    pc, [pc, #20]    ; 33f80028 <_prefetch_abort>
33f80010:    e59ff014     ldr    pc, [pc, #20]    ; 33f8002c <_data_abort>
33f80014:    e59ff014     ldr    pc, [pc, #20]    ; 33f80030 <_not_used>
33f80018:    e59ff014     ldr    pc, [pc, #20]    ; 33f80034 <_irq>
33f8001c:    e59ff014     ldr    pc, [pc, #20]    ; 33f80038 <_fiq>

33f80020 <_undefined_instruction>:
33f80020:    33f80140     mvnccs    r0, #16    ; 0x10

33f80024 <_software_interrupt>:
33f80024:    33f801a0     mvnccs    r0, #40    ; 0x28

33f80028 <_prefetch_abort>:
33f80028:    33f80200     mvnccs    r0, #0    ; 0x0

33f8002c <_data_abort>:
33f8002c:    33f80260     mvnccs    r0, #6    ; 0x6

33f80030 <_not_used>:
33f80030:    33f802c0     mvnccs    r0, #12    ; 0xc

33f80034 <_irq>:
33f80034:    33f80320     mvnccs    r0, #-2147483648    ; 0x80000000

33f80038 <_fiq>:
33f80038:    33f80380     mvnccs    r0, #2    ; 0x2
33f8003c:    deadbeef     cdple    14, 10, cr11, cr13, cr15, {7}
====================================================================================================
    这段比较好理解,先是在33f80000地址处定义了一个全局标号_start,这个地址是在board/smdk2410/config.mk中指定,他会被包含在Makefile文件中,链接时传递给GCC。当然,你还可以从System.map文件中找到他所标识的地址,如:33f80000 T _start,T标识他所在的段是text(code) section.
    然后是一堆中断跳转指令,如:ldr pc, _undefined_instruction。他把_undefined_instruction标号处(即地址33f80020)的值(即33f80140)放入pc指针,就是跳转到相应的中断处理函数的地址处,从反汇编中(ldr  pc, [pc, #20])我们可以看出,就是相对当前pc指针偏移20字节(计算时别忘了流水线哦!)。最后一句可能让人比较费解(.balignl 16,0xdeadbeef),他的定义是增加位置计数器(在当前子段)使它指向规定的存储边界。真是很拗口哦,不知所云。其实从反汇编中可以看出,他在这里做的事情很简单,就是在0x33f8003c地址处写入值0xdeadbeef。
有关.balignl 16,0xdeadbeef的详细解释请参考:http://haoyeren.blog.sohu.com/84511571.html

2设置特权模式
====================================================================================================
start_code:
    /*
     * set the cpu to SVC32 mode
     */
    mrs    r0,cpsr            ;cpsr中的值放到人r0
    bic    r0,r0,#0x1f        ;r0 的值与 0x1f的反码按位作逻辑与操作
    orr    r0,r0,#0xd3        ;r0的值与寄存器 0xd3的值按位作逻辑或操作
    msr    cpsr,r0            ;r0中的值放到cpsr

    bl coloured_LED_init
    bl red_LED_on
============================================================================
33f80050:    e10f0000     mrs    r0, CPSR
33f80054:    e3c0001f     bic    r0, r0, #31    ; 0x1f
33f80058:    e38000d3     orr    r0, r0, #211    ; 0xd3
33f8005c:    e129f000     msr    CPSR_fc, r0
33f80060:    eb000110     bl    33f804a8 <__coloured_LED_init>
33f80064:    eb000110     bl    33f804ac <__red_LED_on>
============================================================================
执行结果:
    禁止IRQ(bit7=1)
    禁止FRQ(bit6=1)
    ARM指令集(bit5=0)
    特权模式(bit[4..0]=10010)
最后两句是有关LED处理的跳转指令,可用如下指令定位:
    arm-linux-addr2line -e u-boot 33f804a8
在lib_arm/board.c文件中的第137行和139行:
        void inline __coloured_LED_init (void) {}
        void inline __red_LED_on (void) {}
其实都是空函数,可根据需要自己添加。

3关闭看门狗
====================================================================================================
    /* turn off the watchdog */
#  define pWTCON        0x53000000
    ldr     r0, =pWTCON            ;把0x53000000放入r0
    mov     r1, #0x0                ;把0x00放入r1
    str     r1, [r0]                ;把r1的值存入r0指向的地址处
====================================================================================================
33f80068:    e3a00453     mov    r0, #1392508928    ; 0x53000000
33f8006c:    e3a01000     mov    r1, #0    ; 0x0
33f80070:    e5801000     str    r1, [r0]
====================================================================================================
反汇编中#1392508928即是十六进制数0x53000000的十进制表示

4屏蔽所有中断
====================================================================================================
#  define INTMSK        0x4A000008    /* Interupt-Controller base addresses */
#  define INTSUBMSK    0x4A00001C
    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov    r1, #0xffffffff
    ldr    r0, =INTMSK
    str    r1, [r0]
# if defined(CONFIG_S3C2410)
    ldr    r1, =0x7ff
    ldr    r0, =INTSUBMSK
    str    r1, [r0]
# endif
====================================================================================================
33f80074:    e3e01000     mvn    r1, #0    ; 0x0
33f80078:    e59f0358     ldr    r0, [pc, #856]    ; 33f803d8 <.text+0x3d8>
33f8007c:    e5801000     str    r1, [r0]
33f80080:    e59f1354     ldr    r1, [pc, #852]    ; 33f803dc <.text+0x3dc>
33f80084:    e59f0354     ldr    r0, [pc, #852]    ; 33f803e0 <.text+0x3e0>
33f80088:    e5801000     str    r1, [r0]
。。。。。
33f803d8:    4a000008     bmi    33f80400
33f803dc:    000007ff     streqd    r0, [r0], -pc
33f803e0:    4a00001c     bmi    33f80458
====================================================================================================
注意这里的立即数无法循环右移偶数位得到,所以汇编器先把他存在了后面的地址空间中,见反汇编代码。

5设置时钟工作频率
====================================================================================================
#  define CLKDIVN    0x4C000014    /* clock divisor register */
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
====================================================================================================
33f8008c:    e59f0350     ldr    r0, [pc, #848]    ; 33f803e4 <.text+0x3e4>
33f80090:    e3a01003     mov    r1, #3    ; 0x3
33f80094:    e5801000     str    r1, [r0]
。。。。。
33f803e4:    4c000014     stcmi    0, cr0, [r0], {20}

6刷新数据和指令缓存
====================================================================================================
    bl    cpu_init_crit            ;跳转到子程序入口处
。。。。。。。
cpu_init_crit:
    /*
     * flush v4 I/D caches
     */
    mov    r0, #0
    mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */
    mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */
====================================================================================================
33f80098:    eb000018     bl    33f80100
。。。。。
33f80100:    e3a00000     mov    r0, #0    ; 0x0
33f80104:    ee070f17     mcr    15, 0, r0, cr7, cr7, {0}
33f80108:    ee080f17     mcr    15, 0, r0, cr8, cr7, {0}
====================================================================================================
记住这里有个子程序入口,第8部分子程序会返回。

7禁止MMU和缓存

====================================================================================================
    /*
     * disable MMU stuff and caches
     */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, r0, #0x00002300    @ clear bits 13, 9:8 (--V- --RS)
    bic    r0, r0, #0x00000087    @ clear bits 7, 2:0 (B--- -CAM)
    orr    r0, r0, #0x00000002    @ set bit 2 (A) Align
    orr    r0, r0, #0x00001000    @ set bit 12 (I) I-Cache
    mcr    p15, 0, r0, c1, c0, 0
====================================================================================================
33f8010c:    ee110f10     mrc    15, 0, r0, cr1, cr0, {0}
33f80110:    e3c00c23     bic    r0, r0, #8960    ; 0x2300
33f80114:    e3c00087     bic    r0, r0, #135    ; 0x87
33f80118:    e3800002     orr    r0, r0, #2    ; 0x2
33f8011c:    e3800a01     orr    r0, r0, #4096    ; 0x1000
33f80120:    ee010f10     mcr    15, 0, r0, cr1, cr0, {0}

8配置存储控制相关寄存器
====================================================================================================
    mov    ip, lr                    ;保存lr到ip(r12)
    bl    lowlevel_init        ;跳转到新的子程序入口处
    mov    lr, ip            ;恢复lr
    mov    pc, lr            ;子程序返回
    。。。。。。。。
#define BWSCON    0x48000000
_TEXT_BASE:
    .word    TEXT_BASE

.globl lowlevel_init
lowlevel_init:
    /* memory control configuration */
    /* make r0 relative the current location so that it */
    /* reads SMRDATA out of FLASH rather than memory ! */
    ldr     r0, =SMRDATA
    ldr    r1, _TEXT_BASE
    sub    r0, r0, r1
    ldr    r1, =BWSCON    /* Bus Width Status Controller */
    add     r2, r0, #13*4
0:
    ldr     r3, [r0], #4
    str     r3, [r1], #4
    cmp     r2, r0
    bne     0b

    /* everything is fine now */
    mov    pc, lr

    .ltorg
/* the literal pools origin */

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30
====================================================================================================
33f80124:    e1a0c00e     mov    ip, lr
33f80128:    eb005f76     bl    33f97f08
33f8012c:    e1a0e00c     mov    lr, ip
33f80130:    e1a0f00e     mov    pc, lr
。。。。。
33f97f04 <_TEXT_BASE>:
33f97f04:    33f80000     mvnccs    r0, #0    ; 0x0

33f97f08 :
33f97f08:    e59f0020     ldr    r0, [pc, #32]    ; 33f97f30 <.text+0x17f30>
33f97f0c:    e51f1010     ldr    r1, [pc, #-16]    ; 33f97f04 <_TEXT_BASE>
33f97f10:    e0400001     sub    r0, r0, r1
33f97f14:    e3a01312     mov    r1, #1207959552    ; 0x48000000
33f97f18:    e2802034     add    r2, r0, #52    ; 0x34
33f97f1c:    e4903004     ldr    r3, [r0], #4
33f97f20:    e4813004     str    r3, [r1], #4
33f97f24:    e1520000     cmp    r2, r0
33f97f28:    1afffffb     bne    33f97f1c
33f97f2c:    e1a0f00e     mov    pc, lr
33f97f30:    33f97f34     mvnccs    r7, #208    ; 0xd0

33f97f34 :
33f97f34:    2211d120     andcss    sp, r1, #8    ; 0x8
33f97f38:    00000700     andeq    r0, r0, r0, lsl #14
33f97f3c:    00000700     andeq    r0, r0, r0, lsl #14
33f97f40:    00000700     andeq    r0, r0, r0, lsl #14
33f97f44:    00001f4c     andeq    r1, r0, ip, asr #30
33f97f48:    00000700     andeq    r0, r0, r0, lsl #14
33f97f4c:    00000700     andeq    r0, r0, r0, lsl #14
33f97f50:    00018005     andeq    r8, r1, r5
33f97f54:    00018005     andeq    r8, r1, r5
33f97f58:    008e04f4     streqd    r0, [lr], r4
33f97f5c:    00000032     andeq    r0, r0, r2, lsr r0
33f97f60:    00000030     andeq    r0, r0, r0, lsr r0
33f97f64:    00000030     andeq    r0, r0, r0, lsr r0
====================================================================================================
注意由于前次子程序未返回,又用bl进入新的子程序,所以先要对lr进行保护。
本段主要完成的任务是,用一个循环把SMRDATA标号处定义的52字节数据依次存放到0x48000000以上的地址空间中 ,从而完成对存储控制相关寄存器的初始化工作。最后恢复lr,子程序返回。

然后来看下具体配置:(根据源代码中的宏定义)
/* BWSCON */
#define DW32            (0x2)
#define B1_BWSCON        (DW32)
#define B6_BWSCON        (DW32)

/* BANK0CON */
#define B0_Tacs            0x0    /*  0clk */
#define B0_Tcos            0x0    /*  0clk */
#define B0_Tacc            0x7    /* 14clk */
#define B0_Tcoh            0x0    /*  0clk */
#define B0_Tah            0x0    /*  0clk */
#define B0_Tacp            0x0
#define B0_PMC            0x0    /* normal */

/* BANK6CON */
#define B6_MT            0x3    /* SDRAM */
#define B6_Trcd            0x1
#define B6_SCAN            0x1    /* 9bit */

/* REFRESH parameter */
#define REFEN            0x1    /* Refresh enable */
#define TREFMD            0x0    /* CBR(CAS before RAS)/Auto refresh */
#define Trp            0x0    /* 2clk */
#define Trc            0x3    /* 7clk */
#define Tchr            0x2    /* 3clk */
#define REFCNT            1268    /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60)

BWSCON:配置总线宽度,等待状态控制寄存器
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
配置结果:
    BANK6设为32位数据总线,禁止WAIT,不用UB/LB
    (BANK0通过外部引脚设定,其他BANK未使用,设置略。)

BANKCON0:BANK0控制寄存器
((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
配置结果:
    nGCS0之前的地址建立时间0clocks,
    在nOE之前片选的建立时间0clocks,
    访问周期14clocks,
    在nOE之后的片选的保持时间0clocks,
    nGCS0之后的地址保持时间0clocks,
    页模式访问周期2clocks,
    页模式配置为标准(1 date),
   
BANKCON6:BANK6控制寄存器
((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
配置结果:
    BANK6设为类型DRAM,
    RAS到CAS延迟3clocks,
    纵向地址数9bit

REFRESH:SDRAM刷新控制寄存器
((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
配置结果:
    使能刷新
    刷新模式为自动刷新
    SDRAM RAS预改变时间2clocks
    SDRAM Semi Row 周期7clocks
    刷新计数值1268(即设定SDRAM刷新频率)

BANKSIZE:BANK大小寄存器
0x32
配置结果:
    使能SDRAM掉电模式
    SCLK仅在访问期间才有效
    BANK6/7按128M映射

MRSRB6:BANK6模式寄存器设置寄存器
0x30
配置结果:
    CAS反应时间3clocks
    顺序触发类型
    触发长度1

9将程序搬移到RAM空间
====================================================================================================
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
====================================================================================================
33f8009c :
33f8009c:    e24f00a4     sub    r0, pc, #164    ; 0xa4
33f800a0:    e51f1068     ldr    r1, [pc, #-104]    ; 33f80040 <_TEXT_BASE>
33f800a4:    e1500001     cmp    r0, r1
33f800a8:    0a000007     beq    33f800cc
33f800ac:    e51f2070     ldr    r2, [pc, #-112]    ; 33f80044 <_armboot_start>
33f800b0:    e51f3070     ldr    r3, [pc, #-112]    ; 33f80048 <_bss_start>
33f800b4:    e0432002     sub    r2, r3, r2
33f800b8:    e0802002     add    r2, r0, r2

33f800bc :
33f800bc:    e8b007f8     ldmia    r0!, {r3, r4, r5, r6, r7, r8, r9, sl}
33f800c0:    e8a107f8     stmia    r1!, {r3, r4, r5, r6, r7, r8, r9, sl}
33f800c4:    e1500002     cmp    r0, r2
33f800c8:    dafffffb     ble    33f800bc
====================================================================================================
先测试是否是Debug中(注意adr相对寻址,ldr绝对寻址的不同),是则跳转到下一部分,否则按8字节循环搬移程序到RAM空间,注意结合上面给出的uboot存储器映射图学习。

10设置堆栈指针
====================================================================================================
    /* Set up the stack                            */
stack_setup:
    ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   */
    sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area                      */
    sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub    sp, r0, #12        /* leave 3 words for abort-stack    */
====================================================================================================
33f800cc :
33f800cc:    e51f0094     ldr    r0, [pc, #-148]    ; 33f80040 <_TEXT_BASE>
33f800d0:    e2400803     sub    r0, r0, #196608    ; 0x30000
33f800d4:    e2400080     sub    r0, r0, #128    ; 0x80
33f800d8:    e240d00c     sub    sp, r0, #12    ; 0xc
====================================================================================================
结合上面的映射图可以看出,_TEXT_BASE标号处地址(33f80000)以上就是上一步重定位的程序代码,他以下减去动态内存分配区大小,再减去bdinfo的大小(uboot第二段会有个结构体指向这个区域),从反汇编代码可以看出,我们未配置用户IRQ,所以再留12个字节给中断堆栈使用。现在指向的地址就是sp指针的位置了,从反汇编可以很容易的看出sp每次减去的数值。

11清零全局未初始化数据段,并跳转到第二阶段--C程序部分
====================================================================================================
clear_bss:
    ldr    r0, _bss_start        /* find start of bss segment        */
    ldr    r1, _bss_end        /* stop here                        */
    mov    r2, #0x00000000        /* clear                            */

clbss_l:str    r2, [r0]        /* clear loop...                    */
    add    r0, r0, #4
    cmp    r0, r1
    ble    clbss_l

    ldr    pc, _start_armboot

_start_armboot:    .word start_armboot
====================================================================================================
33f800dc :
33f800dc:    e51f009c     ldr    r0, [pc, #-156]    ; 33f80048 <_bss_start>
33f800e0:    e51f109c     ldr    r1, [pc, #-156]    ; 33f8004c <_bss_end>
33f800e4:    e3a02000     mov    r2, #0    ; 0x0

33f800e8 :
33f800e8:    e5802000     str    r2, [r0]
33f800ec:    e2800004     add    r0, r0, #4    ; 0x4
33f800f0:    e1500001     cmp    r0, r1
33f800f4:    dafffffb     ble    33f800e8
33f800f8:    e51ff004     ldr    pc, [pc, #-4]    ; 33f800fc <_start_armboot>

33f800fc <_start_armboot>:
33f800fc:    33f80578     mvnccs    r0, #503316480    ; 0x1e000000
====================================================================================================
从board/smdk2410/u-boot.lds文件中,我们看到bss段被链接到了u_boot_cmd段的后面,即地址0x33f80048以后,现在我们要做的就通过一个循环把这段清空。然后重新赋值PC指针,跳转到标号_start_armboot指向的地址处,即第二阶段,C程序部分。

你可能感兴趣的:(u-boot第一阶段初始化流程(反汇编分析))