U-Boot分析
时间:2009-07-27 来源:yuanfu
U-Boot,全称为Universal Boot Loader,即通用的Bootloader。之所以叫通用的Bootloader,是因为它能引导多种操作系统,支持多种架构的CPU。
可以从http://sourceforge.net/projects/U-Boot获得U-Boot的最新版本。
1.U-Boot的配置、编译、连接过程。
在顶层的Makefile中可以看见
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE) smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 若在U-Boot的根目录下编译,则其中的MKCONFIG就是根目录下的mkconfig文件。在U-Boot编译过程中,执行“make smdk2410_config",实际上就是执行如下命令: ./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 再来看看mkconfig的作用,在mkconfig文件开头第6行给出了它的用法: # Parameters: Target Architecture CPU Board [VENDOR] [SOC] 分析mkconfig文件,执行如上命令,则产生如下结果: (1)开发板名称 BOARD_NAME = smdk2410 (2)创建到平台/开发板相关的头文件的链接, ln -s asm-arm asm ln -s arch-sc324x0 asm-arm/arch ln -s proc-armv arm-arm/proc (3)创建顶层Makefile包含的文件 include/config.mk,如下所示: ARCH = ARM CPU = arm920t BOARD = smdk2410 SOC = s3c24x0 (4)创建开发板相关的头文件include/config.h 配置完后,就可以执行“make all”执行编译,在Makefile中,根据上面创建的config.mk文件,来确定编译器,而连接地址在board/smdk2410/config.mk文件中定义TEXT_BASE = 0x33F80000。整体U-Boot的编译流程如下: Ⅰ.首先编译cpu/$(cpu)/start.S,对于不同的CPU,还可能编译cpu/$(cpu)下的其他文件。 Ⅱ.然后,对于平台/开发板相关的每个目录、每个通用目录都使用它们各自的Makefile文件。 Ⅲ.将上面生成的.o、.a文件按照board/$(BOARDDIR)/config.mk文件中指定的代码段起始地址、board/$(BOADRDDIR)/U-Boot.lds连接脚本进行连接。 Ⅳ.将第三步得到的是ELF格式的U-Boot,后面的Makefile还会将它转换为二进制格式、S-Record格式。 2.U-Boot的启动文件分析。 #include <config.h>
#include <version.h> /* _start若还没有在SDRAM中的话,_start的地址为0,若在的话,它的地址等于连接地址,也就是 33F80000,此地址在 /board/smdk2410/config.mk文件中定义 */
.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: .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
/*
申请一个4字节的内存,用Text_BASE初始化它,在/board/smdk2410/config.mk中定义33F80000
*/
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start //用_start所代表的地址初始化_armboot_start /* _bss_start和_end在u-boot.lds中定义 */
.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
/*
* 复位代码
*/ reset:
/*
* 设置CPU为32位管理模式
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 /* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
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 /* FCLK:HCLK:PCLK = 1:2:4 */
/* 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!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT /*关闭MMU和SDRAM的初始化*/
bl cpu_init_crit
#endif #ifndef CONFIG_SKIP_RELOCATE_UBOOT /*复制代码到RAM中*/
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* 当前代码的位置 */
ldr r1, _TEXT_BASE /* 测试是否在SDRAM中*/
cmp r0, r1
beq stack_setup /*若在设置堆栈,若不在执行下面的指令*/ ldr r2, _armboot_start /*第一条指令的位置*/
ldr r3, _bss_start /*在U-Boot.lds中定义,是代码段的结束位置*/
sub r2, r3, r2 /* r2 <- size of armboot ,r2=代码段的长度 */
add r2, r0, r2 /* r2 <- source end address r2=Nor flash上的结束地址 */ 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:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area,128KB */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo,全局数据 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) /*FIQ IRQ的栈*/
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
/*清除BSS段,bss段存放的是无初始值的全局变量和静态变量*/
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
/*第二阶段C语言的入口点*/
ldr pc, _start_armboot _start_armboot: .word start_armboot
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit: /*关闭MMU*/
/*
* 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 */
TOPDIR := $(SRCTREE) smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0 若在U-Boot的根目录下编译,则其中的MKCONFIG就是根目录下的mkconfig文件。在U-Boot编译过程中,执行“make smdk2410_config",实际上就是执行如下命令: ./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0 再来看看mkconfig的作用,在mkconfig文件开头第6行给出了它的用法: # Parameters: Target Architecture CPU Board [VENDOR] [SOC] 分析mkconfig文件,执行如上命令,则产生如下结果: (1)开发板名称 BOARD_NAME = smdk2410 (2)创建到平台/开发板相关的头文件的链接, ln -s asm-arm asm ln -s arch-sc324x0 asm-arm/arch ln -s proc-armv arm-arm/proc (3)创建顶层Makefile包含的文件 include/config.mk,如下所示: ARCH = ARM CPU = arm920t BOARD = smdk2410 SOC = s3c24x0 (4)创建开发板相关的头文件include/config.h 配置完后,就可以执行“make all”执行编译,在Makefile中,根据上面创建的config.mk文件,来确定编译器,而连接地址在board/smdk2410/config.mk文件中定义TEXT_BASE = 0x33F80000。整体U-Boot的编译流程如下: Ⅰ.首先编译cpu/$(cpu)/start.S,对于不同的CPU,还可能编译cpu/$(cpu)下的其他文件。 Ⅱ.然后,对于平台/开发板相关的每个目录、每个通用目录都使用它们各自的Makefile文件。 Ⅲ.将上面生成的.o、.a文件按照board/$(BOARDDIR)/config.mk文件中指定的代码段起始地址、board/$(BOADRDDIR)/U-Boot.lds连接脚本进行连接。 Ⅳ.将第三步得到的是ELF格式的U-Boot,后面的Makefile还会将它转换为二进制格式、S-Record格式。 2.U-Boot的启动文件分析。 #include <config.h>
#include <version.h> /* _start若还没有在SDRAM中的话,_start的地址为0,若在的话,它的地址等于连接地址,也就是 33F80000,此地址在 /board/smdk2410/config.mk文件中定义 */
.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: .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
/*
申请一个4字节的内存,用Text_BASE初始化它,在/board/smdk2410/config.mk中定义33F80000
*/
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start //用_start所代表的地址初始化_armboot_start /* _bss_start和_end在u-boot.lds中定义 */
.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
/*
* 复位代码
*/ reset:
/*
* 设置CPU为32位管理模式
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0 /* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
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 /* FCLK:HCLK:PCLK = 1:2:4 */
/* 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!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT /*关闭MMU和SDRAM的初始化*/
bl cpu_init_crit
#endif #ifndef CONFIG_SKIP_RELOCATE_UBOOT /*复制代码到RAM中*/
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* 当前代码的位置 */
ldr r1, _TEXT_BASE /* 测试是否在SDRAM中*/
cmp r0, r1
beq stack_setup /*若在设置堆栈,若不在执行下面的指令*/ ldr r2, _armboot_start /*第一条指令的位置*/
ldr r3, _bss_start /*在U-Boot.lds中定义,是代码段的结束位置*/
sub r2, r3, r2 /* r2 <- size of armboot ,r2=代码段的长度 */
add r2, r0, r2 /* r2 <- source end address r2=Nor flash上的结束地址 */ 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:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area,128KB */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo,全局数据 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) /*FIQ IRQ的栈*/
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
/*清除BSS段,bss段存放的是无初始值的全局变量和静态变量*/
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
/*第二阶段C语言的入口点*/
ldr pc, _start_armboot _start_armboot: .word start_armboot
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit: /*关闭MMU*/
/*
* 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 */
相关阅读 更多 +