zoukankan      html  css  js  c++  java
  • 《uboot源码解析(一)启动第一阶段——start.s分析》

    原文链接:https://blog.csdn.net/itdo_just/article/details/78701886

     

    以下源码以u-boot-1.1.6中的2410为例。

    1.start.s的引入

    board/smdk2240/u-boot.lds中可以看到ENTRY(_start),。Uboot整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start) 因此_start符号所在的文件就是整个程序的起始文件,_start所在处的代码就是整个程序的起始代码。

     

    2.start.s分析

    ~/cpu/arm920t/start.S

    设置异常向量表

    跳转reset

    /*
      globl就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局的,外部可以访问
      指定入口为_start
      u-boot.lds里面定义了ENTRY(_start),即指定入口为_start 
     */
    .globl _start
    _start:    b       reset
    /*
      ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。
      比如想把数据从内存中某处读取到寄存器中,只能使用ldr
      将_undefined_instruction这个地址处的word(一字节)定义的值赋给pc。
    
      ARM体系结构规定在上电复位的起始位置必须有8条连续的跳转指令,
      通过硬件来实现。它们就是异常向量表。ARM在上电复位后是从0x0开始启动,
      如果bootloader存在,则是从_start开始执行上面的跳转没有执行。
      设置异常向量表的作用是识别bootloader,以后每当系统有异常出现时,
      cpu会根据异常号从内存0x0处开始查找并做相应的处理   
      下面8条即设置异常中断向量表
     */
       /*构建异常向量表*/
        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

    reset分析:

    /*
     * the actual reset code
     */
    
    reset:
    /* 首先进入SVC管理模式,为什么要进行SVC管理模式而不是其它模式,主要因为SVC模式比其他模式有更多的硬件访问权限,
    并且多了影子寄存器,可以访问的硬件资源更多,详情:http://www.360doc.com/content/13/0514/11/7245213_285318786.shtml */
    /* * 1.set the cpu to SVC32 mode */
    /*
    * MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
    * mrs :程序状态寄存器访问指令
    * 通用寄存器  程序状态寄存器(CPSR或SPSR)
    * 读取CPSR程序状态寄存器,保存到R0中
    */
      
    mrs    r0,cpsr
    /*
     * bic :BIC{条件}{S} 目的寄存器,操作数1,操作数2,
     * BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。操作数1应是一个寄存器
     * 操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2为32位的掩码,如果在掩码中设置了某一
     * 位,则清除这一位。未设置的掩码位保持不变。
     * 0x1f=00011111,相当于清除低5位,刚好是模式位。
     */ bic r0,r0,#
    0x1f

    /*
     * ORR{条件}{S} 目的寄存器,操作数1,操作数2
     * ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数
     * 2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1的某些位。
     * 0xd3=11010011
     * 将r0与0xd3算数或运算,然后将结果给r0,即把r0的bit[7:6]和bit[4]和bit[2:0]置为1。
     */
       orr    r0,r0,#0xd3
     /*
      * MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数
      * MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中
      * 将r0中的值赋给状态寄存器cpsr
      */
    msr cpsr,r0 /* 2.turn off the watchdog */ #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] /* * 3.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
      4.设置时钟
    /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ 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! */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit //5和6关闭MMU以及初始化SDRAM控制器 #endif #ifndef CONFIG_SKIP_RELOCATE_UBOOT 7.重定位
    relocate:
    /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address */ copy_loop: 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 #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
      adr 位置无关码,获取_start实际当前位于的地方,_TEXT_BASE 为 0x33f80000 ,这里判断的是代码是否直接运行在 sdram 里了,如果是就不需要重定位了。
        拷贝范围:_start 至 _bss_start 前,拷贝到 0x33f80000 处。

    /* 8.Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area */ 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 /* leave 3 words for abort-stack */
    9.清BSS段 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 ldr pc, _start_armboot
    /* 10.进入这个C函数后就属于第二阶段的代码了,汇编到此结束 */ _start_armboot: .word start_armboot

    cpu_init_crit分析

    /*
     *************************************************************************
     *
     * CPU_init_critical registers
     *
     * setup important registers
     * setup memory timing
     *
     *************************************************************************
     */
    
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    cpu_init_crit:
        
    关 I/D cache 关 TLB
       /* * 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 mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

    根据说明,可以在lowlevel_init.S中找到lowlevel_init的源码

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

    其中TEXT_BASE = 0x33F80000,在~/board/smdk2410/config.mk中有定义,其他一些宏的相关定义在~/include/configs/smdk2410.h 

    1. 设置SVC模式
    2. 关看门狗
    3. 屏蔽中断
    4. 设置时钟
    5. 关闭MMU
    6. 初始化SDRAM控制器
    7. 重定位(代码从FLASH拷贝到内存中)(怎么拷贝)
    8. 设置stack
    9. 清理BSS段()
    10. 调用start_armboot

    以上完成得是硬件相关初始化,称为uboot的第一阶段

  • 相关阅读:
    sge的简单的应用
    dcoker 小应用(二)
    浅谈Docker(二)
    查看Linux版本
    dcoker 小应用(一)
    linux 强制重启!
    浅谈Docker(一)
    ubuntu command
    简析hotjar录屏功能实现原理
    实现node端渲染图表的简单方案
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/11413200.html
Copyright © 2011-2022 走看看