Uboot优美代码赏析2:第一阶段_硬件平台启动start.s分析

http://www.cnblogs.com/zhangsufeng/archive/2011/08/11/2134362.html

 

重点是两个文件:

u-boot-2011.06\arch\arm\cpu\arm920t\start.S

u-boot-2011.06\board\samsung\smdk2410\lowlevel_init.S

C入口:

arch\arm\lib\board.c

初始化函数:board_init_f

启动函数:board_init_r

ARM指令集(汇编语言)基础:

1.运行状态(Processor Operating States)分为:ARM状态(32位以字对齐)Thumb状态(16位以半字对齐,使用BX指令进行切换,寄存器的bit[0]0时处于ARM状态,寄存器的bit[0]1时,处于Thumb状态

2.运行模式(Operating Modes) ARM920T支持7种模式(CPSR寄存器中设置M[4:0])

1) 用户(usr): 正常ARM程序执行状态 10000

2) 快中断(fiq): 为支持数据传输或通道处理设计 10001

3)中断(irq): 用于一般用途的中断处理 10010

4)管理(svc): 操作系统保护模式 10011

5)中止(abt): 数据或指令预取中止后进入 10111

6)系统(sys): 操作系统的特权用户模式 11011

7)未定义(und): 执行了一个未定义指令时进入 11111

2.The ARM State Register Set (ARM状态寄存器)

 

CPSR:程序状态寄存器(current program status register) cpsr在用户级编程时用于存储条件码。CPSR包含条件码标志,中断禁止位,当前处理器模式以及其他状态和控制信息。

SPSR:程序状态保存寄存器。SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。

 

操作cpsr寄存器的指令有:MRSMSR

mrs r0, cpsr ;读出cpsr的值放入r0

msr cpsr, r0 ;存r0的值到cpsr

3.汇编语言的执行逻辑:

label

#指令

定义label,做标记或跳转地址用

label

.word another_label/value

label定义为andother_label或者某个具体值

.macro my_macro_define

#指令

.endm 

定义宏替换

汇编的执行从.globl _start开始,如果没有遇到跳转则一直顺序执行,包括执行label下的指令,但不执行宏替换下的指令

4.基本ARM指令集:

赋值:

MOV  R0 ,R1 ;R1值赋给R0  R0=R1

MVN  R0 ,R1 ;R0=(-1)*(R1 +1)

LDR   R0 ,[R1] ;R1所存地址指向的值赋给R0

LDR   R0 ,=0x0123 ;0x0123赋给R0

STR   R0 ,[R1] ;R0的值存在R1所指地址

移位:

LSL 逻辑左移

LSR 逻辑右移

R0,LSL #3 ;R0左移3

R0,LSL R1 ;R0左移R1

SWP : 单一数据交换

SWP R1,R1,[R0] ; R1 的内容与R0 指向的存储单元的内容进行交换

SWP R1,R2,[R0] ; R0 指向的存储单元内容读取一字节数据到R1 (24 位清零),并将R2 的内容写入到该内存单元中(最低字节有效)

AND:逻辑与

AND R0,R1,R2 ;R0 = R1&R2

AND R0,R0,#3 ;R0 = R0&3(%0011)保留R0的第0位和第1位,其余位清0

BIC位清除:

BIC R0,R1,R2 ;R0 = R1& !R2 Dest = Op_1 AND Not Op_2

EOR:逻辑异或  1^1 = 0,两个数不同则为1,否则为0

EOR R0,R1,R2 ;R0 = R1^R2      

ORR:逻辑或 

ORR R0,R1,R2 ;R0 = R1|R2   

逻辑运算:

ADD : 加法

ADD R0,R1,R2,LSL #1 ;R0 = R1 + (R2 << 1)

SUB : 减法

SUB R0,R1,R2,LSL #1 ;R0 = R1 - (R2 << 1)

MUL:乘法

MUL R0,R1,R2 ;R0=R1*R2

MLA R0,R1,R2,R3 ;R0=(R1*R2)+R3

逻辑指令:

CMP:比较

CMP R0,R1 ;status = R0-R1,return status

CMN R0,R1 ;status = R0-(-R1),return status,比较取负的值,将第二操作数取负后比较

比较语句常与条件语句一起使用

BEQ Branch if Equal 如果相等

BNE Branch if Not Equal 如果不相等

上面的B是跳转的意思

跳转指令:

B:分支 直接将PC(R15)指向Label

