U-boot-13.0-rc3 cpu/pxa/start.S 分析

#include
#include
//global声明一个符号可被其他文件引用,相当于声明了一个全局变量,.globl和.global相同。
//该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。
.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
// .word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long和.int作用和之相同。
_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
// .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign的作用同.align。
// .align {alignment} {,fill} {,max}
//  其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0填充。max是填充字节数最大值,如果填充字节数超过max,
//  就不进行对齐,例如:
//  .align 4  /* 指定对齐方式为字对齐 */
    .balignl 16,0xdeadbeef
/*
* Startup Code (reset vector)
*
* do important init only if we don’t start from RAM!
* - relocate armboot to ram
* - setup stack
* - jump to second stage
*/
// TEXT_BASE在研发板相关的目录中的config.mk文件中定义, 他定义了
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
_TEXT_BASE:
    .word    TEXT_BASE
// 声明 _armboot_start 并用 _start 来进行初始化,在board/u-boot.lds中定义。
.globl _armboot_start
_armboot_start:
    .word _start
/*
* These are defined in the board-specific linker script.
*/
// 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在和板相关的u-boot.lds中。
// _bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在
// 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时
// 地址的影响. _bss_end也是同样的道理.
.globl _bss_start
_bss_start:
    .word __bss_start
// 同上
.globl _bss_end
_bss_end:
    .word _end
#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
/****************************************************************************/
/*                                        */
/* the actual reset code                            */
/*                                        */
/****************************************************************************/
//  MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd
//  使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样能最佳地完成对CRSP或SPSR的修改
//  MSR {} CPSR_|SPSR_,Rm 或是 MSR {} CPSR_f|SPSR_f,#
//  MRS和MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分
//   bic r0,r1,r2  ;r0:=r1 and not r2
//   orr ro,r1,r2  ;r0:=r1 or r2
//  这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI)
reset:
    mrs    r0,cpsr        /* set the cpu to SVC32 mode        */
    bic    r0,r0,#0x1f        /* (superviser mode, M=10011)        */
    orr    r0,r0,#0x13
    msr    cpsr,r0
    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
//
// B----转移指令,跳转到指令中指定的目的地址
// BL---带链接的转移指令,像B相同跳转并把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程式的调用
// 该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。
//
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl    cpu_init_crit        /* we do sys-critical inits        */
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
//调试阶段的代码是直接在RAM中运行的,而最后需要把这些代码固化到Flash中,因此U-Boot需要自己从Flash转移到
//RAM中运行,这也是重定向的目的所在。
//通过adr指令得到当前代码的地址信息:如果U-boot是从RAM开始运行,则从adr,r0,_start得到的地址信息为
//r0=_start=_TEXT_BASE=TEXT_BASE=0xa3000000;如果U-boot从Flash开始运行,即从处理器对应的地址运行,
//则r0=0x0000,这时将会执行copy_loop标识的那段代码了。
// _TEXT_BASE 定义在board/pxa255_idp/config.mk中
relocate:                /* relocate U-Boot to RAM        */
    adr    r0, _start        /* r0 中,用来进行芯片选择,Monahans是XScale PXA27X系列的新成员*/
    /* mask all IRQs     */
