Xloader是在rom code和uboot之间的一个小的BootLoader,其启动分析如下:
从下面lds文件中可以看到xloader的入口函数
x-loader/board/omap1710h3/x-load.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm926ejs/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
其中start.s的分析如下:
入口函数首先执行reset
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
#关掉watchdog
/*
* turn off the watchdog, unlock/diable sequence
*/
mov r1, #0xF5
ldr r0, =WDTIM_MODE
strh r1, [r0]
mov r1, #0xA0
strh r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =REG_IHL1_MIR
str r1, [r0]
ldr r0, =REG_IHL2_MIR
str r1, [r0]
/*
* we do sys-critical inits at reboot,
*/
bl cpu_init_crit
/*
* relocate exception vectors to SRAM where ROM code expects
*/
#ifdef CFG_BOOT_CS0
adr r0, _start /* r0 <- current position of code */
add r0, r0, #4 /* skip reset vector */
mov r2, #36 /* r2 <- size of data (8+1 words) */
add r2, r0, r2 /* r2 <- source end address */
mov r1, #0x20000000
next:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
ble next
#endif
#执行重定位
relocate: /* relocate X-Loader 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 X-Loader */
sub sp, r0, #128 /* leave 32 words for abort-stack */
#清bss
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
add r0, r0, #4 /* start at first byte of bss */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
#最终执行c的函数_start_armboot
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
其中_start_armboot 函数实现如下:lib/board.c:105:void start_armboot (void)
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
int i;
uchar *buf;
char boot_dev_name[8];
u32 boot_device = 0;
#首先初始化一些信息
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
#ifdef START_LOADB_DOWNLOAD
strcpy(boot_dev_name, "UART");
do_load_serial_bin (CFG_LOADADDR, 115200);
#else
#从寄存器中得到当前是从nand/emmc/sd 等device boot
/* Read boot device from saved scratch pad */
boot_device = __raw_readl(0x480029c0) & 0xff;
buf = (uchar*) CFG_LOADADDR;
switch(boot_device) {
case 0x03:
strcpy(boot_dev_name, "ONENAND");
#if defined(CFG_ONENAND)
for (i = ONENAND_START_BLOCK; i < ONENAND_END_BLOCK; i++) {
if (!onenand_read_block(buf, i))
buf += ONENAND_BLOCK_SIZE;
else
goto error;
}
#endif
break;
case 0x02:
default:
strcpy(boot_dev_name, "NAND");
#if defined(CFG_NAND)
for (i = NAND_UBOOT_START; i < NAND_UBOOT_END;
i+= NAND_BLOCK_SIZE) {
if (!nand_read_block(buf, i))
buf += NAND_BLOCK_SIZE; /* advance buf ptr */
}
#endif
break;
#加入我们从mmc中boot的话,这里会将uboot 从emmc 中读取到dram中
case 0x05:
strcpy(boot_dev_name, "EMMC");
#if defined(CONFIG_MMC)
if (mmc_read_bootloader(1, 0) != 0)
goto error;
#else
goto error;
#endif
break;
case 0x06:
strcpy(boot_dev_name, "MMC/SD1");
#if defined(CONFIG_MMC) && defined(CFG_CMD_FAT)
if (mmc_read_bootloader(0, 1) != 0)
goto error;
#else
goto error;
#endif
break;
};
#endif
#开始跳入到uboot中执行,正常情况下后面的code 都不会执行
/* go run U-Boot and never return */
printf("Starting OS Bootloader from %s ...\n", boot_dev_name);
((init_fnc_t *)CFG_LOADADDR)();
/* should never come here */
#if defined(CFG_ONENAND) || defined(CONFIG_MMC)
error:
#endif
#如果失败的话,则挂载这里
printf("Could not read bootloader!\n");
hang();
}
其中从emmc中读取uboot的code如下:
int mmc_read_bootloader(int dev, int part)
{
long size;
unsigned long offset = CFG_LOADADDR;
block_dev_desc_t *dev_desc = NULL;
unsigned char ret = 0;
#首先初始化emmc 控制器
ret = mmc_init(dev);
if (ret != 0){
printf("\n MMC init failed \n");
return -1;
}
#然后从emmc中读取uboot
if (part) { /* FAT Read for extenal SD card */
dev_desc = mmc_get_dev(dev);
size = file_fat_read("u-boot.bin", (unsigned char *)offset, 0);
if (size == -1)
return -1;
} else { /* RAW read for EMMC */
ret = mmc_read(dev, 0x400, (unsigned char *)offset, 0x60000);
if (ret != 1)
return -1;
}
return 0;
}