现在的位置: 首页 > 综合 > 正文

uboot源码分析-第一阶段(汇编部分)

2013年10月20日 ⁄ 综合 ⁄ 共 7368字 ⁄ 字号 评论关闭

42 u-boot源码分析 --- 启动第一阶段

分析代码当然要从上电后执行的第一条指令开始看起咯, 那第一条指令在哪呢? 还是以smdk2410为例,我们看它的链接脚本:

board/smsk2410/u-boot.lds:

……

ENTRY(_start)   //入口地址

SECTIONS

{

    . = 0x00000000;

 

    . = ALIGN(4);

    .text      :

    {

  cpu/arm920t/start.o  (.text)   //呵呵, 这个就是启动后执行的第一个文件

  *(.text)

}

 

    . = ALIGN(4);

    .rodata : { *(.rodata)
}

……

}

由这个文件可知第一个执行的文件是cpu/arm920t/start.S,那第一条指令就在这里了。我们看这个文件:

cpu/arm920t/start.S:

.globl _start

_start: b       reset   
   //
复位向量

        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

 

2410CPU规定开机后的PC寄存器地址为0,即从0地址开始执行指令,因此我们必须把我们的程序放在正确的地址处才能正常开机。 ARM核也规定启动地址处的32个字节必须存放异常向量跳转表,里面保存有中断,异常等的处理函数地址。当系统产生中断时,必定会跳到这里来开始处理中断。具体可参考ARM方面的书籍。

u-boot.lds可知入口地址为_start, 即开机后从_start处开始执行指令。所以第一条指令就是:

b reset       //跳转到reset处进行复位处理

 

cpu/arm920t/start.S:

/*

 * the actual reset code

 */

 

reset:

    /*

     * 让处理器进入SVC32模式,这样可以拥有特权操作,参考ARM书籍

     */

    mrs r0,cpsr

    bic r0,r0,#0x1f

    orr r0,r0,#0xd3

    msr cpsr,r0

 

/* turn off the
watchdog */

//CPU上操作watchdog相关的寄存器地址,可参考CPUdatasheet,这里用到的地址都是实地址,

//因为还没为MMU等部件进行初始化,也没切换操作模式呢。

#if
defined(CONFIG_S3C2400)

# define pWTCON    0x15300000

# define INTMSK    0x14400008  /*
Interupt-Controller base addresses */

# define CLKDIVN   0x14800014  /*
clock divisor register */

#elif
defined(CONFIG_S3C2410)

# define pWTCON    0x53000000

# define INTMSK    0x4A000008  /*
Interupt-Controller base addresses */

# define INTSUBMSK 0x4A00001C

# define CLKDIVN   0x4C000014  /*
clock divisor register */

#endif

 

#if
defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

    ldr    
r0, =pWTCON

    mov    
r1, #0x0

    str    
r1, [r0] //
关闭watchdog,具体寄存器含义可参考CPU手册

 

    /*

     *
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,
=0x3ff

    ldr r0,
=INTSUBMSK

    str r1,
[r0]  //
关闭所有的中断

# endif

 

    /* FCLK:HCLK:PCLK = 1:2:4 */

    /* default FCLK is 120 MHz ! */

//设置HCLKFCLK/2, PCLKFCLK/4, FCLKCPU产生clock,HCLKAHB总线上的设备产生//clock, PCLKAPB总线上的设备产生clock,具体参考s3c2410datasheet

    ldr r0,
=CLKDIVN

    mov r1,
#3

    str r1,
[r0] 

#endif  /* CONFIG_S3C2400 || CONFIG_S3C2410 */

 

    /*

     * we
do sys-critical inits only at reboot,

     * not
when booting from ram!

     */

//做系统相关的重要初始化,这些初始化代码只在系统重起的时候执行,

// CONFIG_SKIP_LOWLEVEL_INIT 可以看README.

#ifndef
CONFIG_SKIP_LOWLEVEL_INIT

    bl  cpu_init_crit  //可以先看这段代码在转回来接着看后面的复位过程。

#endif

 

   //内存配置完后,可以进行重定位操作了

#ifndef
CONFIG_SKIP_RELOCATE_UBOOT

relocate:              /* 重定位u-bootRAM*/

    adr r0,
_start      /* r0
flash中的代码的起始地址*/

    ldr r1,
_TEXT_BASE  /* r1
= 代码在RAM中的起始地址 */

    cmp    
r0, r1      /*
看是否u-boot就在RAM中运行*/

    beq    
stack_setup  /*
如果在RAM中则无需重定位*/

   

    /*开始重定位,即把u-bootflash中搬到RAM中去运行*/

    ldr r2,
_armboot_start  /*r2 = flash
中代码的起始地址,看_armboot_start的定义*/

    ldr r3,
