Bootloader 源码分析

Bootloader 完成了Linux系统启动前的硬件初始化,并将跳到C执行入口,进行firmware的初始化部分。这里主要分析汇编部分。

U-boot 启动过程属于多阶段类型。第一阶段完成CPU体系结构初始化,通常由汇编完成。第二阶段实现较为复杂的功能如实现初始化硬件、内存映射、TFTP传输,串口调试,内核参数传递等,通常由C语言实现。

1. 第一阶段代码分析

第一阶段的源文件包括CPU初始化相关以及开发板初始化相关分别对应/cpu/arm920t/start.S和board/***/lowlevel_init.S文件。

1.1. 硬件初始化

完成对CPU正常工作所必须初始化工作,如时钟、工作模式、MMU等。

reset:
    /*
     * 设置CPU 工作在超级保护模式(SVC32)
     */
     mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0
    ldr     r0, =pWTCON /*关闭看门狗*/
    mov     r1, #0x0
     str     r1, [r0]
   .....
bl  cpu_init_crit /*跳转到该标签设置CPU寄存器MMU Cache等*/

1.2 初始化SDRAM控制器

准备Bootloader第二阶段代码RAM空间。

lowlevel_init:
    ldr     r0, =SMRDATA /*13个寄存器值存放地址*/
    ldr r1, _TEXT_BASE
    sub r0, r0, r1      /*地址变换*/
    ldr r1, =BWSCON /* Bus Width Status Controller */
    add     r2, r0, #13*4   /*SMRDATA 末尾地址*/
    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 ....

1.3 设置堆栈

stack_setup:
    ldr r0, _TEXT_BASE  /*代码段地址之前作为堆栈 */
    sub r0, r0, #CFG_MALLOC_LEN/*留给 malloc 动态分配*/
    sub r0, r0, #CFG_GBL_DATA_SIZE /*存放全局变量 */

#ifdef CONFIG_USE_IRQ
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    /*IRQ和FIQ申请堆栈*/
#endif
    sub sp, r0, #12     /* 留下12字节的abord异常空间*/

1.4复制Bootloader第二阶段程序到RAM空间

relocate:               /* 将U-boot复制到RAM空间*/
    adr r0, _start      /* 当前代码地址作为源地址给r0 */
    ldr r1, _TEXT_BASE/*代码段链接地址作为目标地址给r1 */
    cmp     r0, r1         /* don't reloc during debug */
    beq     clear_bss    /*测试是否在RAM中调试,否则继续复制*/
    ldr r2, _armboot_start /*启动地址*/
    ldr r3, _bss_start  /*BSS段起始地址 即 代码段结束地址*/
    sub r2, r3, r2      /* 代码段大小给 r2*/
    bl  CopyCode2Ram    /*Nand启动时(位于bord/boot_init.c )
                           跳转复制函数 r0: source, r1: dest, r2: size*/
    add r2, r0, r2  /* r2 <- source end address*/
copy_loop: /*Nor flash 启动循环复制*/
    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

1.5 跳转到C入口

跳转之前清除堆栈空间,然后PC指针跳转到/lib_arm/board.c中的start_armboot( )函数开始执行bootloader的第二阶段代码。

ldr pc, _start_armboot
_start_armboot: .word start_armboot

2.第二阶段代码分析

Bootloader第二阶段完成工作从lib_arm/board.c中的start_armboot( )函数开始执行,也即是第一阶段跳转到的地址。从这部分开始下面全是由C编写完成,分析起来较为容易,不做过多介绍,依次完成的主要工作:

  • size = flash_init ();
  • nand_init(); /* go init the NAND */
  • env_relocate (); /* initialize environment */
  • devices_init (); /* get the devices list going. */
  • jumptable_init (); /* 初始化跳转列表 */
  • console_init_r (); /* fully init console as a device */
  • enable_interrupts ();/* 中断使能 */
  • board_late_init ();
  • eth_initialize(gd->bd);/* 初始化网口 */
  • 在main_loop ()中死循环,等待用户交互。
for (;;)
{
  main_loop ();
}

你可能感兴趣的:(Bootloader 源码分析)