记录自己学习android系统启动以及 recovery过程(1)----------uboot
欢迎指出其中错误。
启动uboot bootm文件作为uboot->kernel的最后一个步骤,负责引导内核,并配置需要传递进内核的相关参数
在uboot启动后,会检查是否需要recovery,一般通过两个途径, 1.挂载boot device,并查看/cache/recovery文件,2.按键检测,当需要进行recovery时,会重新设置启动的环境变量。
system image和recovery的环境变量主要区别在于:
system : bootm (kernel_addr) (ramdisk_addr)
recovery: bootm或者bootm (kernel_addr) root=/dev/mmcblk0px
uboot阶段通过对bootm代码的执行,来设置传递进内核的参数,通知内核是挂载recovery 还是运行system。
相关代码分析:
1. do_bootm函数
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
ulong iflag;
ulong load_end = 0;
int ret;
boot_os_fn *boot_fn;
/* relocate boot function table */
/*重定位 boot_os内部函数指针地址,启动包含do_bootm_linux。因为在uboot启动的最初阶段,会对uboot的text,data,bss..进行一次搬移*/
if (!relocated) {
int i;
for (i = 0; i < ARRAY_SIZE(boot_os); i++)
if (boot_os[i] != NULL)
boot_os[i] += gd->reloc_off;
relocated = 1;
}
/* determine if we have a sub command */
/* 当传进来参数多于一个时,判断参数类型,并执行。在android正常启动模式下,参数模式是 bootm kernel_addr rd_addr,多于3个,但是参数endp是0,不会return*/
if (argc > 1) {
char *endp;
simple_strtoul(argv[1], &endp, 16);
/* endp pointing to NULL means that argv[1] was just a
* valid number, pass it along to the normal bootm processing
*
* If endp is ':' or '#' assume a FIT identifier so pass
* along for normal processing.
*
* Right now we assume the first arg should never be '-'
*/
if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
return do_bootm_subcommand(cmdtp, flag, argc, argv);
}
/* do_bootm重要函数,主要用来查看,验证 uImage, ramdisk,并初始化一个结构体images,类型为bootm_headers_t,后续会详细解析*/
if (bootm_start(cmdtp, flag, argc, argv))
return 1;
/*
* We have reached the point of no return: we are going to
* overwrite all exception vector code, so we cannot easily
* recover from any failures any more...
*/
iflag = disable_interrupts();
#if defined(CONFIG_CMD_USB)
/*
* turn off USB to prevent the host controller from writing to the
* SDRAM while Linux is booting. This could happen (at least for OHCI
* controller), because the HCCA (Host Controller Communication Area)
* lies within the SDRAM and the host controller writes continously to
* this area (as busmaster!). The HccaFrameNumber is for example
* updated every 1 ms within the HCCA structure in SDRAM! For more
* details see the OpenHCI specification.
*/
usb_stop();
#endif
#ifdef CONFIG_AMIGAONEG3SE
/*
* We've possible left the caches enabled during
* bios emulation, so turn them off again
*/
icache_disable();
dcache_disable();
#endif
/*下面函数,是用来将kernel的uImage 解压并拷贝到指定的运行地址*/
ret = bootm_load_os(images.os, &load_end, 1);
if (ret < 0) {
if (ret == BOOTM_ERR_RESET)
do_reset (cmdtp, flag, argc, argv);
if (ret == BOOTM_ERR_OVERLAP) {
if (images.legacy_hdr_valid) {
if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
puts ("WARNING: legacy format multi component "
"image overwritten\n");
} else {
puts ("ERROR: new format image overwritten - "
"must RESET the board to recover\n");
show_boot_progress (-113);
do_reset (cmdtp, flag, argc, argv);
}
}
if (ret == BOOTM_ERR_UNIMPLEMENTED) {
if (iflag)
enable_interrupts();
show_boot_progress (-7);
return 1;
}
}
lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
if (images.os.type == IH_TYPE_STANDALONE) {
if (iflag)
enable_interrupts();
/* This may return when 'autostart' is 'no' */
bootm_start_standalone(iflag, argc, argv);
return 0;
}
show_boot_progress (8);
#ifdef CONFIG_SILENT_CONSOLE
if (images.os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif
/*image.os.os在bootm_start函数中被初始化,此处,boot_fn就等于do_bootm_linux*/
boot_fn = boot_os[images.os.os];
if (boot_fn == NULL) {
if (iflag)
enable_interrupts();
printf ("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images.os.os), images.os.os);
show_boot_progress (-8);
return 1;
}
/*调用do_bootm_linux引导内核并启动*/
boot_fn(0, argc, argv