do_bootm函数位于common/cmd_bootm.c文件中。
do_bootm函数调用do_bootm_linux函数启动linux内核,当定义了CONFIG_PPC时将使用common/cmd_bootm.c文件中的do_bootm_linux函数;当系统中没有定义该宏时,系统将使用lib_arm/armlinux.c文件中定义的do_bootm_linux函数。注意:这两个函数有很大的区别!
lib_arm/armlinux.c中do_bootm_linux函数源代码:
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
ulong addr, ulong *len_ptr, int verify)
{
DECLARE_GLOBAL_DATA_PTR;
ulong len = 0, checksum;
ulong initrd_start, initrd_end;
ulong data;
void (*theKernel)(int zero, int arch, uint params);
image_header_t *hdr = &header;
bd_t *bd = gd->bd;
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs");
#endif
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); // 设置kernal加载地址
// 用户自定义了initrd之后需要加载进来
// 整个过程需要进行头部以及整个数据内部校验
// 类似于内核的加载校验,这里省略了。
// 下面仅仅列出了无randisk时的处理:
initrd_start = 0;
initrd_end = 0;
SHOW_BOOT_PROGRESS (15);
// 在psbec270.h文件中定义了如下宏
// #define CONFIG_CMDLINE_TAG
// #define CONFIG_SETUP_MEMORY_TAGS
// #define CONFIG_INITRD_TAG
// 根据上面不同的宏加载不同的TAG
// 注意的是必须定义CONFIG_CMDLINE_TAG和CONFIG_SETUP_MEMORY_TAGS
// 除非内核已经根据系统初始化了这些值, 否则必须定义, 不定义将导致无法启动.
#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)
setup_start_tag (bd);
#ifdef CONFIG_SETUP_MEMORY_TAGS
// 设置memory tags
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
// 设置启动命令行tags
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (initrd_start && initrd_end) // 存在ramdisk时设置initrdtag
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
setup_end_tag (bd);
#endif
// 接下来开始调用执行内核启动
printf ("nStarting kernel ...nn");
// 启动之前先做一些清理工作,见下面说明
cleanup_before_linux ();
// 调用内核需要传递的参数如下:
// R0:必须为0
// R1:机器类型ID,本机为ARM(bd->bi_arch_number)
// R2:启动参数列表在内存中的位置(bd->bi_boot_params)
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
}
// 清理工作,调用内核之前必须满足如下条件才可以:
// CPU模式:
// 必须禁止中断(IRQs和FIQs);
// CPU 必须 SVC 模式;
// Cache和MMU的设置:
// MMU 必须关闭;
// 指令 Cache 可以打开也可以关闭;
// 数据 Cache 必须关闭;
int cleanup_before_linux (void)
{
unsigned long i;
disable_interrupts (); // 禁止中断
// 关闭指令和数据cache
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~(C1_DC | C1_IC);
asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
i = 0;
asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i));
return (0);
}
联系客服