BL:带链接的分支 将PC(R15)保存到LR(R14)后指向Label,在label中通过mov pc, lr 返回调用处继续执行

伪指令:

ADR 装载地址

ADR R0,Label ;label的地址装载到R0

上述指令都可以条件码拼合形成新的指令:

 

补充:

协处理器CP15指令:

 

见:http://www.cnblogs.com/gumptious/archive/2010/02/04/1663121.html

5.通过APCS实现调用含参的其他入口,如c函数

()

6.Uboot启动代码分析

.globl _start
_start:    b    start_code    ;跳转到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            ;将上面代码16字节对齐,参考http://zqwt.012.blog.163.com/blog/static/12044684201031102956976/

/*
 *************************************************************************
 *
 * Startup Code (called from the ARM reset exception vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

.globl _TEXT_BASE
_TEXT_BASE:
    .word    CONFIG_SYS_TEXT_BASE

/*
 * These are defined in the board-specific linker script.
 * Subtracting _start from them lets the linker put their
 * relative position in the executable instead of leaving
 * them null.
 */
//定义于board/smdk2410/u-boot.lds
.globl _bss_start_ofs
_bss_start_ofs:
    .word __bss_start - _start

.globl _bss_end_ofs
_bss_end_ofs:
    .word __bss_end__ - _start

.globl _end_ofs
_end_ofs:
    .word _end - _start

切换到此启动:
start_code:
    /*
     * 设置cpu保护模式启动
     */
    mrs    r0, cpsr
    bic    r0, r0, #0x1f    0x1f= 11111 ,cpsrm[4:0]0
    orr    r0, r0, #0xd3    ;将cpsrm[4:0]设置为0xd3(10011),即SVC模式
    msr    cpsr, r0
#ifdef CONFIG_S3C24X0


通过datasheet查下面的地址
#  define pWTCON    0x53000000    /*watchdog timer control register */
#  define INTMSK    0x4A000008    /* Interupt-Controller base addresses */
#  define INTSUBMSK    0x4A00001C
#  define CLKDIVN    0x4C000014    /* clock divisor register */
    /* 关闭看门狗 */
    ldr    r0, =pWTCON
    mov    r1, #0x0
    str    r1, [r0]  pWTCON地址存00为关看门狗

    /*
     * 关所有的中断,1为使中断失效
     */
    mov    r1, #0xffffffff
    ldr    r0, =INTMSK
    str    r1, [r0]


    /* 设置 FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    /*通过设置PLLCON CLKDIVN寄存器来实现超频*/
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]
#endif    /* CONFIG_S3C24X0 */
    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl    cpu_init_crit
#endif
在此先插入该label的代码
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
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 */

    /*
     * 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

    /*
     * before relocating, we have to setup RAM timing
     * because memory timing is board-dependend, you will
     * find a lowlevel_init.S in your board directory.
     */
    mov    ip, lr

    bl    lowlevel_init    ;转到board\samsung\smdk2410\lowlevel_init.S执行

    mov    lr, ip
    mov    pc, lr //返回调用处
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
再插代码:
_TEXT_BASE:
    .word    CONFIG_SYS_TEXT_BASE 
定义在:board\samsung\smdk2400\config.mkCONFIG_SYS_TEXT_BASE = 0x0CF80000
.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 ! */

见:http://weimenlove.blog.163.com/blog/static/1777547320110212134343/
;3. 设置存储相关寄存器
;这是设置SDRAM,flash ROM 存储器连接和工作时序的程序,片选定义的程序,SMRDATA map在下面的程序中定义

    ldr     r0, =SMRDATA ;存放了13DCD数据,不附代码了
    ldr    r1, _TEXT_BASE
    sub    r0, r0, r1
    ldr    r1, =BWSCON    /*存储管理器*/
    add     r2, r0, #13*4 End address of SMRDATA
0:
    ldr     r3, [r0], #4
    str     r3, [r1], #4
    cmp     r2, r0
    bne     0b
;设置存储器控制寄存器从CONFIG_SYS_TEXT_BASE依次填入之前存储到13DCD数据,这个是典型到汇编循环
    /* everything is fine now */
    mov    pc, lr //返回调用处
参考:http://blog.163.com/jiangh_1982/blog/static/12195052010615511574/


继续start.S中执行

 在此设置栈内存,(以前版本是在stack_setup这,将sp指向一块定义好的内存中)

