0、由u-boot-2016.05\arch\arm\cpu\u-boot.lds链接文件中ENTRY(_start)
可知程序的入口在_start,在SourceInsight中查找可发现程序的入口_start在u-boot-2016.05\arch\arm\lib\vectors.S中。
...
ENTRY(_start)
SECTIONS
{
...
. = 0x00000000;
. = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
...
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data*)
}
. = ALIGN(4);
. = .;
...
.bss_start __rel_dyn_start (OVERLAY) : {
KEEP(*(.__bss_start));
__bss_base = .;
}
.bss __bss_base (OVERLAY) : {
*(.bss*)
. = ALIGN(4);
__bss_limit = .;
}
.bss_end __bss_limit (OVERLAY) : {
KEEP(*(.__bss_end));
}
...
}
进入boot-2016.05\arch\arm\lib\vectors.S中,可以看到从_start开始后就跳转到reset去执行:
...
.globl _start
...
_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
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
...
1、从u-boot-2016.05\arch\arm\cpu\arm920t\start.S中reset执行
主要执行流程:reset -> cpu_init_crit -> lowlevel_init -> _main
reset:
...
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
...
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
...
bl lowlevel_init
...
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
2、由bl _main跳转到u-boot-2016.05\arch\arm\lib\crt0.S中从入口_main开始执行
主要执行流程:board_init_f -> relocate_code -> board_init_r
ENTRY(_main)
...
bl board_init_f_alloc_reserve
...
bl board_init_f_init_reserve
...
bl board_init_f
#if ! defined(CONFIG_SPL_BUILD)
...
b relocate_code
...
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
...
#if defined(CONFIG_SYS_THUMB_BUILD)
...
#else
ldr pc, =board_init_r
#endif
#endif
ENDPROC(_main)
这部分有三点说明:
⑴、u-boot-2016.05\common\board_f.c:board_init_f通过initcall_run_list(init_sequence_f)函数执行一系列初始化函数以实现前半部分板级初始化。全局结构体gd在u-boot-2016.05\arch\arm\include\asm\global_data.h中声明:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")
⑵、u-boot-2016.05\arch\arm\lib\relocate.S:relocate_code实现uboot代码的重定位,此部分如果觉得源代码不是简单明了可自己改写。
⑶、去重定位uboot有两种路径:
一种是将gd->flags设为0,在初始化函数序列init_sequence_f中的jump_to_copy函数中去跳转到relocate_code:
static int jump_to_copy(void)
{
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0;
...
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
...
#else
relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
#endif
return 0;
}
另一种就是不宏定义CONFIG_SPL_BUILD,然后在u-boot-2016.05\arch\arm\lib\crt0.S中通过
#if ! defined(CONFIG_SPL_BUILD)
...
b relocate_code
...
#endif
来跳转到relocate_code。以上两种方法选其一,另一种就得去掉。
3、在上一步通过ldr pc, =board_init_r指令进入u-boot-2016.05\common\board_r.c:board_init_r函数,进而调用initcall_run_list(init_sequence_r)函数执行一系列初始化函数以实现后半部分板级初始化,并在initcall_run_list函数里进入run_main_loop不再返回。
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
...
if (initcall_run_list(init_sequence_r))
hang();
/* NOTREACHED - run_main_loop() does not return */
hang();
}
init_sequence_r是一个函数指针数组,里面存放了很多初始化函数指针,里面有两个重要的函数指针initr_announce和run_main_loop:
init_fnc_t init_sequence_r[] = {
...
initr_announce,
...
run_main_loop,
};
initr_announce函数声明从此处开始程序就将跳转到RAM中运行:
static int initr_announce(void)
{
debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr);
return 0;
}
最后一项是run_main_loop ,进入run_main_