uboot启动第一阶段分析

一. uboot第一阶段初识

  1.1. 什么是uboot第一阶段

    1.1.1. 启动os三个阶段

      1.1.1.1. bl0阶段

        a. 这段代码是三星固化到iROM中,可以查看《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》

        b. 这段代码作用是将uboot第一阶段的8kb加载到iRAM中

      1.1.1.2. bl1阶段(uboot第一阶段)

        a. 此部分是整个uboot的前8k部分

        b. 此部分有bl0 加载到iRAM指定地址

      1.1.1.3. bl2阶段(整个uboot)

        a. 此部分是整个uboot    

        b. 此部分由bl1重定位到DDR的链接地址去

  1.2. 第一阶段主要作用

    a. 初始化DDR

    b. 将整个uboot重定位到DDR中

    c. 跳转到DDR中执行uboot(长跳转)

二. uboot 第一阶段源码分析

  2.1. uboot链接脚本分析

    a. ENTRY(_start):整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start)因此_start符号所在的文件就是整个程序的起始文件,_start所在处的代码就是整个程序的起始代码。

    b. 在text段中,指定很多文件的段靠前存放,这样可以保证必要的文件可以在uboot前8K地址内     

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
    . = 0x00000000;

    . = ALIGN(4);
    .text      :
    {
      cpu/s5pc11x/start.o    (.text)
      cpu/s5pc11x/s5pc110/cpu_init.o    (.text)
      board/samsung/x210/lowlevel_init.o    (.text)
          cpu/s5pc11x/onenand_cp.o      (.text)                 
          cpu/s5pc11x/nand_cp.o (.text)                     
          cpu/s5pc11x/movi.o (.text) 
          common/secure_boot.o (.text) 
      common/ace_sha1.o (.text)
      cpu/s5pc11x/pmic.o (.text)
      *(.text)
    }

    . = ALIGN(4);
    .rodata : { *(.rodata) }

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    .got : { *(.got) }

    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;

    . = ALIGN(4);
    .mmudata : { *(.mmudata) }

    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) }
    _end = .;
}
View Code

  2.2. start.S分析 

    2.2.1. 相关头文件分析 

      a. 有些头文件是在配置/编译过程生成的

      b. 有些头文件使用了符号链接

      c. 很多宏定义在x210_sd.h宏定义,但此文件被config.h所引用

#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#include <regs.h>
View Code

    2.2.2. uboot头信息地址占位

      a. 定义4个字空间占用16字节,16字节信息定义可以查看 《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》   

      b. 此处仅仅是定义并未赋有效值,有效值再制作usb启动uboot是写入(如使用sd_fusing中sd_fdisk.c文件会填充)

#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
    .word 0x2000
    .word 0x0
    .word 0x0
    .word 0x0
#endif
View Code

    2.2.3. _start汇编标号分析

      2.3.1.1. 上述我们已经分析了,启动bl1时的起点就是_start

      2.3.1.2. b reset为什么开始执行的第一句汇编

        a. 无论是复位还是开启都属于重启,故启动先执行reset很合理

        b. reset后cpu处于SVC模式,reset汇编重新设置模式也无妨

reset:
    /*
     * set the cpu to SVC32 mode and IRQ & FIQ disable
     */
    @;mrs    r0,cpsr
    @;bic    r0,r0,#0x1f
    @;orr    r0,r0,#0xd3
    @;msr    cpsr,r0
    msr    cpsr_c, #0xd3        @ I & F disable, Mode: 0x13 - SVC
View Code

     2.2.4. 设置栈到iRAM

      a. 此时DDR未初始化,但后面需要压栈出栈故此时把栈设置到iRAM

      b. 栈地址使用《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》memery map推荐的栈地址

/*
     * Go setup Memory and board specific bits prior to relocation.
     */

    ldr    sp, =0xd0036000 /* end of sram dedicated to u-boot */
    sub    sp, sp, #12    /* set stack */
    mov    fp, #0
View Code

    2.2.5. lowlevel_init分析

      2.2.5.1. _TEXT_BASE

        2.2.5.1.1. 此标号相对应变量,变量值为TEXT_BASE

        2.2.5.1.2. TEXT_BASE是怎么来的

          a. 该变量值是make x210_sd_config配置时写入到config.mk文件中

          b. 该值会在\uboot\config.mk中作为uboot链接地址

x210_sd_config :    unconfig
    @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
    @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk
View Code

      2.2.5.2. 判断当前代码执行位置

        a. 这几行代码的作用就是判定当前代码执行的位置在SRAM中还是在DDR中。为什么要做这个判定?

          原因1:BL1(uboot的前一部分)在SRAM中有一份,在DDR中也有一份,因此如果是冷启动那么当前代码应该是在SRAM中运行的BL1,如果是低功耗状态的复位这时候应该就是在DDR中运行的。

          原因2:我们判定当前运行代码的地址是有用的,可以指导后面代码的运行。譬如在lowlevel_init.S中判定当前代码的运行地址,就是为了确定要不要执行时钟初始化和初始化DDR的代码。如果当前代码是在SRAM中,说明冷启动,那么时钟和DDR都需要初始化;如果当前代码是在DDR中,那么说明是热启动则时钟和DDR都不用再次初始化。

        b. bic r1, pc, r0 这句代码的意义是:将pc的值中的某些bit位清0,剩下一些特殊的bit位赋值给r1(r0中为1的那些位清零)相等于:r1 = pc & ~(ff000fff)
