u-boot启动过程之STEP1

时间:2022-03-09 19:33:36

u-boot启动过程之STEP1

1, 初始化中断向量表,正常情况下,直接跳转到reset

.globl _start
_start: b       reset
    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

_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

2. 进入reset后,初始化CPU,使其进入SVreset:

/* * set the cpu to SVC32 mode */
mrsr0,cpsr
bicr0,r0,#0x1f
orrr0,r0,#0xd3
msrcpsr,r0

3. 关看门狗

# 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
    mov     r1, #0x0
    str     r1, [r0]

4. 屏蔽中断

mov r1, #0xffffffff
    ldr r0, =INTMSK
    str r1, [r0]
# if defined(CONFIG_S3C2410)
    ldr r1, =0x3ff
    ldr r0, =INTSUBMSK
    str r1, [r0]
# endif

5. 判断当前是否运行在SDRAM上,若没有运行在SDRAM上,则进行CPU底层的一些初始化:

5.1 获取_start的相对于PC的地址,赋值给r0,获取_start在编译时的链接地址赋值给r1。比较r0和r1。若不相等,则表示,当前程序运行在非SDRAM区,则调用cpu_init_crit函数。

#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 */
    blne    cpu_init_crit
#endif

5.2 使无效整个cache和TLB

Caches是CPU内部的一个2级缓存,它的作用是将常用的数据和指令放在CPU内部。Caches是通过CP15管理的,刚上电的时候,CPU还不能管理Caches。上电的时候指令Cache可关闭,也可不关闭,但数据Cache一定要关闭,否则可能导致刚开始的代码里面,去取数据的时候,从Cache里面取,而这时候RAM中数据还没有Cache过来,导致数据预取异常。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
    /* * flush v4 I/D caches */
    mov r0, #0
    mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache,使无效整个cache */
    mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB,使无效整个TLB */

    /* * disable MMU stuff and caches * C1寄存器的格式可以参考 * [http://blog.csdn.net/skyflying2012/article/details/25823967](http://blog.csdn.net/skyflying2012/article/details/25823967) */
     //读C1的内容到r0
    mrc p15, 0, r0, c1, c0, 0
    //清R,S,V,选择0x00000000-0x0000001c作为异常中断向量表的位置。
    bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
    //禁止MMU,禁止数据cache,存储系统选择小端模式
    bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
    //开启内存访问时地址对其检查的功能
    orr r0, r0, #0x00000002 @ set bit 2 (A) Align
    //使能指令cache
    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  @调用lowlevel_init函数
    mov lr, ip
    mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

5.3 lowlevel_init函数,初始化ARM的BANK区

_TEXT_BASE:
    .word   TEXT_BASE

.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 0xb1
    .word 0x30
    .word 0x30

6. 初始化栈,初始化后,SDRAM中的一部分内存分配是:

_TEXT_BASE –> MALLOC –> GBL_DATA –> Stack of IRQ and FIQ –> abord stack –> sp

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

7. 初始化时钟,提高时钟频率,加快程序的执行速度。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl clock_init
#endif 
void clock_init(void)
{
    S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;
 /* FCLK:HCLK:PCLK = 1:4:8 */
        clk_power->CLKDIVN = S3C2440_CLKDIV;

        /* change to asynchronous bus mod */
        __asm__(    "mrc p15, 0, r1, c1, c0, 0\n"    /* read ctrl register   */  
                    "orr r1, r1, #0xc0000000\n"      /* Asynchronous         */  
                    "mcr p15, 0, r1, c1, c0, 0\n"    /* write ctrl register  */  
                    :::"r1"
                    );

        /* to reduce PLL lock time, adjust the LOCKTIME register */
        clk_power->LOCKTIME = 0xFFFFFFFF;

        /* configure UPLL */
        clk_power->UPLLCON = S3C2440_UPLL_48MHZ;

        /* some delay between MPLL and UPLL */
        delay (4000);

        /* configure MPLL */
        clk_power->MPLLCON = S3C2440_MPLL_400MHZ;

        /* some delay between MPLL and UPLL */
        delay (8000);
}

8. 将u-boot的源码从FLASH区复制到SDRAM

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     clear_bss

    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot */

    bl  CopyCode2Ram    /* r0: source, r1: dest, r2: size */

//根据ATPCS,
//start_addr是当前运行时_start的地址
//*buf指向SDRAM上代码段的起始地址
//size是u-boot程序的大小

int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
    unsigned int *pdwDest;
    unsigned int *pdwSrc;
    int i;

    if (bBootFrmNORFlash())
    {
        pdwDest = (unsigned int *)buf;
        pdwSrc  = (unsigned int *)start_addr;
        /* 从 NOR Flash启动 */
        for (i = 0; i < size / 4; i++)
        {
            pdwDest[i] = pdwSrc[i];
        }
        return 0;
    }
    else
    {
        /* 初始化NAND Flash */
        nand_init_ll();
        /* 从 NAND Flash启动 */
        nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));
        return 0;
    }
}
int bBootFrmNORFlash(void)
{
    volatile unsigned int *pdw = (volatile unsigned int *)0;
    unsigned int dwVal;

    /* * 无论是从NOR Flash还是从NAND Flash启动, * 地址0处为指令"b Reset", 机器码为0xEA00000B, * 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中, * 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。 * 对于NOR Flash,必须通过一定的命令序列才能写数据, * 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动: * 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash */

    dwVal = *pdw;       
    *pdw = 0x12345678;
    if (*pdw != 0x12345678)
    {
        return 1;
    }
    else
    {
        *pdw = dwVal;
        return 0;
    }
}

9. 将BSS段清零.

BSS段包含了程序中未初始化全局变量,在内存中 bss段全部置零。BSS是block started by symbol的缩写。因为未初始化的变量没有对应的值,所以并不需要存储在可执行对象中。但是因为C标准强制规定未初始化的全局变量要被赋予特殊的默认值(基本上是0值),所以内核要从可执行代码装入变量(未赋值的)到内存中,然后将零页映射到该片内存上,于是这些未初始化变量就被赋予了0值。这样做避免了在目标文件中进行显式地初始化,减少空间浪费。

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

10, 跳转到start_armboot中,开始执行STEP2部分。

    ldr pc, _start_armboot

_start_armboot: .word start_armboot