uboot 源码导读 ARM (一) start.S

源码版本:u-boot-2012.04.01 官网下载版本。

 

#include <asm-offsets.h>
#include <config.h>
#include <version.h>
#include <asm/system.h>

.globl _start
_start: b    reset
    ldr    pc, _undefined_instruction      //设置arm的异常向量表
    ldr    pc, _software_interrupt
    ldr    pc, _prefetch_abort
    ldr    pc, _data_abort
    ldr    pc, _not_used
    ldr    pc, _irq
    ldr    pc, _fiq
#ifdef CONFIG_SPL_BUILD      
_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
_pad:            .word 0x12345678 /* now 16*4=64 */
#else
_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
_pad:            .word 0x12345678 /* now 16*4=64 */
#endif    /* CONFIG_SPL_BUILD */

.global _end_vect        //_end_vect中用.balignl来指定接下来的代码要16字节对齐,空缺的用0xdeadbeef,方便更加高效的访问内存
_end_vect:

    .balignl 16,0xdeadbeef
/*************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * setup Memory and board specific bits prior to relocation.
 * relocate armboot to ram
 * setup stack
 *
 *************************************************************************/

.globl _TEXT_BASE
_TEXT_BASE:
    .word    CONFIG_SYS_TEXT_BASE

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start_ofs
_bss_start_ofs:
    .word __bss_start - _start

.global    _image_copy_end_ofs
_image_copy_end_ofs:
    .word     __image_copy_end - _start

.globl _bss_end_ofs
_bss_end_ofs:
    .word __bss_end__ - _start

.globl _end_ofs
_end_ofs:
    .word _end - _start

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
    .word    0x0badc0de         //声明中断处理函数栈起始地址,值在运行时确定

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
    .word 0x0badc0de
#endif

/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
    .word    0x0badc0de

/*
 * the actual reset code
 */

reset:
    bl    save_boot_params       //空实现
    /*
     * set the cpu to SVC32 mode
     */
    mrs    r0, cpsr         //读cpsr寄存器
    bic    r0, r0, #0x1f
    orr    r0, r0, #0xd3
    msr    cpsr,r0         //写cpsr寄存器

#if !defined(CONFIG_TEGRA2)
/*
 * Setup vector:
 * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
 * Continue to use ROM code vector only in OMAP4 spl)
 */
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
    /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
    mrc    p15, 0, r0, c1, c0, 0    @ Read CP15 SCTRL Register
    bic    r0, #CR_V        @ V = 0
    mcr    p15, 0, r0, c1, c0, 0    @ Write CP15 SCTRL Register

    /* Set vector address in CP15 VBAR register */
    ldr    r0, =_start
    mcr    p15, 0, r0, c12, c0, 0    @Set VBAR
#endif
#endif    /* !Tegra2 */

    /* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT        //跳过底层初始化
    bl    cpu_init_cp15      //调用位置在本文件下方
                            //cpu_init_cp15函数是配置cp15协处理器相关寄存器来设置处理器的MMU,
                            //cache以及tlb。
                            //如果没有定义CONFIG_SYS_ICACHE_OFF则会打开icache。关掉mmu以及tlb。
    bl    cpu_init_crit      //调用位置在本文件下方
                            //cpu_init_crit调用的lowlevel_init函数是与特定开发板相关的初始化函数,
                            //在这个函数里会做一些pll初始化,如果不是从mem启动,
                            //则会做memory初始化,方便后续拷贝到mem中运行。
                           //lowlevel_init函数则是需要移植来实现,做clk初始化以及ddr初始化
#endif

/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
    bic    sp, sp, #7 /* 8-byte alignment for ABI compliance */
    ldr    r0,=0x00000000
    bl    board_init_f      //board_init_f函数主要是根据配置对全局信息结构体gd进行初始化。
 
/*------------------------------------------------------------------------------*/

/*
 * void relocate_code (addr_sp, gd, addr_moni)
 *
 * This "function" does not return, instead it continues in RAM
 * after relocating the monitor code.
 *
 */
    .globl    relocate_code
relocate_code:         //这个函数实现了将uboot code拷贝到relocaddr
    mov    r4, r0    /* save addr_sp */
    mov    r5, r1    /* save addr of gd */
    mov    r6, r2    /* save addr of destination */

    /* Set up the stack                            */
stack_setup:
    mov    sp, r4

    adr    r0, _start
    cmp    r0, r6
    moveq    r9, #0        /* no relocation. relocation offset(r9) = 0 */
    beq    clear_bss        /* skip relocation */
    mov    r1, r6            /* r1 <- scratch for copy_loop */
    ldr    r3, _image_copy_end_ofs
    add    r2, r0, r3        /* r2 <- source end address        */

copy_loop:          //uboot 拷贝到ram
    ldmia    r0!, {r9-r10}        /* copy from source address [r0]    */
    stmia    r1!, {r9-r10}        /* copy to   target address [r1]    */
    cmp    r0, r2            /* until source end address [r2]    */
    blo    copy_loop