#ifndef CONFIG_CPU_MONAHANS   
    ldr    r0, IC_BASE      
    mov    r1, #0x00
    str    r1, [r0, #ICMR]
#else
    /* Step 1 - Enable CP6 permission */
    mrc    p15, 0, r1, c15, c1, 0 @ read CPAR
    orr    r1, r1, #0x40
    mcr    p15, 0, r1, c15, c1, 0
    CPWAIT    r1
    /* Step 2 - Mask ICMR & ICMR2 */
    mov    r1, #0
    mcr    p6, 0, r1, c1, c0, 0    @ ICMR
    mcr    p6, 0, r1, c7, c0, 0    @ ICMR2
    /* turn off all clocks but the ones we will definitly require */
    ldr    r1, =CKENA
    ldr    r2, =(CKENA_22_FFUART | CKENA_10_SRAM | CKENA_9_SMC | CKENA_8_DMC)
    str    r2, [r1]
    ldr    r1, =CKENB
    ldr    r2, =(CKENB_6_IRQ)
    str    r2, [r1]
#endif
    /* set clock speed   设置时钟*/
#ifdef CONFIG_CPU_MONAHANS
    ldr    r0, =ACCR
    ldr    r1, =(((CFG_MONAHANS_TURBO_RUN_MODE_RATIO<<8) & ACCR_XN_MASK) | (CFG_MONAHANS_RUN_MODE_OSC_RATIO & ACCR_XL_MASK))
    str    r1, [r0]
#else /* ! CONFIG_CPU_MONAHANS */
#ifdef CFG_CPUSPEED
    ldr    r0, CC_BASE       //0x41300000
    ldr    r1, cpuspeed        //cpuspeed = CFG_CPUSPEED
    str    r1, [r0, #CCCR]   //CCCR = 0x00
    mov    r0, #2
    mcr    p14, 0, r0, c6, c0, 0  //进入频率变化顺序
setspeed_done:
#endif /* CFG_CPUSPEED */
#endif /* CONFIG_CPU_MONAHANS */
    /*
     * 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
    /* Memory interfaces are working. Disable MMU and enable I-cache.   */
    /* mk: hmm, this is not in the monahans docs, leave it now but
     *     check here if it doesn’t work :-) */
    ldr    r0, =0x2001        /* enable access to all coproc.        */
    mcr    p15, 0, r0, c15, c1, 0
    CPWAIT r0
    mcr    p15, 0, r0, c7, c10, 4    /* drain the write & fill buffers   */
    CPWAIT r0
    mcr    p15, 0, r0, c7, c7, 0    /* flush Icache, Dcache and BTB        */
    CPWAIT r0
    mcr    p15, 0, r0, c8, c7, 0    /* flush instuction and data TLBs   */
    CPWAIT r0
    /* Enable the Icache                            */
/*
    mrc    p15, 0, r0, c1, c0, 0
    orr    r0, r0, #0x1800
    mcr    p15, 0, r0, c1, c0, 0
    CPWAIT
*/
    mov    pc, lr
/****************************************************************************/
/*                                        */
/* 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
    /* use bad_save_user_regs for abort/prefetch/undef/swi ...        */
    .macro    bad_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            /* Calling r0-r12        */
    add    r8, sp, #S_PC
    ldr    r2, _armboot_start
    sub    r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub    r2, r2, #(CFG_GBL_DATA_SIZE+8)    @ set base 2 words into abort stack
    ldmia    r2, {r2 - r4}            /* get pc, cpsr, old_r0        */
    add    r0, sp, #S_FRAME_SIZE        /* restore sp_SVC        */
    add    r5, sp, #S_SP
    mov    r1, lr
    stmia    r5, {r0 - r4}            /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
    mov    r0, sp
    .endm
    /* use irq_save_user_regs / irq_restore_user_regs for             */
    /* IRQ/FIQ handling                             */
    .macro    irq_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            /* Calling r0-r12         */
    add    r8, sp, #S_PC
    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, _armboot_start        @ setup our mode stack
    sub    r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub    r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
    str    lr, [r13]            @ save caller lr / spsr
    mrs    lr, spsr
    str    lr, [r13, #4]
    mov    r13, #MODE_SVC        @ prepare SVC-Mode
    msr    spsr_c, r13
    mov    lr, pc
    movs    pc, lr
    .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
    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
    irq_save_user_regs        /* someone ought to write a more    */
    bl    do_fiq            /* effiction fiq_save_user_regs        */
    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
/****************************************************************************/
/*                                        */
/* Reset function: the PXA250 doesn’t have a reset function, so we have to  */
/* perform a watchdog timeout for a soft reset.                    */
/*                                       
The processor contains a 32-bits OS timer that is clocked by the 3.864 MHZ
oscillator.The Operating System Count register(OSCR) is a free running
up-counter.The OS timer also contains four 32-bit match registers (OSMR3,
OSMR2,OSMR1,OSMR0).Developers can read and write to each register.
When the value in the OSCR is equal to the value within any of the match
register,and the interrupt enable bit is set,the corresponding bit in the
OSSR is set.These bits are also routed to the interrupt controller where they
can be programmed to cause an interrupt. OSMR3 also serves as a watchdog match
register that resets the processor when a match occurs provided the OS Timer
Watchdog Match Enable Register(OWER) is set.You must initialize the OSCR and
OSMR registers and clear any set status bits before the FIQ and IRQ interrupts
are enabled within the CPU
/****************************************************************************/
    .align    5
.globl reset_cpu
    /* FIXME: this code is PXA250 specific. How is this handled on        */
    /*      other XScale processors?                    */
reset_cpu:
/***************************************************************************
* This bit is set by writing a one to it and can only be cleared by
* one of the reset functions such as,hardware reset,sleep reset,watchdog
* reset,and GPIO reset
* 只有最低位可进行设置<31:1>不能设置
* 0-----OSMR3 match will not cause a reset of the processor
* 1-----OSMR3 match will cause a reset of the processor
****************************************************************************/
    /* We set OWE:WME (watchdog enable) and wait until timeout happens  */
    ldr    r0, OSTIMER_BASE            //0x40a00000
    ldr    r1, [r0, #OWER]            //OWER OS Timer Watchdog Enable Register
    orr    r1, r1, #0x0001            /* bit0: WME            */
    str    r1, [r0, #OWER]
    /* OS timer does only wrap every 1165 seconds, so we have to set    */
    /* the match register as well.                        */
    ldr    r1, [r0, #OSCR]            /* read OS timer OSCR:OS Timer Counter Register */
    add    r1, r1, #0x800            /* let OSMR3 match after    */
    add    r1, r1, #0x800            /* 4096*(1/3.6864MHz)=1ms   */
    str    r1, [r0, #OSMR3]
reset_endless:
    b    reset_endless

你可能感兴趣的:(c,timer,user,Flash,alignment,linker)