u-boot源码分析第一阶段之Start.S

时间:2021-02-01 04:04:10

                        u-boot之源码分析阶段一

                           --Edison Gao

//u-boot.1.1.6

//u-boot1.1.6/cpu/arm920t/start.S

u-boot顶层目录有很多子目录,下面介绍一些主要的目录

(1)arch:对应不同架构的cpu,子目录的名字就是所支持的cpu框架的名称,如arch目录下含有arm,arv32以及x86等,这些目录可以继续细分。例如arm下含有cpu,include和lib等目录,其中cpu用于区分不同体系的arm内核

(2)common:该目录存在的是一些公共的通用代码文件,包括用于实现各种公共命令的cmd_*.c,env_*.c文件以及一些通用函数。它们独立于处理器的体系架构,直接跟客户打交道,是用户与设备驱动之间沟通的纽带,也是U-Boot的精髓所在

(3)drivers:该目录存放的是各类外设的驱动程序,如mmc,serial,和net等。

(4)fs:支持文件系统

(5)net:该目录里面的文件实现了各种网络协议

(6)nand_apl:实现U-Boot从Nand Flash中启动的设备驱动。

(7)include:一些头文件和单板配置文件,所有单板配置的文件位于include/configs目录下。

(8)tools:常用工具,包括用于制作uImage和mkimage工具。

(9)Makefile:控制整个工程的编译


一:设置ARM工作模式

那么我们首先分析u-boot的启动过程(Start.S),一般都是以汇编语言编写

b:跳转指令

bl:带返回的跳转指令

bx:带状态切换的跳转指令

blx:带返回和状态切换的跳转指令

.globl _start
_start:    b       reset     //跳转到reset
    ldr    pc, _undefined_instruction  //未定义指令异常
    ldr    pc, _software_interrupt    //软中断,一般用于Linux系统的系统调用,就是从用户模式进入保护模式 后者进入超级用户模式
    ldr    pc, _prefetch_abort  //预取止终止   CPU取不到下一条指令
    ldr    pc, _data_abort   //cpu取不到值
    ldr    pc, _not_used
    ldr    pc, _irq  //一般中断  
    ldr    pc, _fiq  //快中断   u-boot中遇不到 ,我们可以不需要分析

_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

    .balignl 16,0xdeadbeef

跳转到reset函数,这里对reset分析
reset:
    /*
     * set the cpu to SVC32 mode  设置cpu到svc32模式   即管理员模式
     */
    mrs    r0,cpsr    //读状态寄存器指令,将寄存器cpsr读取到r0中
    bic    r0,r0,#0x1f  //位清除指令 清除r0寄存器的低6位 ,将r0寄存器的低6位置0
    orr    r0,r0,#0xd3  //将r0寄存器与0x11010011 或运算
    msr    cpsr,r0      //写状态寄存器指令,即cpsr = 0x11010011

/* cpsr的低八位为0x11010011
第7位,即为I位,当i=1时禁止IRQ中断
第6位,即为F位,当F=1时禁止FIQ中断
第5位,即为T位,当T=1时执行ARM指令;T=0时执行Thumb指令
低5位,即为0x13,为管理员模式*/

这样我们就把arm设置为管理模式(svc)。


二:关闭看门狗

  

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)    //关闭看门狗

# define pWTCON        0x53000000
# define INTMOD     0X4A000004
# define INTMSK        0x4A000008    /* Interupt-Controller base addresses */
# define INTSUBMSK    0x4A00001C
# define CLKDIVN    0x4C000014    /* clock divisor register */

    ldr     r0, =pWTCON  // 将pWTCON地址放入r0寄存器中
    mov     r1, #0x0    
    str     r1, [r0]   //将r1寄存器的值放入r0地址中

三:屏蔽所有中断

    mov    r1, #0xffffffff  //屏蔽所有中断 r1 = 0xffffffff,
    ldr    r0, =INTMSK    //将地址INTMSK值加载入r0寄存器中
    str    r1, [r0]     //将r1的值放入r0寄存器中  即INTMSK=0xffffffff
# if defined(CONFIG_S3C2410)
    ldr    r1, =0x3ff
    ldr    r0, =INTSUBMSK
    str    r1, [r0]      //类似  地址INTSUBMSK = 0x3ff

四:时钟初始化

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr    r0, =CLKDIVN
    mov    r1, #3
    str    r1, [r0]    // CLKDIVN = 0x2  分频  FCLK:HCLK:PCLK = 1:2:4

五:CPU初始化

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    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判断两个地址是否相等证明sdram又没被初始化*/
    blne    cpu_init_crit     //bl是跳转命令,ne是不相等执行,这句的意思的cspr寄存器的Z标志位为1时执行跳转

cpu_init_crit:  
    /*
     * flush v4 I/D caches  cashes初始化
     */
    mov    r0, #0  //将0这个立即数加载到r0寄存器中
    mcr    p15, 0, r0, c7, c7, 0//r0是ARM处理器的寄存器,c7是协处理器的寄存器,第一个0是操作码1,第二个0时操作码2,此处是将c7写入0,使ICache与DCache失效/* flush v3/v4 cache */
    mcr    p15, 0, r0, c8, c7, 0//将c8写入0,使TLB失效    /* flush v4 TLB */

    /*
     * disable MMU stuff and caches   关闭mmu和cashes
     */
    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)   //CPU为小字节序,关闭Dcaches,数据访问时不进行地址对齐检查,关闭mmu  
    orr    r0, r0, #0x00000002    @ set bit 2 (A) Align    //数据访问时进行地址对齐检查
    orr    r0, r0, #0x00001000    @ set bit 12 (I) I-Cache  //开启Icaches
    mcr    p15, 0, r0, c1, c0, 0    //将c1写入0  ,,关闭mmu,caches

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

五:设置栈

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

六:将代码从flash读到SDRAM中

我们可以了解,对于2440

上电后,2440的iROM的代码会先运行  即干了两件事

a.初始化时钟,关闭看门狗之类

b.将flash的头4k内存加载到片内内存中,这4k代码主要是配置好sdram,然后bootloder的大部分再到sdram中

relocate:                /* relocate U-Boot to RAM        */   //把代码从flash读到sdram里面去
    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     clear_bss
    ldr    r2, _armboot_start
    ldr    r3, _bss_start
    sub    r2, r3, r2        /* r2 <- size of armboot            */
#if 1
    bl  CopyCode2Ram    /* r0: source, r1: dest, r2: size */
#else
    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

七:清bss段

      clear_bss:
    ldr    r0, _bss_start        /* find start of bss segment        */   //清BSS段 全部清0
    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


最后的代码是一些异常处理函数。这里就不一 一探讨了


下一节我们会继续分析源码第二阶段