UBOOT源码分析(uboot-1.1.6)
由链接文件可知,uboot第一个执行文件为start.S.
ARM单板上电,nand启动,先从flash中拷贝4K内容到soc内部ram中,开始运行。通过这段代码将boot代码拷贝到ram中来运行。
首先,设置异常向量表。
.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: .wordundefined_instruction
_software_interrupt: .wordsoftware_interrupt
_prefetch_abort: .wordprefetch_abort
_data_abort: .worddata_abort
_not_used: .wordnot_used
_irq: .wordirq
_fiq: .wordfiq
.balignl 16,0xdeadbeef
重启后,跳转到reset执行。
1、设置CPU为SVC管理模式
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
2、关看门狗和禁止使能中断
/* turn off the watchdog*/
#ifdefined(CONFIG_S3C2400)
# definepWTCON 0x15300000
# defineINTMSK 0x14400008 /*Interupt-Controller base addresses */
# defineCLKDIVN 0x14800014 /*clock divisor register */
#elifdefined(CONFIG_S3C2410)
# definepWTCON 0x53000000
# define INTMOD 0X4A000004
# define INTMSK 0x4A000008 /*Interupt-Controller base addresses */
# defineINTSUBMSK 0x4A00001C
# defineCLKDIVN 0x4C000014 /*clock divisor register */
#endif
#ifdefined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in theINTMR - default
*/
mov r1,#0xffffffff
ldr r0,=INTMSK
str r1,[r0]
# ifdefined(CONFIG_S3C2410)
ldr r1,=0x3ff
ldr r0,=INTSUBMSK
str r1,[r0]
# endif
3、初始化SDRAM
#ifndefCONFIG_SKIP_LOWLEVEL_INIT 没有定义该宏为正常启动过程,否则为调试启动,调试器直接下载uboot代码到ram中
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 duringdebug */
blne cpu_init_crit
#endif
_start,如果正常启动start位置为0。调试启动,调试器直接将代码下载链接地址(代码运行地址,0x33f80000)
_TEXT_BASE,为uboot.lds中指定的链接地址(0x33f80000)。
Cmp 如果这两个地址相同,说明为调试启动,那SDRAM已经被初始化过了。如果不同,那说明SDRAM还未被初始化,需要进入
cpu_init_crit里来初始化SDRAM。
4、cpu_init_crit
#ifndefCONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0,#0
mcr p15,0, r0, c7, c7, 0 /* flush v3/v4cache */
mcr p15,0, r0, c8, c7, 0 /* flush v4 TLB*/
关闭ICACHE和DCACHE
/*
* disable MMU stuff and caches
*/
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
关闭MMU
/*
* before relocating, we have to setup RAMtiming
* because memory timing is board-dependend,you will
* find a lowlevel_init.S in your boarddirectory.
*/
mov ip,lr
bl lowlevel_init
mov lr,ip
mov pc,lr
#endif /*CONFIG_SKIP_LOWLEVEL_INIT */
5、lowlevel_init
初始化sdram
.globl lowlevel_init
lowlevel_init:
/* memory controlconfiguration */
/* make r0 relative thecurrent location so that it */
/* reads SMRDATA out ofFLASH rather than memory ! */
ldr r0, =SMRDATA
ldr r1,_TEXT_BASE
sub r0,r0, r1
ldr r1,=BWSCON /* Bus Width StatusController */
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 poolsorigin */
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 0xb1
.word 0x30
.word 0x30
这时候的代码、数据都只保存在flash上,内存中还没有,所以读取数据时要变换地址。
6、设置栈
/* Set up the stack */
stack_setup:
ldr r0,_TEXT_BASE /*upper 128 KiB: relocated uboot */
sub r0,r0, #CFG_MALLOC_LEN /* mallocarea */
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 */最后留出12个字节给abort异常,剩下就是栈,sp指向没有使用的内存即可。栈向下生长
SDRAM划分如下
7、设置时钟
由于
sub sp,r0,#12 /*leave 3 words for abort-stack */
中已经将SP指针设置好。故可以调用C函数,所以clock_init是C代码实现。
#ifndefCONFIG_SKIP_LOWLEVEL_INIT
bl clock_init
#endif
void clock_init(void)
{
S3C24X0_CLOCK_POWER*clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;
/* support both of S3C2410 and S3C2440 */
if (isS3C2410)
{
/* FCLK:HCLK:PCLK = 1:2:4 */
clk_power->CLKDIVN = S3C2410_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust theLOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON =S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON =S3C2410_MPLL_200MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
else
{
/* FCLK:HCLK:PCLK = 1:4:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust theLOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON =S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON =S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
}
8、重定位(代码从flash拷贝到SDRAM)
#ifndefCONFIG_SKIP_RELOCATE_UBOOT
relocate: /*relocate U-Boot to RAM */
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 duringdebug */
beq clear_bss
ldr r2,_armboot_start
ldr r3,_bss_start
sub r2,r3,r2 /*r2 <- size of armboot */
#if 1
bl CopyCode2Ram /*r0: source, r1: dest, r2: size */
#else
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
#endif /*CONFIG_SKIP_RELOCATE_UBOOT */
9、清BSS段
lear_bss:
ldr r0,_bss_start /*find start of bss segment */
ldr r1,_bss_end /*stop here */
mov r2,#0x00000000 /*clear */
clbss_l:str r2,[r0] /*clear loop... */
add r0,r0, #4
cmp r0,r1
ble clbss_l
10、调用start_armboot(C函数)——第二阶段代码lib_arm/board.c
ldr pc,_start_armboot
_start_armboot: .wordstart_armboot