打开uboot的链接脚本 u-boot.lds , 内容如下:
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
从这里,可以看出start.o的代码段被链接在最前面,所以start.S会最先被执行,找到start.S,进行分析,则可以进一步了解Uboot的启动过程。
start.S的内容大概如下:
/* * the actual reset code */
reset:
/* * set the cpu to SVC32 mode */
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/* turn off the watchdog */
...
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
...
/* * mask all IRQs by setting all bits in the INTMR - default */
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
...
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
/* * we do sys-critical inits only at reboot, * not when booting from ram! */
bl cpu_init_crit
...
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
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 */
...
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
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
ldr pc, _start_armboot
_start_armboot: .word start_armboot
从以上内容可以得出,uboot会做以下事情:
1.设置CPU进入管理模式
2.关闭看门口
3.关中断
4.设置系统时钟
5.与CPU有关的相关初始化 cpu_init_crit
6.将uboot复制到SDRAM上
7.设置栈
8.清BSS段
9.调用start_armboot
至此,Uboot的第一阶段启动就到这里。
而从调用C函数start_armboot之后就进入uboot的第二阶段。
C函数start_armboot大致内容如下:
void start_armboot (void)
{
...
/* 以下是初始化本阶段要使用到的硬件设备 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);
...
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
...
nand_init(); /* go init the NAND */
...
/* initialize environment */
env_relocate ();
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
...
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
...
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
}
从start_armboot的代码分析可知道uboot进入第二阶段,首先会进行与本阶段相关硬件设备的初始化,执行如下代码可以实现:
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
其中init_sequence是一个指针数组,它比较重要的内容为:
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
serial_init, /* serial communications setup */
dram_init, /* configure available RAM banks */
...
};
其中很重要的两条信息
/* arch number of SMDK2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
}
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100;
是在board_init函数中实现的。这两个参数会传递给内核,告诉内核该开发板的机器ID,还有告诉内核另一些要传给内核的参数所存放的地址位于哪。
env_init函数进行Uboot环境变量的初始化。设置Uboot命令模式中的环境变量的默认值。Uboot环境变量如下图所示:
serial_init函数则是串口的初始化,以用于用户与Uboot的交互。
dram_init函数则是设置SDRAM的起始地址和大小
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
对于本开发板来说,
PHYS_SDRAM_1 = 0x30000000 /* SDRAM Bank #1 */
PHYS_SDRAM_1_SIZE = 0x04000000 /* 64 MB */
接下来在start_armboot函数还会初始化 NOR_FLASH 还有 NAND_FLASH 的一些参数等等,接着就会进入main_loop ()函数。