分类:
2011-04-10 15:42:56
1。第一阶段完成的功能
u-boot-2010.06/arch/arm/cpu/arm920t/start.S
<1>硬件初始化。
设置CPU工作模式为管理模式(svc)
关闭开门狗
设置FCLK,HCLK,PCLK的比例(即设置CLKDIVN)
关闭MMU.CACHE
<2>为加载Bootloader的第二阶段代码准备RAM空间。
所谓准备RAM空间就是初始化内存芯片,使其能正常工作。在start.S中调用lowlevel_init 函数来设置存储控制器,使得外接的SDRAM可用。代码在board/samsung/smdk2440/lowlevel_init.S中。
<3>复制Bootloader的第二阶段到RAM空间。
将这个U-Boot的代码(包括第一、第二阶段)都复制到SDRAM中,在arch/arm/cpu/arm920t/start.S中实现。
<4>设置好栈。
<5>跳转到第二阶段的C入口点。
在跳转之前,还要清除BSS段(初始值为0、无初始化的全局变量、静态变量都放在BSS段)。如果设置了如下命令(1-bootdelay、2-bootm)则直接跳转,调用lib_arm/board.c中的start_armboot()函数。这是第二阶段的入口点。
2。源码流程
<1>:初始化硬件:
vi u-boot-2010.06/arch/arm/cpu/arm920t/start.S
.globl _start //u-boot的主入口,跳入了后面的start_code
_start: b start_code //这些是跳转向量表,和芯片的体系结构有关 占4字节内存
ldr pc, _undefined_instruction //ldr语句的意思是将第二个操作数(如:_undefined_instruction)指向的地址数据传给PC
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 //.word 为定义一个4字节的空间
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//以上每条指令占4字节内存
.balignl 16,0xdeadbeef //16字节对齐,并以0xdeadbeef填充,它是个Magic number 。
/***********************************************
引用:http://haoyeren.blog.sohu.com/84511571.html
占了4x7=32字节内存。
所以在这个.balignl 16,0xdeadbeef指令之前,一共占了4x15=60个字节的内存,所以本代码的作者当时就简单的在15这个数上,加了个1,即16,把当前指针往后移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。
我不知道这个地方是作者一个错误,歪打正着呢,还是怎么回子事,其实这个偏移的值还有好多种情况。如果说最小的值的话,那么也可以写成.balignl 8,0xdeadbeef,也可以达到同样的目的。因为60不是8的倍数,但是64是8的倍数,如果写8,也正好插到64前面,也即60这个内存起始地址。如果更大一点儿的呢,那么填32也可以达到同样的效果,即.balignl 32,0xdeadbeef,道理同上。当然,不能为4,因为pc值在任何时候,都是4的倍数,只要不为0就为4的倍数,呵呵,这个值不行,如果用了这个值,0xdeadbeef永远也插不进去,呵呵。
**************************************************/
********************************为BSS段,代码段,中断等地址分配内存********************************
_TEXT_BASE:
.word TEXT_BASE //这些和上面的一样,定义一个4字节的空间存放地址
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
******************************************设置CPU工作模式为管理模式(svc)******************************
start_code:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
*******************************************关闭看门狗********************************************************
# define pWTCON 0x53000000
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
*******************************************关闭中断和子中断************************************************
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK寄存器有15位可用
ldr r0, =INTSUBMSK
str r1, [r0]
*****************************************设置时钟频率*******************************************************
# define CLKDIVN 0x4C000014 /* clock divisor register */
#define MPLLCON 0x4C000004 //系统主频配置寄存器基地址
#define UPLLCON 0x4C000008 //USB时钟频率配置寄存器基地址
ldr r0, =CLKDIVN //设置分频系数FCLK:HCLK:PCLK = 1:4:8
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON //设置系统主频为405MHz,才能让内核启动。
ldr r1, =0x7F021 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str r1, [r0]
ldr r0, =UPLLCON //设置USB时钟频率为48MHz
ldr r1, =0x38022 //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部
str r1, [r0]
****************************************关闭mmu、cache初始化内存*************************************
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit //在start.S文件的最后,里面跳出start.S文件
#endif
//跳入cpu_init_crit ,这是一个系统初始化函数,他还会调用board/samsung/lowlevel_init.S中的lowlevel_init函数。主要是对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor Flash、SDRAM才可以被系统使用。下面的代码重定向就依赖它。
<2>为加载Bootloader的第二阶段代码准备RAM空间。
vi u-boot-2010.06/board/samsung/smdk2440/lowlever_init.S
lowlevel_init.S这个函数并不复杂,只是要注意这时的代码、数据都只是保存在Nor Flash上,内存中还没有,所以读取数据时要变化数据。这些都在4kb Stepping Stone中进行。
#define BWSCON 0x48000000 //总线控制寄存器
.....(略)一大堆寄存器位的定义
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA //SMRDATA 表示这13个寄存器的值存放的开始地址(连接地址),值为0x33F8 XXXX,处于内存中。
ldr r1, _TEXT_BASE //代码段地址 0x33F8 0000,定义在board/samsung/smdk2440/config.mk中。
sub r0, r0, r1 //0x33F8 xxxx 与 0x33F8 0000相减,这就是13个寄存器值在NOR Flash上存放的地址。
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: //根据SDRAM的datasheet,给13个寄存器赋值
.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
<3>复制Bootloader的第二阶段到RAM空间。(代码重定向)
初始化内存后回到 u-boot-2010.06/arch/arm/cpu/arm920t/start.S。
如果是直接跳到下面的堆栈初始化代码 stack_setup。
relocate:
adr r0, _start //R0:当前代码段开始地址
ldr r1, _TEXT_BASE //R1:代码段的连接地址
cmp r0, r1 //测试现在是在Flash中还是在RAM中
beq stack_setup //如果已经在RAM中了,则不需要复制,直接跳转到设置栈。
//nor/nand flash双启动判断,判断flash类型。
#define BWSCON 0x48000000
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6 //判断BWSCON[2:1]是否为00,如果是,Z=1即跳转到nand_boot
beq nand_boot
//系统从Norflash启动
ldr r2, _armboot_start
ldr r3, _bss_start
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
//下面添加2440中u-boot从Nand Flash启动
nand_boot:
mov r1, #NAND_CTL_BASE //复位Nand Flash
ldr r2, =( (0<<12)|(3<<8)|(0<<4)|(3<<2)|(1<<1) )
str r2, [r1, #oNFCONF] //设置配置寄存器的初始值,参考s3c2440手册
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(1<<1)|(1<<0) )
str r2, [r1, #oNFCONT] //设置控制寄存器
ldr r2, [r1, #oNFCONT]
//ldr r2, =(0x01) //RnB Clear
//str r2, [r1, #oNFSTAT]
//ldr r2, [r1, #oNFSTAT]
mov r2, #0xff //复位command
strb r2, [r1, #oNFCMD]
mov r3, #0 //等待
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] //等待就绪
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x02 //取消片选
str r2, [r1, #oNFCONT]
//get read to call C functions (for nand_read())
ldr sp, DW_STACK_START //为C代码准备堆栈,DW_STACK_START定义在下面
mov fp, #0
//copy U-Boot to RAM
ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址
mov r1, #0x0 //传递给C代码的第二个参数:Nand Flash的起始地址
mov r2, #0x40000 //传递给C代码的第三个参数:u-boot的长度大小(256k),这个可以根据具体大小填写。
bl nand_read_ll //此处调用C代码中读Nand的函数,/board/samsung/smdk2440/nand_read.c
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2: b loop2 //infinite loop
ok_nand_read:
//检查搬移后的数据,如果前4k完全相同,表示搬移成功
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x1000 //4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3 //infinite loop
<4>设置好栈。
stack_setup:
ldr r0, _TEXT_BASE //_TEXT_BASE为代码段的开始地址,值为0x33F8 0000。
sub r0, r0, #CONFIG_SYS_MALLOC_LEN //代码段下面,留一段内存以实现malloc
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE //再留出一段内存,存一些全局参数
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) //IRQ,FIQ模式的栈
#endif
sub sp, r0, #12 //最后,留出12字节的内存给abort异常
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
<5>跳转到第二阶段的C入口点。
clear_bss: //在跳转之前,清除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
ldr pc, _start_armboot //此处跳转到第二阶段。进入喜欢的C环境。
_start_armboot: .word start_armboot
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
//最后是第2步中的关闭mmu,cache和调用初始化内存的函数cpu_init_crit:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* 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
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
@
@ 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
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/
.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)
sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
/* set base 2 words into abort stack */
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
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 r7, sp, #S_PC
stmdb r7, {sp, lr}^ @ Calling SP, LR
str lr, [r7, #0] @ Save calling PC
mrs r6, spsr
str r6, [r7, #4] @ Save CPSR
str r0, [r7, #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
/* return & move spsr_svc into cpsr */
subs pc, lr, #4
.endm
.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE)
sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
/* reserve a couple spots in abort stack */
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)
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
/*
* exception handlers
*/
.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
/* someone ought to write a more effiction fiq_save_user_regs */
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