#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
U-boot-13.0-rc3 cpu/pxa/start.S 分析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.