ldr r2, _TEXT_BASE 加载链接地址到r2,然后将r2的相应位清0剩下特定位。
        c. 最后比较r1和r2.

    ldr    r0, =0xff000fff
    bic    r1, pc, r0        /* r0 <- current base addr of code */
    ldr    r2, _TEXT_BASE        /* r1 <- original base addr in ram */
    bic    r2, r2, r0        /* r0 <- current base addr of code */
    cmp     r1, r2                  /* compare r0, r1                  */
    beq     1f            /* r0 == r1 then skip sdram init   */
View Code

      2.2.5.3. lowlevel_init总结 

        a. 检查复位状态、IO恢复、关看门狗、开发板供电锁存、时钟初始化、DDR初始化、串口初始化并打印'O'、tzpc初始化、打印'K'。

        b. 其中值得关注的:关看门狗、开发板供电锁存、时钟初始化、DDR初始化、打印"OK"

_TEXT_BASE:
    .word    TEXT_BASE

    .globl lowlevel_init
lowlevel_init:
    push    {lr}

    /* check reset status  */
    
    ldr    r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
    ldr    r1, [r0]
    bic    r1, r1, #0xfff6ffff
    cmp    r1, #0x10000
    beq    wakeup_reset_pre
    cmp    r1, #0x80000
    beq    wakeup_reset_from_didle

    /* IO Retention release */
    ldr    r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
    ldr    r1, [r0]
    ldr    r2, =IO_RET_REL
    orr    r1, r1, r2
    str    r1, [r0]

    /* Disable Watchdog */
    ldr    r0, =ELFIN_WATCHDOG_BASE    /* 0xE2700000 */
    mov    r1, #0
    str    r1, [r0]

    /* SRAM(2MB) init for SMDKC110 */
    /* GPJ1 SROM_ADDR_16to21 */
    ldr    r0, =ELFIN_GPIO_BASE
    
    ldr    r1, [r0, #GPJ1CON_OFFSET]
    bic    r1, r1, #0xFFFFFF
    ldr    r2, =0x444444
    orr    r1, r1, r2
    str    r1, [r0, #GPJ1CON_OFFSET]

    ldr    r1, [r0, #GPJ1PUD_OFFSET]
    ldr    r2, =0x3ff
    bic    r1, r1, r2
    str    r1, [r0, #GPJ1PUD_OFFSET]

    /* GPJ4 SROM_ADDR_16to21 */
    ldr    r1, [r0, #GPJ4CON_OFFSET]
    bic    r1, r1, #(0xf<<16)
    ldr    r2, =(0x4<<16)
    orr    r1, r1, r2
    str    r1, [r0, #GPJ4CON_OFFSET]

    ldr    r1, [r0, #GPJ4PUD_OFFSET]
    ldr    r2, =(0x3<<8)
    bic    r1, r1, r2
    str    r1, [r0, #GPJ4PUD_OFFSET]


    /* CS0 - 16bit sram, enable nBE, Byte base address */
    ldr    r0, =ELFIN_SROM_BASE    /* 0xE8000000 */
    mov    r1, #0x1
    str    r1, [r0]

    /* PS_HOLD pin(GPH0_0) set to high */
    ldr    r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
    ldr    r1, [r0]
    orr    r1, r1, #0x300    
    orr    r1, r1, #0x1    
    str    r1, [r0]

    /* when we already run in ram, we don't need to relocate U-Boot.
     * and actually, memory controller must be configured before U-Boot
     * is running in ram.
     */
    ldr    r0, =0xff000fff
    bic    r1, pc, r0        /* r0 <- current base addr of code */
    ldr    r2, _TEXT_BASE        /* r1 <- original base addr in ram */
    bic    r2, r2, r0        /* r0 <- current base addr of code */
    cmp     r1, r2                  /* compare r0, r1                  */
    beq     1f            /* r0 == r1 then skip sdram init   */

    /* init system clock */
    bl system_clock_init

    /* Memory initialize */
    bl mem_ctrl_asm_init
    
1:
    /* for UART */
    bl uart_asm_init

    bl tzpc_init

#if defined(CONFIG_ONENAND)
    bl onenandcon_init
#endif

#if defined(CONFIG_NAND)
    /* simple init for NAND */
    bl nand_asm_init
#endif

    /* check reset status  */
    
    ldr    r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
    ldr    r1, [r0]
    bic    r1, r1, #0xfffeffff
    cmp    r1, #0x10000
    beq    wakeup_reset_pre

    /* ABB disable */
    ldr    r0, =0xE010C300
    orr    r1, r1, #(0x1<<23)
    str    r1, [r0]

    /* Print 'K' */
    ldr    r0, =ELFIN_UART_CONSOLE_BASE
    ldr    r1, =0x4b4b4b4b
    str    r1, [r0, #UTXH_OFFSET]

    pop    {pc}
View Code

猜你喜欢

转载自www.cnblogs.com/linux-37ge/p/10274962.html