u-boot2009.08.start.S代码分析
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
下面定义一些全局变量,
这里_TEXT_BASE是一个标签,告诉编译器在这里分配一个word的空间,存放的值为TEXT_BASE
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start 这里用.globl伪指令定义一个全局标号,可以在其他文件引用
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start //bss段开始
_bss_start:
.word __bss_start
.globl _bss_end //bss段结束
_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
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>/*
* the actual start code
*/
start_code: //进入代码段
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr //设置处理器模式操作系统使用的保护模式
bic r0,r0,#0x1f //屏蔽所有中断,在bootloader执行中不需要中断
orr r0,r0,#0xd3
msr cpsr,r0
bl coloured_LED_init //点灯,针对具体的开发板,需要修改,测试用,可屏蔽
bl red_LED_on
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start //重定位向量表
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON //各个硬件还未就绪,关闭看门狗
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff //禁止所有中断
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
str r1, [r0]
# if defined(CONFIG_S3C2440)
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
# if defined(CONFIG_S3C2440)
#define MPLLCON 0x4c000004
#define UPLLCON 0x4c000008
ldr r0,=CLKDIVN
mov r1,#05
str r1,[r0]
ldr r0,=MPLLCON /* FCLK:HCLK:PCLK = 1:4:8 */ //设置时钟比例 FCLK用于CPU,HCLK用于AHB,PCLK用于APB
ldr r1,=0x7f021 /*405Mhz*/
str r1,[r0]
ldr r0,=UPLLCON /*48Mhz*/
ldr r1,=0x38022
ldr r1,[r0]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit //初始化cpu
#endif
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
下面这段代码是u-boot第一阶段最重要的工作,重定位代码段。这里要介绍一下adr指令,简单的说就是把 _start地址读出来,而且这个地址是相对当前pc的,所以和当前程序运行地址相关,如果在0x30000000运行,r0 = pc(0x30000004 + 0x08) + #0 = 0x3000000C;如果在0x00000000运行, r0 = pc(0x00000004 + 0x08) + #0 = 0x0000000C,所以在不同的位置运行,r0所得到的结果是不一样的,唯一确定的相对偏移量。
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */ r0<-得到_srart的运行地址
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ //r1<-Text_Base
cmp r0, r1 /* don't reloc during debug */ //如果两个地址相同,则在ram中,否则把代码搬运到ram中运行
beq stack_setup
ldr r2, _armboot_start //代码代码段起始地址
ldr r3, _bss_start //bss段起始地址
sub r2, r3, r2 /* r2 <- size of armboot */ u-boot代码大小=-bss-start-_start
add r2, r0, r2 /* r2 <- source end address */ //u-boot大小加上_start运行地址,得出u-boot的运行结束地址
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */ 把r0中的的数据放入r3-r10,r0加1,
stmia r1!, {r3-r10} /* copy to target address [r1] */ //把r3-r10的数据存入r1指向的地址,r1加1
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo
text段向下移动 CONFIG_SYS_MALLOC_LEN 字节作为栈区域,栈向下移动 CONFIG_SYS_GBL_DATA_SIZE 字节作为全局数据结构区域 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */ //得到最终的sp,设置sp
clear_bss:
ldr r0, _bss_start /* find start of bss segment */ r0指向bss开始
ldr r1, _bss_end /* stop here */ r1指向bss结束
mov r2, #0x00000000 /* clear */ r2=0
clbss_l:str r2, [r0] /* clear loop... */ 把r2内容放入r0中地址中,清零
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot 至此堆栈已经建立,开始进入c代码,开始第二阶段
_start_armboot: .word start_armboot