分类: LINUX
2011-07-04 16:35:23
Uboot启动分析
uboot\cpu\s3c44b0\start.S
.globl _start //这个伪操作将这个symbol作为全局符号暴露给连接器(linker),这个符号可以是定义的一个独立的模块。
_start: b reset
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
(仅仅处理7个中断)
.balignl 16,0xdeadbeef //填充标志位0xdeadbeef
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* relocate u-boot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
_TEXT_BASE:// _TEXT_BASE是编译器连接过来的值,原型是在board/mrtos/config.mk里定义的TEXT_BASE = 0x0C700000。
.word TEXT_BASE// /*把TEXT_BASE这个值存储在当前位置,_TEXT_BASE是换在c中理解得话,就是一个指针,指向TEXT_BASE存储的位置,在汇编的准确定义是叫标号,标志TEXT_BASE的存储位置 */
.globl _armboot_start
_armboot_start:
.word _start //把_start存储到当前位置,并且用标号_armboot_start标记,也就是定义_armboot_start指针指向词值,并且这个指针值可以冰编译器引用。
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start //这个值__(2个下划线)bss_start 是编译器编译uboot的时候产生的,用_(一个下划线)bss_start标记,引用。
.globl _bss_end
_bss_end:
.word _end //这个值_end 是编译器编译uboot的时候产生的,用_bss_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
/*
* the actual reset code
*/
reset: //reset代码段
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0x13
msr cpsr,r0
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
//判断是否要初始化CPU等,区分调试运行还是XIP
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
/*
* 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.
*/
bl lowlevel_init
#endif
//重载uboot,将uboot拷贝到ram区间执行,为什么要怎么做,有一个重要原因因为,在uboot运行过程中,用户需要烧写参数到flash,所以必须将程序运行在ram区,这样才能控制flash区间的擦写。
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
//如果程序从flash启动,_start值为0
//如果程序被用户以调试方式加载,如用户设定0x0c000800,则_start值为0x0c000800
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
//重载代码的目标位置
cmp r0, r1 /* don't reloc during debug */
//比较程序的实际开始位置与重载目标位置,如果一致,则无需copy,否则执行stack_setup
beq stack_setup //相等直接跳到设置堆栈代码段,忽略代码重载部分
ldr r2, _armboot_start //不相等
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
//计算uboot代码的实际结束地址,_start+(_bss_start-_armboot_start)
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
//从r0的位置copy n个数据到 r3 -r10这几个寄存器,r0自动加n
stmia r1!, {r3-r10} /* copy to target address [r1] */
//从r3 -r10这几个寄存器 copy n个数据到 r1指向的开始的位置r1自动加n.
cmp r0, r2 /* until source end addreee [r2] */
//判断r0 是否copy完成
ble copy_loop //循环
//中断矢量重载
//将中断重定义到0x0c000000的位置,也就是RAM的起始位置
/*
now copy to sram the interrupt vector
*/
adr r0, real_vectors
add r2, r0, #1024
ldr r1, =0x0c000000
add r1, r1, #0x08 //注意,这里的地址变为0x0c000008咯
vector_copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble vector_copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
//参考上一段
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
//堆栈的结束地址_TEXT_BASE
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
//分配CONFIG_SYS_MALLOC_LEN 区间。
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
//分配CONFIG_SYS_GBL_DATA_SIZE 区间。
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
//分配CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ区间
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
// 12bytes冗余区间,赋值堆栈的起始位置
ldr pc, _start_armboot
// 跳转到start_armboot (c代码)
_start_armboot: .word start_armboot
/******************************************************************** CPU_init_critical临界区寄存器
* 设置一些重要的寄存器,并进行内存测试。
*******************************************************************/
#define INTCON (0x01c00000+0x200000) /* 中断控制器 */
#define INTMSK (0x01c00000+0x20000c) /* 中断控制屏蔽寄存器 */
#define LOCKTIME (0x01c00000+0x18000c)
#define PLLCON (0x01c00000+0x180000)
#define CLKCON (0x01c00000+0x180004)
#define WTCON (0x01c00000+0x130000)
cpu_init_crit:
/* 关闭看门狗 */
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
/** 清除所有中断位,设置INTMRs实现。*/
ldr r1,=INTMSK
ldr r0, =0x03fffeff
str r0, [r1]
ldr r1, =INTCON
ldr r0, =0x05
str r0, [r1]
/* 设置时钟控制寄存器 */
ldr r1, =LOCKTIME
ldrb r0, =800
strb r0, [r1]
/* 设置锁相环,控制CPU运行速度。 */
ldr r1, =PLLCON
#if CONFIG_S3C44B0_CLOCK_SPEED==60
ldr r0, =0x88042 /* 60MHz (Quartz=10MHz) */
#elif CONFIG_S3C44B0_CLOCK_SPEED==75
ldr r0, =0xac042 /* 75MHz */
#else
# error CONFIG_S3C44B0_CLOCK_SPEED undefined
#endif
str r0, [r1]
ldr r1,=CLKCON
ldr r0, =0x7ff8
str r0, [r1]
/* 调用子函数返回 */
mov pc, lr
/*************************************************/
/* 实际的中断向量表 */
/*************************************************/
real_vectors:
b reset
b undefined_instruction
b software_interrupt
b prefetch_abort
b data_abort
b not_used
b irq
b fiq
/*************************************************/
undefined_instruction:
mov r6, #3
b reset
software_interrupt:
mov r6, #4
b reset
prefetch_abort:
mov r6, #5
b reset
data_abort:
mov r6, #6
b reset
not_used:
/* we *should* never reach this */
mov r6, #7
b reset
irq:
mov r6, #8
b reset
fiq:
mov r6, #9
b reset
总结:uboot这样挑来跳去,确实不好懂,不过可以画一个图,就很明了了