uboot找到了可支持启动的内核镜像,并不是立马去启动它。为什么不能立马去启动它呢?因为整个内核镜像并不仅仅是内核的有效信息,还有有关内核描述的相关信息,因此先找到内核镜像的启动入口才是关键,下面是详细的过程:
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
bootm_headers_t *images)
{
ulong initrd_start, initrd_end;
ulong ep = 0;
bd_t *bd = gd->bd;
char *s;
int machid = bd->bi_arch_number; // 机器码
void (*theKernel)(int zero, int arch, uint params);
int ret;
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs"); //获取命令
#endif
/* find kernel entry point */ //kernel内核入口不是在起始头部,头部前面可能解压缩代码、镜像格式信息等等。
if (images->legacy_hdr_valid) {
ep = image_get_ep (&images->legacy_hdr_os_copy);
#if defined(CONFIG_FIT)
} else if (images->fit_uname_os) {
ret = fit_image_get_entry (images->fit_hdr_os, //内核入口于镜像头寻在偏移量
images->fit_noffset_os, &ep);
if (ret) {
puts ("Can't get entry point property!\n");
goto error;
}
#endif
} else {
puts ("Could not find kernel entry point!\n");
goto error;
}
theKernel = (void (*)(int, int, uint))ep; //将ep的值赋值给theKernel,这是kernel开始执行的第一句代码
s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, 16);
printf ("Using machid 0x%x from environment\n", machid);
}
ret = boot_get_ramdisk (argc, argv, images, IH_ARCH_ARM,
&initrd_start, &initrd_end);
if (ret)
goto error;
show_boot_progress (15);
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) theKernel);
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG) || \
defined (CONFIG_LCD) || \
defined (CONFIG_VFD) || \
defined (CONFIG_MTDPARTITION)
setup_start_tag (bd); //这里的bd指的是gd->bd->bi_arch_number ,是前面结果两次转换过来的
#ifdef CONFIG_SERIAL_TAG //
setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (initrd_start && initrd_end)
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
setup_videolfb_tag ((gd_t *) gd);
#endif
#ifdef CONFIG_MTDPARTITION
setup_mtdpartition_tag();
#endif
setup_end_tag (bd);
#endif
/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n"); //打印出来这一句说明uboot死掉了
//同时说明uboot成功校验zImage类型、找到kernel的入口地址、成功加载了整个内核到DDR中了
#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
}
#endif
cleanup_before_linux ();
theKernel (0, machid, bd->bi_boot_params);
/* does not return */
return;
error:
do_reset (cmdtp, flag, argc, argv); //uboot错误重启
return;
}
当然,找到内核入口前还是有很多东西要做的,比如:获取机器码、获取环境变量参数等等,找到内核入口(entry point)然后才开始执行内核第一句代码(theKernel = xxxx)、如果打印出来(Strating Kernel.....),说明了uboot整个阶段(包括第一阶段第二阶段)都是正常的、zImage类型校验成功、找到了kernel所在、机器码、环境变量、kernel入口、并执行了kernel的第一行代码、成功加载内核镜像到DDR并在DDR中执行了内核解压缩的那段代码,至此,uboot负责启动内核的使命就完成了....