以下是bootstrap的啓動過程,主要分爲兩個步驟:
第一階段:彙編程序,主要負責最低層的硬件初始化
第二階段:c程序,主要負責SDRAM初始化,Dataflash的拷貝工作,完成程序在SDRAM中運行的準備工作
第一階段主要是在crt0_gnu.S中,和前面的鏈接腳本文件有很大關係()
crt0_gnu.S的彙編程序是bootstrap的第一階段執行過程:
主要實現的目的是:
1 建立中斷向量表(_exception_vectors:在此標號處)
2 設置堆棧SP(代碼在內部SRAM0中運行,堆棧在內部SRAM1中運行。啓動過程是cpu啓動後先檢測外部的dataflash,有接,則拷貝dataflash從0開始的4K字節到內部SRAM1中,開始執行)
(_init_stack:在此處)
3 主晶振使能爲主時鐘(設置時鐘_setup_clocks: 使能主晶振_enable_mosc: 打開主晶振_switch_to_mosc: )
4 數據段拷貝 (_init_data:)
5 BSS段數據初始化(_init_bss:)
6 底層基本初始化完成,跳轉到C代碼的MAIN函數中執行(_branch_main:)
至此bootstrap第一階段彙編代碼的任務執行完畢。接下來執行C代碼。
以下是彙編代碼的詳細註釋:
.sectionstart 定義域中包含的段
.text 代碼段開始
#include"include/part.h" 包含頭文件,供編譯使用
/*----------------------------------------------------------------------------
Area Definition 區域定義
Must be defined as function to put first inthe code as it must be mapped
at offset 0 of the flash EBI_CSR0, ie. ataddress 0 before remap.必須先定義一個函數進入第一段代碼必須映射到flash(EBI_CSR0)的偏移0地址處例如地址重映射後在0地址
--------------------------------------------------------------------------*/
/*Application startup entry point */應用程序開始進入點
.globl reset 定義全局符號
.align 4 以下以4字節對齊
reset:
//Exception vectors (should be a branch to be detected as a valid code by the rom異常向量表8個
_exception_vectors:
b reset_vector /* reset */
b undef_vector /* Undefined Instruction */
b swi_vector /*Software Interrupt */
b pabt_vector /*Prefetch Abort */
b dabt_vector /* DataAbort */
.word _edata /* Size of the image for SAM-BA */
b irq_vector /* IRQ : read the AIC */
b fiq_vector /* FIQ */
undef_vector:
b undef_vector
swi_vector:
b swi_vector
pabt_vector:
b pabt_vector
dabt_vector:
b dabt_vector
rsvd_vector:
b rsvd_vector
irq_vector:
b irq_vector
fiq_vector:
b fiq_vector
reset_vector:
/*Init the stack */堆棧初始化
_init_stack:
ldr sp,=TOP_OF_MEM //TOP_OF_MEMORY=0x301000
//在Makefile文件中的# Link Address andTop_of_Memory
//LINK_ADDR=0x20 0000 內部SRAM0 的起始位置 0x20 0000 共4k
//TOP_OF_MEMORY=0x30 1000 內部SRAM1的起始位置 0x30 1000 共4K
#ifdef CFG_NORFLASH //NORFLASH啓動時要使用的代碼段,本次移植使用的是DATAFLASH
/* When running from NOR, we must relocate to SRAM prior toresetting the clocks and SMC timings. */
_relocate_to_sram:
#if 0
/*relocation is slow, disable the watchdog or it will trigger */
ldr r1, =0xFFFFFD44
mov r2, #0x00008000
str r2, [r1]
#endif
mov r1, #0
ldr r3, =_stext
ldr r4, =_edata
1:
cmp r3, r4
ldrcc r2, [r1], #4
strcc r2, [r3], #4
bcc 1b
ldr pc, =_setup_clocks
#endif /* CFG_NORFLASH */
_setup_clocks: 設置時鐘寄存器
/*Test if main oscillator is enabled */測試主晶振是否使能
ldr r0,=AT91C_PMC_SR // (PMC) Status Register 0xFFFFFC68
ldr r1,[r0] //將狀態寄存器中的值讀出到R1
ldr r2,=AT91C_PMC_MOSCS //R2= (0x1 << 0)
ands r1, r1, r2 //R1=R1與R2 判斷主晶振是否起振了
// r1=1 則晶振已經啓動 r1=0則晶振未啓動
bne _switch_to_mosc //未起振,則繼續執行函數_enable_mosc執行啓動主晶振
bne不等於 則跳轉
/*Enable the main oscillator */使能主晶振
_enable_mosc:
ldr r0,=AT91C_PMC_MOR // (PMC) Main Oscillator Register(0xFFFFFC20)
mov r1,#(0x40 << 8)
ldr r2,=AT91C_CKGR_MOSCEN // (CKGR) Main Oscillator Enable(0x1<< 0)
orr r1,r1, r2 // r1,=r1或 r2
str r1,[r0] //將r1的值寫入寄存器 AT91C_PMC_MOR
ldr r0,=AT91C_PMC_SR // (PMC) Status Register(0xFFFFFC68)
1:
ldr r1,[r0] //寄存器的值讀出到R1中
ldr r2,=AT91C_PMC_MOSCS //0x1 << 0) (PMC) MOSCStatus/Enable/Disable/Mask
ands r1, r1, r2 //R1=R1與R2
beq 1b //如果等於0,就繼續循環檢測,爲1爲止說明晶振已啓動跳到下面函數處理
/*Test if MCK == SLOW CLOCK */
_switch_to_mosc: // 到此函數說明主晶振已起振
ldr r0,=AT91C_PMC_MCKR // (PMC) Master Clock Register(0xFFFFFC30)
ldr r1,=AT91C_PMC_CSS //(PMC) Programmable Clock Selection(0x3 << 0)
ldr r2,[r0] //將Master Clock Register讀到R2
and r2,r2, r1 //R2=R2與R1
mov r1,#0 //R1=0
cmp r1,r2 //判斷R2是否位0
/* No=> Do nothing */是0,則主時鐘選擇是MCK ==SLOW CLOCK
bne _init_bss //R1=R2直接初始化bss段
/*Yes => Switch to the main oscillator */打開主晶振開關
ldr r1,=AT91C_PMC_CSS_MAIN_CLK // (PMC)Main Clock is selected (0x1) R1=1
ldr r2,=AT91C_PMC_PRES_CLK // (PMC) Selectedclock(0x0 << 2)R2=0
orr r1,r1, r2 //R1=R1或R2 R1=1
str r1,[r0] //將R1寫到Master Clock Register
ldr r0,=AT91C_PMC_SR // (PMC) Status Register (0xFFFFFC68)讀到R0
1:
ldr r1, [r0] //將Master Clock Register讀到R1
ldr r2,=AT91C_PMC_MCKRDY//MasterClockStatus/Enable/Disable/Mask(0x1<<3)
ands r1, r1, r2 //R2=1000 R1=R1與R2
beq 1b//如果不等於,就繼續循環檢測,直到爲1爲止,跳到下面函數處理
//Copythe data section in RAM at .data link address從連接地址.data開始拷貝數據段到 RAM
_init_data:
ldr r2, =_lp_data
ldmia r2, {r1, r3, r4} //r1=[ r2] r3=[ r2] +4 r4=[ r2] +8
1:
cmp r3, r4
ldrcc r2, [r1], #4
strcc r2, [r3], #4 //將r2中的數據寫入到[r3]的地址的存儲單元中,並新地址[r3]=[ r3] +4
bcc 1b
/*Initialize the bss segment *///初始化bss段
_init_bss:
adr r2, _lp_bss //僞指令:小範圍內讀取數據
ldmia r2, {r3, r4}
mov r2, #0
1:
cmp r3, r4
strcc r2, [r3], #4
bcc 1b
/*Branch on C code Main function (with interworking) *///進入C代碼MAIN函數
_branch_main:
ldr r4, = main//在main函數中,拷貝完主要的運行代碼
mov lr, pc //將LR寄存器的值直接寫入道PC中
bx r4 //此處真正跳轉到MAIN函數執行
/*Branch to the application at the end of the bootstrap init *//在bootstrap初始化最後分支進入應用程序中執行
_go: //main函數執行完畢返回,一個地址傳遞到r0中,此地址是SDRAM中的地址
ldr r1, =MACH_TYPE
mov lr, pc
bx r0 //跳轉到main函數執行完畢的返回地址,也就是跳轉到bootstrap加載的
//程序(uboot)在SDRAM中的位置
.align
_lp_data:
.word _etext
.word _sdata
.word _edata
_lp_bss:
.word _sbss
.word _ebss
問題:
1 _init_data的數據拷貝爲什麼從代碼段的結束位置開始到數據段的結束位置結束?????
2 彙編中bne和beq的各自跳轉使用方式???
3 彙編中 ldmia , ldrcc , strcc , bcc 具體的指令說明?其中的cc是什麼意思???
問題解決辦法:
1:
2:彙編中bne和beq的各自跳轉使
B是跳轉,後面的是跳轉條件,EQ 相等 NE 不相等
3:
LDMIA
IA: 每次傳送後地址加4;
IB: 每次傳送前地址加4;
DA: 每次傳送後地址減4;
DB: 每次傳送前地址減4;
ldmia r2, {r1, r3, r4} //r1=[ r2] r3=[ r2] +4 r4=[ r2] +8
ldrcc r2, [r1], #4 //將r1地址的數據傳送到r2中,並且新的r1=r1+4,等待下個存儲單元的使用
strcc r2, [r3], #4 //將r2中的數據寫入到[r3]的地址的存儲單元中,並新地址[r3]=[ r3] +4
bcc //一旦遇到一個B指令,ARM處理器將立即跳轉到給定的目標地址,從那裏繼續執行
條件助記符:
BEQ 相等則跳轉,
B跳轉,EQ相等(,前面有CMP)
LDRCC 小於則裝載內存數據到寄存器,LDR裝載,CC小於
STRCC BCC類似
<助記符>{<執行條件>}{S}<Rd>,<Rn>{,第2操作數}
有S則表示影響CPSR寄存器的值
條件碼助記符:
EQ 相等
NE 不相等
CS/HS 無符號數大於或等於
CC/LO 無符號數小於