u-boot-2016.05启动流程
2018-03-21 21:25
281 查看
0、由u-boot-2016.05\arch\arm\cpu\u-boot.lds链接文件中
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
2、由bl _main跳转到u-boot-2016.05\arch\arm\lib\crt0.S中从入口_main开始执行
主要执行流程:board_init_f -> relocate_code -> board_init_r
这部分有三点说明:
⑴、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_loop 后便不再返回。4、在run_main_loop 里会进入u-boot-2016.05\common\main.c:main_loop函数static int run_main_loop(void)
{
...
for (;;)
main_loop();
return 0;
}进入main_loop之前就已经完成初始化,接下来准备去处理命令/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
const char *s;
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
...
/* get environment_variable: s = getenv("bootcmd"); -> bootcmd */
s = bootdelay_process();
...
autoboot_command(s);
...
}main_loop函数里有两个重要的过程:
⑴、首先在bootdelay_process函数里通过s = getenv(“bootcmd”)得到bootcmd参数并返回bootcmd参数,const char *bootdelay_process(void)
{
char *s;
int bootdelay;
...
s = getenv("bootdelay");
...
debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
...
s = getenv("bootcmd");
...
stored_bootdelay = bootdelay;
return s;
}其中,bootcmd参数通过以下方式指定:
先在u-boot-2016.05\include\env_default.h中#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif再在u-boot-2016.05\include\configs\smdk2440.h中指定#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel;bootm 30000000"⑵、然后进入autoboot_command函数,并将bootcmd参数传入,继而进入run_command_list函数,继续将bootcmd参数传入
{
int need_buff = 1;
char *buff = (char *)cmd; /* cast away const */
int rcode = 0;
if (len == -1) {
len = strlen(cmd);
#ifdef CONFIG_SYS_HUSH_PARSER
...
#else
/* the built-in parser will change our string if it sees \n */
need_buff = strchr(cmd, '\n') != NULL;
#endif
}
if (need_buff) {
buff = malloc(len + 1);
if (!buff)
return 1;
memcpy(buff, cmd, len);
buff[len] = '\0';
}
#ifdef CONFIG_SYS_HUSH_PARSER
...
#ifdef CONFIG_CMDLINE
...
#else
rcode = board_run_command(buff);
#endif
#endif
...
}那么,board_run_command如何去执行命令?
首先,board_run_command函数通过bootcmd参数中的bootm命令找到u-boot-2016.05\cmd\bootm.c中的U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
"boot application image from memory", bootm_help_text
);然后,根据这个信息找到执行bootm命令的处理函数指针do_bootm,并进入do_bootm函数执行相关代码,而U_BOOT_CMD在u-boot-2016.05\include\command.h中定义:#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)在此,board_run_command函数还会将bootm命令中的参数(内核映像所在地址)30000000赋给bootm_headers_t结构体变量images,则images首地址就是30000000,images在u-boot-2016.05\cmd\bootm.c中定义:bootm_headers_t images; 6、根据U_BOOT_CMD信息进入u-boot-2016.05\cmd\bootm.c:do_bootm函数int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
...
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
BOOTM_STATE_OS_CMDLINE |
#endif
BOOTM_
eda8
STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO, &images, 1);
}7、从do_bootm进入u-boot-2016.05\common\bootm.c:do_bootm_states函数,Now run the OS!int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
/*
* Work through the states and see how far we get. We stop on
* any error.
*/
if (states & BOOTM_STATE_START)
ret = bootm_start(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOS))
ret = bootm_find_os(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
ret = bootm_find_other(cmdtp, flag, argc, argv);
argc = 0; /* consume the args */
}
/* Load the OS */
if (!ret && (states & BOOTM_STATE_LOADOS)) {
ulong load_end;
iflag = bootm_disable_interrupts();
ret = bootm_load_os(images, &load_end, 0);
if (ret == 0)
lmb_reserve(&images->lmb, images->os.load,
(load_end - images->os.load));
else if (ret && ret != BOOTM_ERR_OVERLAP)
goto err;
else if (ret == BOOTM_ERR_OVERLAP)
ret = 0;
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
if (images->os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif
}
/* Relocate the ramdisk */
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
if (!ret && (states & BOOTM_STATE_RAMDISK)) {
ulong rd_len = images->rd_end - images->rd_start;
ret = boot_ramdisk_high(&images->lmb, images->rd_start,
rd_len, &images->initrd_start, &images->initrd_end);
if (!ret) {
setenv_hex("initrd_start", images->initrd_start);
setenv_hex("initrd_end", images->initrd_end);
}
}
#endif
#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
if (!ret && (states & BOOTM_STATE_FDT)) {
boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
&images->ft_len);
}
#endif
/* From now on, we need the OS boot function */
if (ret)
return ret;
boot_fn = bootm_os_get_boot_func(images->os.os);
need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
if (boot_fn == NULL && need_boot_fn) {
if (iflag)
enable_interrupts();
printf("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images->os.os), images->os.os);
bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
return 1;
}
/* Call various other states that are not generally used */
if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_BD_T))
ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_PREP))
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
#ifdef CONFIG_TRACE
/* Pretend to run the OS, then run a user command */
if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
char *cmd_list = getenv("fakegocmd");
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
images, boot_fn);
if (!ret && cmd_list)
ret = run_command_list(cmd_list, -1, flag);
}
#endif
/* Check for unsupported subcommand. */
if (ret) {
puts("subcommand not supported\n");
return ret;
}
/* Now run the OS! We hope this doesn't return */
if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn);
/* Deal with any fallout */
err:
if (iflag)
enable_interrupts();
if (ret == BOOTM_ERR_UNIMPLEMENTED)
bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
else if (ret == BOOTM_ERR_RESET)
do_reset(cmdtp, flag, argc, argv);
return ret;
}do_bootm_states函数总共分8个部分:
⑴、 Work through the states and see how far we get. We stop on any error.
其中主要函数bootm_find_os实现三个功能:get kernel image header, start address and length,get image parameters。大概过程是:bootm_find_os -> boot_get_kernel -> image_get_kernel 。
boot_get_kernel - find kernel image(returns:
pointer to image header if valid image was found, plus kernel start address and length, otherwise NULL)image_get_kernel - verify legacy format kernel image(returns:
pointer to a legacy image header if valid image was found otherwise return NULL)
⑵、Load the OS
⑶、Relocate the ramdisk
⑷、From now on, we need the OS boot function
由
①、关于参数images->os.os,可以由下列定义得知它是系统内核的类型,并在(2)中被赋值,若系统类型为linux,则images->os.os=5。typedef struct bootm_headers {
...
#ifndef USE_HOSTCC /*USE_HOSTCC 没有宏定义*/
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
ulong rd_start, rd_end;/* ramdisk start/end */
char *ft_addr; /* flat dev tree address */
ulong ft_len; /* length of flat device tree */
ulong initrd_start;
ulong initrd_end;
ulong cmdline_start;
ulong cmdline_end;
bd_t *kbd;
#endif
...
} bootm_headers_t;
得到images.os.os的值:
⑹、Check for unsupported subcommand
⑺、Now run the OS! We hope this doesn’t return
8、执行
说明:
关于
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_loop 后便不再返回。4、在run_main_loop 里会进入u-boot-2016.05\common\main.c:main_loop函数static int run_main_loop(void)
{
...
for (;;)
main_loop();
return 0;
}进入main_loop之前就已经完成初始化,接下来准备去处理命令/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
const char *s;
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
...
/* get environment_variable: s = getenv("bootcmd"); -> bootcmd */
s = bootdelay_process();
...
autoboot_command(s);
...
}main_loop函数里有两个重要的过程:
⑴、首先在bootdelay_process函数里通过s = getenv(“bootcmd”)得到bootcmd参数并返回bootcmd参数,const char *bootdelay_process(void)
{
char *s;
int bootdelay;
...
s = getenv("bootdelay");
...
debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
...
s = getenv("bootcmd");
...
stored_bootdelay = bootdelay;
return s;
}其中,bootcmd参数通过以下方式指定:
先在u-boot-2016.05\include\env_default.h中#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif再在u-boot-2016.05\include\configs\smdk2440.h中指定#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel;bootm 30000000"⑵、然后进入autoboot_command函数,并将bootcmd参数传入,继而进入run_command_list函数,继续将bootcmd参数传入
void autoboot_command(const char *s) { ... if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { ... run_command_list(s, -1, 0); ... } ... }5、从autoboot_command函数进入u-boot-2016.05\common\cli.c:run_command_list函数后,接着会调用board_run_command函数去执行命令int run_command_list(const char *cmd, int len, int flag)
{
int need_buff = 1;
char *buff = (char *)cmd; /* cast away const */
int rcode = 0;
if (len == -1) {
len = strlen(cmd);
#ifdef CONFIG_SYS_HUSH_PARSER
...
#else
/* the built-in parser will change our string if it sees \n */
need_buff = strchr(cmd, '\n') != NULL;
#endif
}
if (need_buff) {
buff = malloc(len + 1);
if (!buff)
return 1;
memcpy(buff, cmd, len);
buff[len] = '\0';
}
#ifdef CONFIG_SYS_HUSH_PARSER
...
#ifdef CONFIG_CMDLINE
...
#else
rcode = board_run_command(buff);
#endif
#endif
...
}那么,board_run_command如何去执行命令?
首先,board_run_command函数通过bootcmd参数中的bootm命令找到u-boot-2016.05\cmd\bootm.c中的U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
"boot application image from memory", bootm_help_text
);然后,根据这个信息找到执行bootm命令的处理函数指针do_bootm,并进入do_bootm函数执行相关代码,而U_BOOT_CMD在u-boot-2016.05\include\command.h中定义:#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)在此,board_run_command函数还会将bootm命令中的参数(内核映像所在地址)30000000赋给bootm_headers_t结构体变量images,则images首地址就是30000000,images在u-boot-2016.05\cmd\bootm.c中定义:bootm_headers_t images; 6、根据U_BOOT_CMD信息进入u-boot-2016.05\cmd\bootm.c:do_bootm函数int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
...
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
BOOTM_STATE_OS_CMDLINE |
#endif
BOOTM_
eda8
STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO, &images, 1);
}7、从do_bootm进入u-boot-2016.05\common\bootm.c:do_bootm_states函数,Now run the OS!int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
/*
* Work through the states and see how far we get. We stop on
* any error.
*/
if (states & BOOTM_STATE_START)
ret = bootm_start(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOS))
ret = bootm_find_os(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
ret = bootm_find_other(cmdtp, flag, argc, argv);
argc = 0; /* consume the args */
}
/* Load the OS */
if (!ret && (states & BOOTM_STATE_LOADOS)) {
ulong load_end;
iflag = bootm_disable_interrupts();
ret = bootm_load_os(images, &load_end, 0);
if (ret == 0)
lmb_reserve(&images->lmb, images->os.load,
(load_end - images->os.load));
else if (ret && ret != BOOTM_ERR_OVERLAP)
goto err;
else if (ret == BOOTM_ERR_OVERLAP)
ret = 0;
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
if (images->os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif
}
/* Relocate the ramdisk */
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
if (!ret && (states & BOOTM_STATE_RAMDISK)) {
ulong rd_len = images->rd_end - images->rd_start;
ret = boot_ramdisk_high(&images->lmb, images->rd_start,
rd_len, &images->initrd_start, &images->initrd_end);
if (!ret) {
setenv_hex("initrd_start", images->initrd_start);
setenv_hex("initrd_end", images->initrd_end);
}
}
#endif
#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
if (!ret && (states & BOOTM_STATE_FDT)) {
boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
&images->ft_len);
}
#endif
/* From now on, we need the OS boot function */
if (ret)
return ret;
boot_fn = bootm_os_get_boot_func(images->os.os);
need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
if (boot_fn == NULL && need_boot_fn) {
if (iflag)
enable_interrupts();
printf("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images->os.os), images->os.os);
bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
return 1;
}
/* Call various other states that are not generally used */
if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_BD_T))
ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_PREP))
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
#ifdef CONFIG_TRACE
/* Pretend to run the OS, then run a user command */
if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
char *cmd_list = getenv("fakegocmd");
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
images, boot_fn);
if (!ret && cmd_list)
ret = run_command_list(cmd_list, -1, flag);
}
#endif
/* Check for unsupported subcommand. */
if (ret) {
puts("subcommand not supported\n");
return ret;
}
/* Now run the OS! We hope this doesn't return */
if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn);
/* Deal with any fallout */
err:
if (iflag)
enable_interrupts();
if (ret == BOOTM_ERR_UNIMPLEMENTED)
bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
else if (ret == BOOTM_ERR_RESET)
do_reset(cmdtp, flag, argc, argv);
return ret;
}do_bootm_states函数总共分8个部分:
⑴、 Work through the states and see how far we get. We stop on any error.
其中主要函数bootm_find_os实现三个功能:get kernel image header, start address and length,get image parameters。大概过程是:bootm_find_os -> boot_get_kernel -> image_get_kernel 。
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; bool ep_found = false; int ret; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); ... /* get image parameters */ switch (genimg_get_format(os_hdr)) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) case IMAGE_FORMAT_LEGACY: /*旧系统格式的内核映像*/ images.os.type = image_get_type(os_hdr); images.os.comp = image_get_comp(os_hdr); images.os.os = image_get_os(os_hdr); images.os.end = image_get_image_end(os_hdr); images.os.load = image_get_load(os_hdr); images.os.arch = image_get_arch(os_hdr); break; #endif #if IMAGE_ENABLE_FIT case IMAGE_FORMAT_FIT: ... #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE case IMAGE_FORMAT_ANDROID: ... #endif default: puts("ERROR: unknown image format type!\n"); return 1; } ... if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { images.os.load = images.os.image_start; images.ep += images.os.load; } ...关于boot_get_kernel 、image_get_kernel 的说明:
boot_get_kernel - find kernel image(returns:
pointer to image header if valid image was found, plus kernel start address and length, otherwise NULL)image_get_kernel - verify legacy format kernel image(returns:
pointer to a legacy image header if valid image was found otherwise return NULL)
⑵、Load the OS
⑶、Relocate the ramdisk
⑷、From now on, we need the OS boot function
由
boot_fn = bootm_os_get_boot_func(images->os.os);得到boot处理函数指针并赋给boot_fn。
①、关于参数images->os.os,可以由下列定义得知它是系统内核的类型,并在(2)中被赋值,若系统类型为linux,则images->os.os=5。typedef struct bootm_headers {
...
#ifndef USE_HOSTCC /*USE_HOSTCC 没有宏定义*/
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
ulong rd_start, rd_end;/* ramdisk start/end */
char *ft_addr; /* flat dev tree address */
ulong ft_len; /* length of flat device tree */
ulong initrd_start;
ulong initrd_end;
ulong cmdline_start;
ulong cmdline_end;
bd_t *kbd;
#endif
...
} bootm_headers_t;
bootm_headers_t images;
typedef struct image_info { ulong start, end; /* start/end of blob */ ulong image_start, image_len; /* start of image within blob, len of image */ ulong load; /* load addr for the image */ uint8_t comp, type, os; /* compression, type of image, os type */ uint8_t arch; /* CPU architecture */ } image_info_t;
得到images.os.os的值:
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { const void *os_hdr; ... /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); ... /* get image parameters */ switch (genimg_get_format(os_hdr)) { #if defined(CONFIG_IMAGE_FORMAT_LEGACY) case IMAGE_FORMAT_LEGACY: /*旧系统格式的内核映像*/ ... images.os.os = image_get_os(os_hdr); ... break; #endif②、bootm_os_get_boot_func中会用到函数指针数组boot_os,该数组利用传入的images.os.os=5的值得到boot处理函数指针do_bootm_linux返回给boot_fn 。
boot_fn = bootm_os_get_boot_func(images->os.os);
boot_os_fn *bootm_os_get_boot_func(int os) { ... return boot_os[os]; }
static boot_os_fn *boot_os[] = { [IH_OS_U_BOOT] = do_bootm_standalone, #ifdef CONFIG_BOOTM_LINUX [IH_OS_LINUX] = do_bootm_linux, #endif #ifdef CONFIG_BOOTM_NETBSD [IH_OS_NETBSD] = do_bootm_netbsd, #endif ... };操作系统代号可在u-boot-2016.05\include\image.h中查看
/* * Operating System Codes */ #define IH_OS_INVALID 0 /* Invalid OS */ #define IH_OS_OPENBSD 1 /* OpenBSD */ #define IH_OS_NETBSD 2 /* NetBSD */ #define IH_OS_FREEBSD 3 /* FreeBSD */ #define IH_OS_4_4BSD 4 /* 4.4BSD */ #define IH_OS_LINUX 5 /* Linux */ ...⑸、Call various other states that are not generally used
⑹、Check for unsupported subcommand
⑺、Now run the OS! We hope this doesn’t return
if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, images, boot_fn);从do_bootm_states进入u-boot-2016.05\common\bootm_os.c:boot_selected_os函数,执行
boot_fn(state, argc, argv, images);
int boot_selected_os(int argc, char * const argv[], int state, bootm_headers_t *images, boot_os_fn *boot_fn) { ... boot_fn(state, argc, argv, images); ... }⑻、Deal with any fallout
8、执行
boot_fn(state, argc, argv, images),因为boot_fn=do_bootm_linux,所以相当于执行
do_bootm_linux(state, argc, argv, images),程序跳到u-boot-2016.05\arch\arm\lib\bootm.c:
/* Main Entry point for arm bootm implementation*/ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { ... boot_jump_linux(images, flag); ... }do_bootm_linux -> boot_jump_linux -> kernel_entry(0, machid, r2);
static void boot_jump_linux(bootm_headers_t *images, int flag) { ... unsigned long machid = gd->bd->bi_arch_number; char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; /* ep:entry point of OS*/ s = getenv("machid"); if (s) { if (strict_strtoul(s, 16, &machid) < 0) { debug("strict_strtoul failed!\n"); return; } printf("Using machid 0x%lx from environment\n", machid); } ... if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) { ... kernel_entry(0, machid, r2); } #endif }run the OS!
说明:
关于
kernel_entry = (void (*)(int, int, uint))images->ep;中的images->ep在u-boot-2016.05\common\bootm.c:bootm_find_os函数中被赋值。
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { ... if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { images.os.load = images.os.image_start; images.ep += images.os.load; } ... }
相关文章推荐
- u-boot-2016.05启动流程
- u-boot-2016.05启动流程
- u-boot-2016.05启动流程
- u-boot-2016.05启动流程
- u-boot-2016.05启动流程
- Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析
- spring boot 启动流程
- 转:AM335x启动流程(BootRom->MLO->Uboot)
- (七)u-boot2013.01.01 for s5pv210:《u-boot启动流程》
- u-boot启动流程
- 2014.4新版uboot启动流程分析
- Spring Boot 启动流程详解(二)
- SpringBoot启动流程简析(一)
- 基于ar9331 mips架构AP121 uboot分析(4) 启动流程 Stage1
- linux系统启动流程及 MBR损坏,grub内容,文件误删,boot目录,分区误删修复
- 97. SpringBoot-启动流程分析第一篇
- SpringBoot:深入探索内嵌tomcat启动流程
- AM335x启动流程(BootRom->MLO->Uboot)
- UBOOT-2012-10在OK6410平台的移植(二)uboot 2012.10启动流程
- U-BOOT的启动流程及移植