#include <config.h>
#include <version.h>
//global聲明一個符号可被其他文檔引用,相當于聲明了一個全局變量,.globl和.global相同。
//該部分為處理器的異常處理向量表。位址範圍為0x0000 0000 ~ 0x0000 0020,剛好8條指令。
.globl _start //u-boot啟動入口
_start: b reset //複位向量并且跳轉到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
// 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
// 聲明_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
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
// 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
// 這幾條指令執行完畢後,進入SVC32模式,該模式主要用來處理軟體中斷(SWI)
reset:
mrs r0,cpsr //将CPSR狀态寄存器讀取,儲存到R0中
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 //将R0寫入狀态寄存器中
//關閉看門狗
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014
#endif #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
//關閉所有中斷
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
// B 轉移指令,跳轉到指令中指定的目的位址
// BL 帶連結的轉移指令,像B相同跳轉并把轉移後面緊接的一條指令位址儲存到連結寄存器LR(R14)中,以此來完成子程式的調用
// 該語句首先調用cpu_init_crit進行CPU的初始化,并把下一條指令的位址儲存在LR中,以使得執行完後能夠正常傳回。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#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/smdk2410/config.mk中
relocate:
adr r0, _start
ldr r1, _TEXT_BASE
cmp r0, r1
beq stack_setup //重新定位代碼
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2
add r2, r0, r2 copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
#endif
//初始化堆棧
stack_setup:
ldr r0, _TEXT_BASE
sub r0, r0, #CFG_MALLOC_LEN
sub r0, r0, #CFG_GBL_DATA_SIZE
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 clear_bss:
ldr r0, _bss_start
ldr r1, _bss_end
mov r2, #0x00000000 clbss_l:str r2, [r0]
add r0, r0, #4
cmp r0, r1
ble clbss_l #if 0
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
mov r1, #0xffffffff
ldr r0, =INTMR
str r1, [r0]
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif //跳轉到start_armboot函數入口,_start_armboot字儲存函數入口指針
ldr pc, _start_armboot _start_armboot: .word start_armboot //start_armboot函數在lib_arm/board.c中實作
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
//初始化CACHE
mov r0, #0
mcr p15, 0, r0, c7, c7, 0
mcr p15, 0, r0, c8, c7, 0
//關閉MMU和CACHE
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
//初始化RAM時鐘。因為記憶體時鐘是依賴開發闆硬體的,是以在board的相應目錄下可以找到memsetup.s檔案
mov ip, lr
bl lowlevel_init //lowlevel_init子程式在board/smdk2410/memsetup.s中實作
mov lr, ip
mov pc, lr
#endif @
@ 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 .macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
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 - r3} @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm .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
msr spsr, 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
.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
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