U-Boot Stage1

u-boot 的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下:

(1)定义入口。由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。

(2)设置异常向量(ExceptionVector)。

(3)设置CPU 的速度、时钟频率及终端控制寄存器。

(4)初始化内存控制器。

(5)将ROM 中的程序复制到RAM 中。

(6)初始化堆栈。

(7)转到RAM 中执行,该工作可使用指令ldr pc 来完成。

第一阶段对应的文件是cpu/arm920t/start.S,U-Boot启动第一阶段流程如下:

       U-Boot Stage1_第1张图片



cpu/arm920t/start.S

/*

*************************************************************************

*

* Jump vector table as in table 3.1 in [1]

*

*************************************************************************

*/

;定义变量_start,然后跳转到处理器复位代码

.globl _start //u-boot 启动入口

_start: b reset

;产生中断则利用pc 来跳转到对应的中断处理程序中

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 //快速中断向量

;利用.word 来在当前位置放置一个值,这个值实际上就用对应的中断处理函数的地址

;.word 的意义为在当前地址处放入一个16bits 值

_undefined_instruction: .word 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

.balignl 16,0xdeadbeef

/*

*************************************************************************

*

* Startup Code (reset vector)

*

* do important init only if we don't start from memory!

* relocate armboot to ram

* setup stack

* jump to second stage

*

*************************************************************************

*/

;定义变量

_TEXT_BASE:

.word TEXT_BASE

.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

/*

* the actual reset code

*/

;实际处理代码

reset:

/*

* set the cpu to SVC32 mode

*/

mrs r0,cpsr

;bic 清除指定为1的位

bic r0,r0,#0x1f

;orr 逻辑或操作

orr r0,r0,#0xd3

;经过以上两步r0值控制位位11010011,第0~4位标识处理器当前所处模式为10011(32位

管理模式),第6、7位

;为1标识禁止IRQ 和FIQ 中断,第5位为0标识程序运行为arm 状态,若其为1则运行在thumb

状态

;设置处理器为32位管理模式,并运行与arm 状态

msr cpsr,r0

/* turn off the watchdog */

#if defined(CONFIG_S3C2400)

# define pWTCON 0x15300000

# define INTMSK 0x14400008 /* Interupt-Controller baseaddresses */

# define CLKDIVN 0x14800014 /* clock divisor register */

#elif defined(CONFIG_S3C2410)

;看门狗寄存器地址

# define pWTCON 0x53000000

;中断掩码寄存器,决定那个中断源被屏蔽,某位为1则屏蔽中断源,初始值为0xFFFFFFFF,

屏蔽所有中断

# define INTMSK 0x4A000008 /* Interupt-Controller baseaddresses */

;中断子掩码寄存器,该寄存器只能屏蔽11个中断源,因此其仅低11位有效,初始值为0x7FF

# define INTSUBMSK 0x4A00001C

;时钟分频控制寄存器

# define CLKDIVN 0x4C000014 /* clock divisor register */

#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

;将看门狗寄存器清空,其各位含义为,第0位为1则当看门狗定时器溢出时重启,为0则不重启,初值为1

;第2位为中断使能位,初值为0

;第3、4位为时钟分频因子,初值为00,

;第5位为看门狗的使能位初值为1

;第8~15位为比例因子,初值为0x80

ldr r0, =pWTCON

mov r1, #0x0

;将看门狗寄存器所有位置零,关闭看门狗,其实只要将第5位置0即可

str r1, [r0]

;屏蔽所有中断,实际上中断屏蔽掩码寄存器初值即为0xFFFFFFF

mov r1, #0xffffffff

ldr r0, =INTMSK

str r1, [r0]

# if defined(CONFIG_S3C2410)

;设置子中断掩码寄存器

ldr r1, =0x3ff

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

;设置时钟寄存器,CLKDIVN 第0位为PDIVN,为0则PCLK=HCLK,为1则PCLK=HCLK/2

;第1位为HDIVN,为0则HCLK=FCLK,为1则HCLK=FCLK/2

;这里两位均为1,则FCLK:HCLK:PCLK= 4:2:1

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

/*

* we do sys-critical inits only at reboot,

* not when booting from ram!

*/

;对临界寄存器的初始化,如果从ram 中启动则不执行,如果重启则执行

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl cpu_init_crit

#endif

;重定向代码,也就是从flash 中复制到ram 中

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate: /* relocate U-Boot to RAM */

;当前代码地址,adr 获取当前代码的地址信息,若从ram 运行则_start=TEXT_BASE,否则

_start=0x00000000

adr r0, _start /* r0 <- current position of code */

;获取_TEXT_BASE

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp r0, r1 /* don't reloc during debug */

;两者相等,表示从ram 运行则跳转到堆栈设置

beq stack_setup

;不相等则表示从flash 中运行,重定向代码

ldr r2, _armboot_start

;获取未初始化数据段地址

ldr r3, _bss_start

;计算代码段大小

sub r2, r3, r2 /* r2 <- size of armboot */

;计算代码段终止地址

add r2, r0, r2 /* r2 <- source end address */

;复制代码,r0为代码的起始地址,r1为ram 中地址,r2为代码的终止地址

;每次copy 后将r0值递增同r2比较来判断是否复制完成

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 /* CONFIG_SKIP_RELOCATE_UBOOT */

/* Set up the stack */

stack_setup:

;获取_TEXT_BASE

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */

; 获取分配区域起始指针,

CFG_MALLOC_LEN=128*1024+CFG_ENV_SIZE=128*1024+0x10000=192K

sub r0, r0, #CFG_MALLOC_LEN /* malloc area */

;另外分配128bytes 来存储开发板信息

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

;再减去12bytes 用于栈起点

sub sp, r0, #12 /* leave 3 words for abort-stack */

;清空未初始化数据段

clear_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

#if 0

;关闭看门狗

/* try doing this stuff after the relocation */

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, =INTMR

str r1, [r0]

;设置时钟

/* FCLK:HCLK:PCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

/* END stuff after relocation */

#endif

; 完成复制后跳转到start_armboot, 到这里就进入函数lib_arm/board.c 的这里将进入stage2

start_armboot 函数中

ldr pc, _start_armboot

_start_armboot: .word start_armboot


你可能感兴趣的:(U-Boot Stage1)