決定從頭開始分析u-boot-1.1.4源碼(一)
來源:互聯網
上載者:User
在網上看了不少有關u-boot的文章,有的講得也比較詳細,但我按照上面的步驟移植到我的2410開發板總是有點小問題,所以我決定從頭開始分析u-boot-1.1.4的源碼,希望能對u-boot有個深入的瞭解,最後移植到我的開發板上.這裡需要有點彙編和C基礎,我在2410上寫過最小啟動代碼,這個相信問題不大. 下面就從代碼的入口地址u-boot-1.1.4\cpu\arm920t\start.s處開始分析:.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_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.balignl 16,0xdeadbeef注:.globl相當ADS中的GLOBAL,.word相當於ADS中的DCD,指分配一個字的記憶體單元,其值為undefined_instruction等,.balignl應該是相當於ADS中的ALIGN(The ALIGN directive aligns the current location to a specified boundary by padding with zeroes.),意思是通過填充0來使當前位置滿足一定的格式. 然後程式跳到reset處開始執行:reset:
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3 /*屏蔽IRQ中斷,FIQ中斷,進入管理員模式*/
msr cpsr,r0#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008
# define CLKDIVN 0x14800014
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000 /*定義相關寄存器地址,因為這裡沒用到get 2410addr.inc,所以要自己定義*/
# 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]
# endifldr r0, =CLKDIVN /*設定FCLK:HCLK:PCLK = 1:2:4 */
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif下面就跳到cpu_init-crit,代碼如下 cpu_init_crit:mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */設定cache,mmu等相關控制寄存器,其定義在S3C2410X USER'S MANUAL 1.2中546頁可以查到,其中bit13為V bit:Base location of exception registers,0=Low addresses=0x0000 0000,1=High addresses=0xFFFF 0000,B bit為Big-endian/little-endian選擇,bit1為Alignment fault enable,bit12為I bit,Instruction
cache enable.
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然後儲存PC地址,跳到lowlevel_init去初始化儲存空間控制寄存器,這裡的lr為進入cpu_init_crit之前的PC地址,需要儲存,等下用來返回.
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr接著進入到lowlevel_init,這裡執行一個迴圈,相當於迴圈13次,把一個預先定義的一個表的值賦給從BWSCON開始的13個連續的寄存器.這些寄存器定義了bank1--bank7的控制設定,包括初始化sdram等,代碼如下:lowlevel_init:ldr r0, =SMRDATA /*這裡的ldr為直接地址跳轉,是非位置無關代碼,所以這裡的SMRDATA為串連時地址,即在0x33f80000以上*/
ldr r1, _TEXT_BASE /*在u-boot-1.1.4\board\smdk2410\congfig.mk中定義了TEXT_BASE = 0x33F80000*/
sub r0, r0, r1 /*實際上前面的ldr指令如果用adr指令代碼,這行可以不用*/
ldr r1, =BWSCON /* Bus Width Status Controller */
add r2, r0, #13*4
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b/* everything is fine now */
mov pc, lr.ltorg
/* the literal pools origin */SMRDATA:
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32 /*這裡有些參數是不準的,要根據實際板子的參數設定,雖然有時按這個設定也能正常工作*/
.word 0x30
.word 0x30這裡執行完以後,程式返回到cpu_init_crit的下一行開始執行,代碼如下: #ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /*_start為當前代碼的起始地址,即為rom的起始地址0*/
ldr r1, _TEXT_BASE /*_TEXT_BASE為程式碼片段的串連起始地址*/
cmp r0, r1 /*如果兩者相等,則為已經在ram中運行,不需要再拷貝*/
beq stack_setupldr r2, _armboot_start /*_armboot_start的定義是_armboot_start: .word _start,意思是說這個值在運行期間是不變的,而_start則運行在rom時與運行在ram時是不同的*/
ldr r3, _bss_start /*下面這裡有一點點複雜,不過我可能已經看過N次,這裡就不分析了*/
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */接下來進行堆棧初始化:stack_setup:
ldr r0, _TEXT_BASE
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */clear_bss: /*將從_bss_start到_bss_end的bss段清0*/
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越來越複雜,一開始尤其是搞不清u-boot在ram中的記憶體分布, 從這裡看大概是這樣: _TEXT_BASE 0x33f80000 malloc area 0x33f80000-CFG_MALLOC_LEN bdinfo 0x33f80000-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE stack 0x33f80000-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE-CONFIG_STACKSIZE_IRQ-CONFIG_STACKSIZE_FIQ-abort-stack到這裡,彙編部分的啟動代碼就結束了,通過執行下面這條長跳轉指令跳轉到ram中執行C語言部分代碼,ldr偽指令是位置相關的,即跳到串連時的地址. ldr pc, _start_armboot_start_armboot: .word start_armboot