• 海思uboot启动流程详细分析(一)


    第一阶段 start.S

    首先我们可以在u-boot.lds中看到ENTRY(_start),即指定了入口_start_start也就是整个start.S的最开始;

    1. reset

    archarmcpuarmv8hi3559av100中的start.S

    注意x30在ARMV8中代表lr寄存器

    
    reset:
        /*
         * Could be EL3/EL2/EL1, Initial State:
         * Little Endian, MMU Disabled, i/dCache Disabled
         */
        adr    x0, vectors
        switch_el x1, 3f, 2f, 1f
    3:  msr    vbar_el3, x0
        mrs    x0, scr_el3
        orr    x0, x0, #0xf             /* SCR_EL3.NS|IRQ|FIQ|EA */
        msr    scr_el3, x0
        msr    cptr_el3, xzr            /* Enable FP/SIMD */
    #ifdef COUNTER_FREQUENCY
        ldr    x0, =COUNTER_FREQUENCY
        msr    cntfrq_el0, x0           /* Initialize CNTFRQ */
    #endif
        b      0f
    2:  msr    vbar_el2, x0
        mov    x0, #0x33ff
        msr    cptr_el2, x0             /* Enable FP/SIMD */
        b      0f
    1:  msr    vbar_el1, x0
        mov    x0, #3 << 20
        msr    cpacr_el1, x0            /* Enable FP/SIMD */
    0:
        /*
         * Cache/BPB/TLB Invalidate
         * i-cache is invalidated before enabled in icache_enable()
         * tlb is invalidated before mmu is enabled in dcache_enable()
         * d-cache is invalidated before enabled in dcache_enable()
         */
    
        /*
         *  read system register REG_SC_GEN2
         *  check if ziju flag
         */
        ldr    x0, =SYS_CTRL_REG_BASE
        ldr    w1, [x0, #REG_SC_GEN2]
        ldr    w2, =0x7a696a75         /* magic for "ziju" */
        cmp    w1, w2
        bne    normal_start_flow
        mov    x1, sp                  /* save sp */
        str    w1, [x0, #REG_SC_GEN2]  /* clear ziju flag */
    

    adr x0, vectors,其中的vectors代表了异常向量表

    主要做了如下事情:

    1)reset SCTRL寄存器

    具体可参考reset_sctrl函数,由CONFIG_SYS_RESET_SCTRL控制,一般不需要打开。该配置项的解释如下:

    Reset the SCTRL register at the very beginning of execution to avoid interference from stale mappings set up by early firmware/loaders/etc.

    http://lists.denx.de/pipermail/u-boot/2015-April/211147.html

    2)根据当前的EL级别,配置中断向量、MMU、Endian、i/d Cache等。

    3)配置ARM的勘误表

    具体可参考apply_core_errata函数,由CONFIG_ARM_ERRATA_XXX控制,在项目的初期,可以不打开,后续根据实际情况打开)。

    2. normal_start_flow流程

    这里是正常启动流程

    normal_start_flow:
        /* set stack for C code  */
        ldr    x0, =(CONFIG_SYS_INIT_SP_ADDR)
        bic    sp, x0, #0xf            /* 16-byte alignment for ABI compliance */
    
        bl      uart_early_init
        adr     x0, Str_SystemSartup
        bl      uart_early_puts
    	ldr  x0, =0x1202008c
    	ldr w0, [x0]
    	bl uart_early_put_hex
        /* enable I-Cache  */
        bl     icache_enable
    

    1)设置代码的堆栈
    2.)跳转到uart_early_init

    因为uart_early_init是全局的伪汇编指令(在uart.S中定义),所以在start.S中也可以使用到

    3)声明一个字符串Str_SystemSartup
    4)使能icache

    因为bne normal_start_flow是不跳转回来的,所以会继续向下执行

    3. running_addr_check流程

    判断是否进入not_ddr_init中,不需要DDR初始化,直接copy到DDR中

    check_boot_mode:
        ldr    x0, =SYS_CTRL_REG_BASE
        ldr    w0, [x0, #REG_SYSSTAT]
        lsr    w6, w0, #4
        and    w6, w6, #0x3
        cmp    w6, #BOOT_FROM_EMMC  //判断是不是EMMC启动
        bne    ufs_boot //如果不是,则进入ufs_boot
    

    4. ziju_flow流程

    自举模式从这里我可以推断出,芯片的启动分为两种,一种是自举模式也就是本地的spiflash或nand或emmc等启动,另一种就是pcie启动模式。不同启动模式对应不同的启动流程。但不同启动模式代码是相互交织的,需要分清楚!

    1) 初始化PLL和DDRC控制器和管脚复用情况。

    /* init PLL/DDRC/pin mux/... */
        ldr r0, _blank_zone_start
        ldr r1, _TEXT_BASE
        sub r0, r0, r1
        ldr r1, =RAM_START_ADRS
        add r0, r0, r1
        mov r1, #0x0                 /* flags: 0->normal 1->pm */
        bl  init_registers           /* init PLL/DDRC/... */
    

    bl init_registers这个函数是初始化一些寄存器,这些寄存器分了很多,包括中断、网络、哈希功能形式的寄存器,初始化的意思就是给一个值,但这值一般没什么意义,具体的寄存器,后面会再进行配置!

    2) start_ddr_training

    /* DDR training:DR布线,完全按等长约束就没有ddr training的说法。
    当布线去掉等长约束或放宽约束条件,就要做ddr training,以保证时序的完整性,使信号的建立&保持时间窗口一致。ddr training是调整Addr/Cmd信号对CLK,DQ信号对DQS的延时。由于没做等长约束,信号有长,有短,就会导致信号有快,慢之差(信号在1000mil走线耗时约160~180ps,相对FR-4的板材),ddr training就是找到一套参数,使信号的建立与保持时间充足。并保存且写到配置中。*/

    3) pcie_slave_boot

    5. jump_to_ddr

    自举模式省略了一些PCIE判断的情况的解释,我也没怎么看懂

    jump_to_ddr:
        adr    x0, _start_armboot
        ldr    x30,[x0]
        ret
    

    开始进入跳转到C语言阶段

    总结

    1. 关cache,关mmu,SVC模式
    2. 检测是不是自举模式还是pcie启动,也包括是冷启动还是热启动
    3. 串口初始化
    4. DDR初始化和DDR training
    5. 正常启动时,会检测启动方式,对代码进行相应的拷贝,重定位
    6. 设置堆栈
    7. 清bss段
    8. 跳转到第二阶段,即C语言阶段
  • 相关阅读:
    数据结构01——线性表
    hdu 6069 Counting Divisors (唯一正整数分解定理+素数筛)
    hdu 6053 TrickGCD (莫比乌斯)
    hdu 1695 GCD(莫比乌斯入门)
    poj 2096 Collecting Bugs (概率dp)
    DC.p4: programming the forwarding plane of a data-center switch
    Packet Transactions: High-level Programming for Line-Rate Switches
    P4: Programming Protocol-Independent Packet Processors
    Improving Network Management with Software Defined Networking
    Are We Ready for SDN? Implementation Challenges for Software-Defined Networks
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/10649273.html
Copyright © 2020-2023  润新知