/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)//这个宏定义在include\configs\smdk2410.h ?
    bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
    ldr    r0,=0x00000000    //调用函数前,将参数a1(APCS)置为0
    bl    board_init_f    //进入C初始化

/*
 * void relocate_code (addr_sp, gd, addr_moni)
 *
 * This "function" does not return, instead it continues in RAM
 * after relocating the monitor code.
 *

  */

准备Uboot重定位代码

.globl relocate_code

relocate_code:

mov r4, r0 /* save addr_sp */

mov r5, r1 /* save addr of gd */

mov r6, r2 /* save addr of destination */


/* Set up the stack    */

stack_setup:

mov sp, r4


adr r0, _start //ram启动的地址

cmp r0, r6 //判断当前是从flash启动还是从ram启动

beq clear_bss /* skip relocation */ram启动则跳过Uboot重定位代码,执行BSS段空间清0

mov r1, r6 /* r1 <- scratch for copy_loop */ 此时R6SMRDATA+13*4 

ldr r3, _bss_start_ofs 

add r2, r0, r3 /* r2 <- source end address   此处不明白? */

copy_loop:
    ldmia    r0!, {r9-r10}        /* copy from source address [r0]    */
    stmia    r1!, {r9-r10}        /* copy to   target address [r1]    */
    cmp    r0, r2            /* until source end address [r2]    */
    blo    copy_loop


#ifndef CONFIG_PRELOADER
    /*
     * fix .rel.dyn relocations
     */
    ldr    r0, _TEXT_BASE        /* r0 <- Text base */
    sub    r9, r6, r0        /* r9 <- relocation offset */
    ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
    add    r10, r10, r0        /* r10 <- sym table in FLASH */
    ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
    add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
    ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
    add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
fixloop:
    ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
    add    r0, r0, r9        /* r0 <- location to fix up in RAM */
    ldr    r1, [r2, #4]
    and    r7, r1, #0xff
    cmp    r7, #23            /* relative fixup? */
    beq    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]
    add    r1, r1, r9
fixnext:
    str    r1, [r0]
    add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
    cmp    r2, r3
    blo    fixloop
#endif

clear_bss:
#ifndef CONFIG_PRELOADER
    ldr    r0, _bss_start_ofs
    ldr    r1, _bss_end_ofs
    mov    r4, r6            /* reloc addr */
    add    r0, r0, r4
    add    r1, r1, r4
    mov    r2, #0x00000000        /* clear        0        */
/*BSS段空间循环清0*/
clbss_l:str    r2, [r0]        /* clear loop...            */
    add    r0, r0, #4
    cmp    r0, r1
    bne    clbss_l

    bl coloured_LED_init
    bl red_LED_on
#endif

/*
 * We are done. Do not return, instead branch to second part of board
 * initialization, now running from RAM.
 */
#ifdef CONFIG_NAND_SPL
    ldr     r0, _nand_boot_ofs
    mov    pc, r0 //进入nandflash启动的C主函数

_nand_boot_ofs:
    .word nand_boot
#else
    ldr    r0, _board_init_r_ofs 
    adr    r1, _start
    add    lr, r0, r1
    add    lr, lr, r9
    /* setup parameters for board_init_r */
    mov    r0, r5        /* gd_t */
    mov    r1, r6        /* dest_addr */
    /* jump to it ... */
    mov    pc, lr     //进入C主函数

_board_init_r_ofs:
    .word board_init_r - _start
#endif

_rel_dyn_start_ofs:
    .word __rel_dyn_start - _start
_rel_dyn_end_ofs:
    .word __rel_dyn_end - _start

 */

准备Uboot重定位代码

.globl 

mov r4, r0 

mov r5, r1 

mov r6, r2 


/* Set up the stack 

mov 


adr r0, _start 

cmp r0, r6 

beq clear_bss 

mov r1, r6 

ldr 

add r2, r0, r3 /* r2 <- source end address 

relocate_coderelocate_code:/* save addr_sp *//* save addr of gd *//* save addr of destination */    */stack_setup:sp, r4//ram启动的地址//判断当前是从flash启动还是从ram启动/* skip relocation */ram启动则跳过Uboot重定位代码,执行BSS段空间清0/* r1 <- scratch for copy_loop */r3, _bss_start_ofs    */_dynsym_start_ofs:
 

 .word __dynsym_start - _start  

   

有几个疑问需请教各位大牛:

1.中间一段dynsym实在是看不懂

2.BSS段的copy和清0还不太明白

3.SMRDATA为何如此定义?

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值