#ifndef CONFIG_SPL_BUILD
    /*
     * fix .rel.dyn relocations
     */
    ldr    r0, _TEXT_BASE        /* r0 <- Text base */
    sub    r9, r6, r0        /* r9 <- relocation offset */
    ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
    add    r10, r10, r0        /* r10 <- sym table in FLASH */
    ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
    add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
    ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
    add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
fixloop:
    ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
    add    r0, r0, r9        /* r0 <- location to fix up in RAM */
    ldr    r1, [r2, #4]
    and    r7, r1, #0xff
    cmp    r7, #23            /* relative fixup? */
    beq    fixrel
    cmp    r7, #2            /* absolute fixup? */
    beq    fixabs
    /* ignore unknown type of fixup */
    b    fixnext
fixabs:
    /* absolute fix: set location to (offset) symbol value */
    mov    r1, r1, LSR #4        /* r1 <- symbol index in .dynsym */
    add    r1, r10, r1        /* r1 <- address of symbol in table */
    ldr    r1, [r1, #4]        /* r1 <- symbol value */
    add    r1, r1, r9        /* r1 <- relocated sym addr */
    b    fixnext
fixrel:
    /* relative fix: increase location by offset */
    ldr    r1, [r0]
    add    r1, r1, r9
fixnext:
    str    r1, [r0]
    add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
    cmp    r2, r3
    blo    fixloop
    b    clear_bss
_rel_dyn_start_ofs:
    .word __rel_dyn_start - _start
_rel_dyn_end_ofs:
    .word __rel_dyn_end - _start
_dynsym_start_ofs:
    .word __dynsym_start - _start

#endif    /* #ifndef CONFIG_SPL_BUILD */

clear_bss:
#ifdef CONFIG_SPL_BUILD
    /* No relocation for SPL */
    ldr    r0, =__bss_start
    ldr    r1, =__bss_end__
#else
    ldr    r0, _bss_start_ofs
    ldr    r1, _bss_end_ofs
    mov    r4, r6            /* reloc addr */
    add    r0, r0, r4
    add    r1, r1, r4
#endif
    mov    r2, #0x00000000        /* clear                */

clbss_l:str    r2, [r0]        /* clear loop...            */
    add    r0, r0, #4
    cmp    r0, r1
    bne    clbss_l

/*
 * We are done. Do not return, instead branch to second part of board
 * initialization, now running from RAM.
 */
jump_2_ram:
/*
 * If I-cache is enabled invalidate it
 */
#ifndef CONFIG_SYS_ICACHE_OFF
    mcr    p15, 0, r0, c7, c5, 0    @ invalidate icache
    mcr     p15, 0, r0, c7, c10, 4    @ DSB
    mcr     p15, 0, r0, c7, c5, 4    @ ISB
#endif
    ldr    r0, _board_init_r_ofs
    adr    r1, _start
    add    lr, r0, r1
    add    lr, lr, r9
    /* setup parameters for board_init_r */
    mov    r0, r5        /* gd_t */
    mov    r1, r6        /* dest_addr */
    /* jump to it ... */ //跳转执行board_init_r
    mov    pc, lr

_board_init_r_ofs:
    .word board_init_r - _start

/*************************************************************************
 *
 * cpu_init_cp15
 *
 * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
 * CONFIG_SYS_ICACHE_OFF is defined.
 *
 *************************************************************************/
.globl cpu_init_cp15
cpu_init_cp15:
    /*
     * Invalidate L1 I/D
     */
    mov    r0, #0            @ set up for MCR
    mcr    p15, 0, r0, c8, c7, 0    @ invalidate TLBs
    mcr    p15, 0, r0, c7, c5, 0    @ invalidate icache
    mcr    p15, 0, r0, c7, c5, 6    @ invalidate BP array
    mcr     p15, 0, r0, c7, c10, 4    @ DSB
    mcr     p15, 0, r0, c7, c5, 4    @ ISB

    /*
     * disable MMU stuff and caches
     */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, r0, #0x00002000    @ clear bits 13 (--V-)
    bic    r0, r0, #0x00000007    @ clear bits 2:0 (-CAM)
    orr    r0, r0, #0x00000002    @ set bit 1 (--A-) Align
    orr    r0, r0, #0x00000800    @ set bit 11 (Z---) BTB
#ifdef CONFIG_SYS_ICACHE_OFF
    bic    r0, r0, #0x00001000    @ clear bit 12 (I) I-cache
#else
    orr    r0, r0, #0x00001000    @ set bit 12 (I) I-cache
#endif
    mcr    p15, 0, r0, c1, c0, 0
    mov    pc, lr            @ back to my caller


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************/
cpu_init_crit:
    /*
     * Jump to board specific initialization...
     * The Mask ROM will have already initialized
     * basic memory. Go here to bump up clock rate and handle
     * wake up conditions.
     */
    mov    ip, lr            @ persevere link reg across call
    bl    lowlevel_init        @ go setup pll,mux,memory
    mov    lr, ip            @ restore link
    mov    pc, lr            @ back to my caller
#endif

#ifndef CONFIG_SPL_BUILD
/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE    72

#define S_OLD_R0    68
#define S_PSR        64
#define S_PC        60
#define S_LR        56
#define S_SP        52

#define S_IP        48
#define S_FP        44
#define S_R10        40
#define S_R9        36
#define S_R8        32
#define S_R7        28
#define S_R6        24
#define S_R5        20
#define S_R4        16
#define S_R3        12
#define S_R2        8
#define S_R1        4
#define S_R0        0

#define MODE_SVC 0x13
#define I_BIT     0x80

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */

    .macro    bad_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE        @ carve out a frame on current
                        @ user stack
    stmia    sp, {r0 - r12}            @ Save user registers (now in
                        @ svc mode) r0-r12
    ldr    r2, IRQ_STACK_START_IN        @ set base 2 words into abort
                        @ stack
    ldmia    r2, {r2 - r3}            @ get values for "aborted" pc
                        @ and cpsr (into parm regs)
    add    r0, sp, #S_FRAME_SIZE        @ grab pointer to old stack

    add    r5, sp, #S_SP
    mov    r1, lr
    stmia    r5, {r0 - r3}            @ save sp_SVC, lr_SVC, pc, cpsr
    mov    r0, sp                @ save current stack into r0
                        @ (param register)
    .endm

    .macro    irq_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0-r12
    add    r8, sp, #S_PC            @ !! R8 NEEDS to be saved !!
                        @ a reserved stack spot would
                        @ be good.
    stmdb    r8, {sp, lr}^            @ Calling SP, LR
    str    lr, [r8, #0]            @ Save calling PC
    mrs    r6, spsr
    str    r6, [r8, #4]            @ Save CPSR
    str    r0, [r8, #8]            @ Save OLD_R0
    mov    r0, sp
    .endm

    .macro    irq_restore_user_regs
    ldmia    sp, {r0 - lr}^            @ Calling r0 - lr
    mov    r0, r0
    ldr    lr, [sp, #S_PC]            @ Get PC
    add    sp, sp, #S_FRAME_SIZE
    subs    pc, lr, #4            @ return & move spsr_svc into
                        @ cpsr
    .endm

    .macro get_bad_stack
    ldr    r13, IRQ_STACK_START_IN        @ setup our mode stack (enter
                        @ in banked mode)

    str    lr, [r13]            @ save caller lr in position 0
                        @ of saved stack
    mrs    lr, spsr            @ get the spsr
    str    lr, [r13, #4]            @ save spsr in position 1 of
                        @ saved stack

    mov    r13, #MODE_SVC            @ prepare SVC-Mode
    @ msr    spsr_c, r13
    msr    spsr, r13            @ switch modes, make sure
                        @ moves will execute
    mov    lr, pc                @ capture return pc
    movs    pc, lr                @ jump to next instruction &
                        @ switch modes.
    .endm

    .macro get_bad_stack_swi
    sub    r13, r13, #4            @ space on current stack for
                        @ scratch reg.
    str    r0, [r13]            @ save R0's value.//'''
    ldr    r0, IRQ_STACK_START_IN        @ get data regions start
                        @ spots for abort stack
    str    lr, [r0]            @ save caller lr in position 0
                        @ of saved stack
    mrs    r0, spsr            @ get the spsr
    str    lr, [r0, #4]            @ save spsr in position 1 of
                        @ saved stack
    ldr    r0, [r13]            @ restore r0
    add    r13, r13, #4            @ pop stack entry
    .endm

    .macro get_irq_stack            @ setup IRQ stack
    ldr    sp, IRQ_STACK_START
    .endm

    .macro get_fiq_stack            @ setup FIQ stack
    ldr    sp, FIQ_STACK_START
    .endm

/*
 * exception handlers
 */
    .align    5
undefined_instruction:
    get_bad_stack
    bad_save_user_regs
    bl    do_undefined_instruction

    .align    5
software_interrupt:
    get_bad_stack_swi
    bad_save_user_regs
    bl    do_software_interrupt

    .align    5
prefetch_abort:
    get_bad_stack
    bad_save_user_regs
    bl    do_prefetch_abort

    .align    5
data_abort:
    get_bad_stack
    bad_save_user_regs
    bl    do_data_abort

    .align    5
not_used:
    get_bad_stack
    bad_save_user_regs
    bl    do_not_used

#ifdef CONFIG_USE_IRQ

    .align    5
irq:
    get_irq_stack
    irq_save_user_regs
    bl    do_irq
    irq_restore_user_regs

    .align    5
fiq:
    get_fiq_stack
    /* someone ought to write a more effective fiq_save_user_regs */
    irq_save_user_regs
    bl    do_fiq
    irq_restore_user_regs

#else

    .align    5
irq:
    get_bad_stack
    bad_save_user_regs
    bl    do_irq

    .align    5
fiq:
    get_bad_stack
    bad_save_user_regs
    bl    do_fiq

#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */

 

posted @ 2015-04-07 22:47  JustRelax  阅读(1036)  评论(0)    收藏  举报