uboot中启动linux内核的函数——do_bootm_linux函数解析
Posted 代二毛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uboot中启动linux内核的函数——do_bootm_linux函数解析相关的知识,希望对你有一定的参考价值。
1、do_bootm_linux函数解析
do_bootm_linux函数是专门启动linux内核的,包括以下功能:
(1)确认当前的机器码,可以从全局变量gd或者环境变量machid中获取,其中环境变量machid的优先级高于gd中的机器码;
(2)计算出内核的入口地址;
(3)准备给内核的传参;不清楚uboot给内核传参的看博客:《uboot中命令体系详解》。
(4)协处理器的相关操作,为启动内核初始化环境;
(5)启动内核;
2、启动内核入口的传参
(1)
theKernel (0, machid, bd->bi_boot_params);
theKernel 是函数指针,指向内核的入口地址,也就是内核将要执行的第一句代码。其中要传三个参数,第一个参数固定为0,第二个参数是机器码,第三个参数是uboot传给内核参数所在的首地址。
(2)机器码
机器码可以算作是一块板子的id,嵌入式设备是高度定制的,内核也是可以高度裁剪的,所以每个版本的内核只能支持移植过开发板。在内核中维护有个表格,里面记录了支持的开发板的id,也就是机器码,如果启动内核时传入的机器码没有在表格中找到,说明内核不支持该开发板,启动失败。
3、do_bootm_linux函数源码
#define CONFIG_BOOTARGS "console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3"
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; //从全局变量gd中获取机器码
void (*theKernel)(int zero, int arch, uint params);
int ret;
#ifdef CONFIG_CMDLINE_TAG
//对应宏:CONFIG_BOOTARGS,bootargs是启动内核的传的参数
char *commandline = getenv ("bootargs");
#endif
/* find kernel entry point */
if (images->legacy_hdr_valid) {
ep = image_get_ep (&images->legacy_hdr_os_copy); //得到内核的入口地址
} else {
puts ("Could not find kernel entry point!\\n");
goto error;
}
//theKernel 是函数指针,指向内核的入口地址
theKernel = (void (*)(int, int, uint))ep;
//从环境变量获取机器码,这里可以看出环境变量里的机器码优先级高于全局变量gd里的机器码
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); //传递给内核参数的起始tag结构体
#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
//传递给内核参数的结束tag结构体
setup_end_tag (bd);
#endif
/* we assume that the kernel is in place */
printf ("\\nStarting kernel ...\\n\\n");
#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
}
#endif
/*启动内核前的设置,主要是协处理器的相关操作,包括关iCache和dCache等*/
cleanup_before_linux ();
/*这句是真正启动内核的语句,到此uboot的使命就结束了;
theKernel是内核的入口地址,也就是内核执行的第一句代码;
第1个参数固定为0,第2个参数是机器码,第3个参数是传递给内存的传参tag的首地址*/
theKernel (0, machid, bd->bi_boot_params);
/* does not return */
return;
error:
do_reset (cmdtp, flag, argc, argv);
return;
}
以上是关于uboot中启动linux内核的函数——do_bootm_linux函数解析的主要内容,如果未能解决你的问题,请参考以下文章