U-Boot Init
http://www.foxice.net/techinfo_ubootinit.asp
U-Boot的entry的位置在:
u-boot-<version>/cpu/<type>/start.S中.
一開始的動作便是要初始化processor, 因此在start.S中:
.globl _start
_start:b reset
這邊直接branch到reset這個label的地方, 這個assembler的函式負責初始系統的硬件(主要是processor與memory), 然後會jump到start_armboot這個function (這個function存在於u-boot-<version>/lib_<arch>/board.c中, <arch>為你的processor的架構, 例如xscale就是lib_arm的目錄, 進到start_armboot就大多是C語言而不是assembler, 感謝上帝&媽祖&眾神明...)。
讓我們以ARM pxa為例來看看這段assembler程式碼 (sorry, 其它的架構不是太熟)。一開始必需讓ARM進入superviser mode, 因此必需設定Current Program Status Register(CPSR)如下:
mrs r0, cpsr /* set the cpu to SVC32 mode */
bic r0, r0,#0x1f /* (superviser mode, M=10011) */
orr r0, r0,#0x13
msr cpsr, r0
ARM的SVC mode必需設定CPSR為100112(請參考ARM的相關數據, 我自己是看Steve Furber的書『ARM system-on-chip architecture』第108頁)。然後u-boot會branch去一段cpu init的routine, 這邊在新版的U-Boot有一點不一樣, 舊版的會直接branch過去, 而新版的U-Boot(version 1.1.1)會以一個設定值CONFIG_INIT_CRITICAL來判斷要不要執行這段routine, 這是因為新版的U-Boot可以支持bootloader debug的方式讓你方便研發, 但是這個我沒試過, 因此有興趣的人請自行試試。下面是cpu_init_crit這個routine的程式片斷:
cpu_init_crit:
/* mask all IRQs */
ldr r0, IC_BASE
mov r1, #0x00
str r1, [r0, #ICMR]#if defined(CFG_CPUSPEED)
/* set clock speed */
ldr r0, CC_BASE
ldr r1, cpuspeed
str r1, [r0, #CCCR]
mov r0, #2
mcr p14, 0, r0, c6, c0, 0setspeed_done:
#endif/*
* before relocating, we have to setup RAM timing because memory timing is
* board-dependend, you will find a memsetup.S in your board directory.
*/
mov ip, lr
bl memsetup
mov lr, ip/* Memory interfaces are working. Disable MMU and enable I-cache. */
ldr r0, =0x2001 /* enable access to all coproc. */
mcr p15, 0, r0, c15, c1, 0
CPWAIT
mcr p15, 0, r0, c7, c10, 4 /* drain the write & fill buffers */
CPWAIT
mcr p15, 0, r0, c7, c7, 0 /* flush Icache, Dcache and BTB */
CPWAIT
mcr p15, 0, r0, c8, c7, 0 /* flush instuction and data TLBs */
CPWAIT
mov pc, lr
這段assembler程序代碼主要就是透過ARM coprocessor interface來設定Performance Monitoring Unit(PMU)與Memory Management Unit(MMU), 也就是CP14與CP15這兩個coprocessor, 這段assembler片段有詳細的說明(感恩呀...), 因此可以很清楚的看到中間還有branch到u-boot-<version>/board/<board-type>/memsetup.S裡面的memsetup這個位置, 這個routine會設定GPIO相關設定以及memory controller, 因此在之前提過的硬件設定檔要加入相關的設定值, 以lubbock為例, 他設定GPIO與memory的部份如下:
#define CFG_GPSR0_VAL 0x00008000
#define CFG_GPSR1_VAL 0x00FC0382
#define CFG_GPSR2_VAL 0x0001FFFF
#define CFG_GPCR0_VAL 0x00000000
#define CFG_GPCR1_VAL 0x00000000
#define CFG_GPCR2_VAL 0x00000000
#define CFG_GPDR0_VAL 0x0060A800
#define CFG_GPDR1_VAL 0x00FF0382
#define CFG_GPDR2_VAL 0x0001C000
#define CFG_GAFR0_L_VAL 0x98400000
#define CFG_GAFR0_U_VAL 0x00002950
#define CFG_GAFR1_L_VAL 0x000A9558
#define CFG_GAFR1_U_VAL 0x0005AAAA
#define CFG_GAFR2_L_VAL 0xA0000000
#define CFG_GAFR2_U_VAL 0x00000002
#define CFG_PSSR_VAL 0x20
#define CFG_MSC0_VAL 0x23F223F2
#define CFG_MSC1_VAL 0x3FF1A441
#define CFG_MSC2_VAL 0x7FF97FF1
#define CFG_MDCNFG_VAL 0x00001AC9
#define CFG_MDREFR_VAL 0x00018018
#define CFG_MDMRS_VAL 0x00000000
這部份的設定也是要根據你的硬件配置與外圍, 因此必需跟你的硬件人員研究一下, 當這些硬件初始的動作作玩後, 我們會回到之前branch到cpu_init_crit的下一個位置(透過把LR緩存器的值寫進PC緩存器), 然後把U-Boot重新尋址到RAM上面, 如下:
/* relocate U-Boot to RAM */
relocate:adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _armboot_end
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
最後再設定stack與清除BSS segment就可以跳到start_armboot的地方啦