_bss_start  /*r3 = bss
段的起始地址,_bss_start可在u-boot.lds中查看。*/

    sub r2,
r3, r2      /* r2
= 需要重定位的字节数*/

    add r2,
r0, r2      /* r2
flashRO,RW内容的结束地址 */

 

//开始把代码从flash中搬运到RAM

copy_loop:

    ldmia   r0!,
{r3-r10}      /*
获取从r0开始的代码,存入r3—r10*/

    stmia   r1!,
{r3-r10}      /*
r3—r10的内容存入r1所在位置,即RAM*/

    cmp r0,
r2                  /*copy
所有代码 */

    ble copy_loop

#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */

 

    /*设置栈地址*/

stack_setup:

    ldr r0,
_TEXT_BASE     /*upper 128 KiB: relocated
uboot*/

    sub r0, r0, #CFG_MALLOC_LEN /*malloc分配内存的区域,大小以板子的配置而定,smdk2410

的在include/configs/smdk2410.h中定义*/

    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     /*
保留 12字节给
abort-stack, 并设好堆栈*/

 

//bss段内容清0

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

 

#if 0

    /* try doing this stuff after the relocation
*/

    ldr    
r0, =pWTCON

    mov    
r1, #0x0

    str    
r1, [r0]

 

    /*

     *
mask all IRQs by setting all bits in the INTMR - default

     */

    mov r1,
#0xffffffff

    ldr r0,
=INTMR

    str r1,
[r0]

 

    /* FCLK:HCLK:PCLK = 1:2:4 */

    /* default FCLK is 120 MHz ! */

    ldr r0,
=CLKDIVN

    mov r1,
#3

    str r1,
[r0]

    /* END stuff after relocation */

#endif

 

    ldr pc,
_start_armboot   //
跳转到_start_armboot处执行。

_start_armboot: .word start_armboot

 

总结reset这块代码,主要完成了一下几个部分:

1.    重要部分的初始化工作,如禁止中断,关闭watchdog,初始化memory控制器等

2.    重定位boot
loader
ram

3.    设置好堆栈

4.    跳转到第2阶段执行

完成这些后,此时内存的分布情况如下:


这个图代表的是u-boot自己在内存的情况,和上面的图不一样,这里的_TEXT_BASE就是0x33F8’0000

 

   接着看CPU_init_critical

 

cpu/arm920t/start.S:

/*

 *************************************************************************

 *

 * CPU_init_critical registers

* 设置cache,TLB,MMU等寄存器

 * 设置内存操作的时序

 *

 *************************************************************************

 */

cpu_init_crit:

    /*

     *
flush v4 I/D caches

     */

    /*使cacheTLB无效,
可以参考data sheet*/

    mov r0,
#0

    mcr p15,
0, r0, c7, c7, 0  /*
使指令cache和数据cache无效 */

    mcr p15,
0, r0, c8, c7, 0  /*
使TLB无效 */

 

    /*

     *
disable MMU stuff and caches

     */

    mrc p15,
0, r0, c1, c0, 0  /*
读出c1控制寄存器的值*/

    bic r0,
r0, #0x00002300 @ clear bits 13, 9:8 (--V-
--RS)

    bic r0,
r0, #0x00000087 @ clear bits 7, 2:0 (B---
-CAM),
小端对齐,关闭数据cache,关

//闭错误检测,关闭MMU

    orr r0,
r0, #0x00000002 @ set bit 2 (A) Align,
使能错误检测

    orr r0,
r0, #0x00001000 @ set bit 12 (I) I-Cache
, 使能指令cache

    mcr p15,
0, r0, c1, c0, 0  /*
设置c1控制寄存器*/

    /*可以参考data sheet*/

 

    /*

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

     */

    //在把u-boot重定位到RAM前,我们必须先把RAM的时序设置好,内存时序是依板子而定的,//所以这里的初始化应该由我们提供,一般在我们的板子所在目录下有个lowlevel_init.S来负//责这件事情。特定板子的目录还记得吗, 呵呵回到上面在看看。

    mov ip,
lr

    bl  lowlevel_init

    mov lr,
ip

 

    mov pc,
lr //
类似于函数返回

 

cpu_init_crit主要是使能了instruction
cache,
关闭了MMU等部件,但是好像在u-boot后面的代码里没有看见打开MMU的操作,我猜测可能是留到了OS启动的时候再打开了吧,data cache在第二阶段的board_init下被使能。

 

接着看lowlevel_init。以smdk2410位例

 

board/smdk2410/lowlevel_init.S

_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  //
设置内存配置寄存器,可以对着datasheet来看这里的设置,包括时

//序位宽等等, 使用一个循环来配置所有的寄存器

    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

这部分代码主要是设置memory的时序,位宽等参数

 

抱歉!评论已关闭.