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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章