uboot从bootm跳到内核
(2014-03-18 23:28:59)
标签:
it |
分类: uboot移植 |
main_loop中执行的最重要的操作便是引导内核。引导分两步。第一步先读取内核镜像uImage到内存。然后再使用bootm引导内核。
读取内核只是进行内存复制,因此仅仅需要分析bootm。
2。boot_os
3。do_bootm_linux
之前所做的引导工作都是与操作系统无关的,接下来都是针对linux 的。
可以看到,参数flag传过来的是0。
4.
5.
http://daimajishu.iteye.com/blog/1087397
读取内核只是进行内存复制,因此仅仅需要分析bootm。
Cpp代码
-
-
-
-
引导应用程序在内存中的镜像。
-
common/cmd_bootm.c
-
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; -
检查是否有子命令 -
if (argc > 1) { -
char *endp; -
simple_strtoul(argv[1], &endp, 16); //调用字符串转无符号整形的函数,endp指向尾字符。 -
-
if ((*endp != 0) && (*endp != ':') && (*endp != '#')) //是否有子命令。一般不会有,所以这个路径不会执行。 -
return do_bootm_subcommand(cmdtp, flag, argc, argv); -
} -
if (bootm_start(cmdtp, flag, argc, argv)) //bootm_start的分析见下一篇文章。这个函数执行成功返回0,失败返回1。这个函数主要用于获取镜像的信息并存入images。 -
return 1; -
-
iflag = disable_interrupts();//禁用中断。 -
ret = bootm_load_os(images.os, &load_end, 1);//将镜像的数据从images.os.image_start复制到images.os.load 打印:Loading Kernel Image ... OK -
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));//由于没有定义CONFIG_LMB,这个函数调用被定义为一个空的宏。 -
if (images.os.type == IH_TYPE_STANDALONE) {//处理单独的程序镜像。显然引导内核时不会进入这个路径。 -
if (iflag) -
enable_interrupts(); -
-
bootm_start_standalone(iflag, argc, argv); -
return 0; -
} -
show_boot_progress (8); -
boot_fn = boot_os[images.os.os];//根据操作系统的类型获取引导操作系统的函数, boot_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; -
} -
arch_preboot_os();//禁用中断,重设中断向量 -
boot_fn(0, argc, argv, &images);//调用do_bootm_linux,分析在下面。 -
show_boot_progress (-9); -
#ifdef
DEBUG -
puts ("\n## Control );returned to monitor - resetting...\n" -
#endif
-
do_reset (cmdtp, flag, argc, argv); -
return 1; -
}
2。boot_os
Cpp代码
-
static
boot_os_fn *boot_os[] = { -
#ifdef
CONFIG_BOOTM_LINUX -
[IH_OS_LINUX] = do_bootm_linux, -
#endif
-
#ifdef
CONFIG_BOOTM_NETBSD -
[IH_OS_NETBSD] = do_bootm_netbsd, -
#endif
-
#ifdef
CONFIG_LYNXKDI -
[IH_OS_LYNXOS] = do_bootm_lynxkdi, -
#endif
-
#ifdef
CONFIG_BOOTM_RTEMS -
[IH_OS_RTEMS] = do_bootm_rtems, -
#endif
-
#if
defined(CONFIG_CMD_ELF) -
[IH_OS_VXWORKS] = do_bootm_vxworks, -
[IH_OS_QNX] = do_bootm_qnxelf, -
#endif
-
#ifdef
CONFIG_INTEGRITY -
[IH_OS_INTEGRITY] = do_bootm_integrity, -
#endif
-
};
3。do_bootm_linux
之前所做的引导工作都是与操作系统无关的,接下来都是针对linux 的。
可以看到,参数flag传过来的是0。
Cpp代码
-
arch/arm/lib/bootm.c
-
int
do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) -
{
-
bd_t *bd = gd->bd; -
char *s; -
int machid = bd->bi_arch_number; -
void (*theKernel)(int zero, int arch, uint params); -
#ifdef
CONFIG_CMDLINE_TAG//如果定义了这个宏,将会把bootargs传给内核。 -
char *commandline = getenv ("bootargs");//获取bootargs环境变量。 -
#endif
-
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) -
return 1; -
theKernel = (void (*)(int, int, uint))images->ep;//镜像的入口地址处也就是需要执行的函数入口 -
s = getenv ("machid"); -
if (s) { -
machid = simple_strtoul (s, NULL, 16); -
printf ("Using machid ,0x%x from environment\n" machid); -
} -
show_boot_progress (15); -
debug ("## Transferring ,control to Linux (at address lx) ...\n" -
(ulong) theKernel); -
//下面将会初始化传给内核的标签(tag),这些标签里包含了必要的环境变量和参数。
-
#if
defined (CONFIG_SETUP_MEMORY_TAGS) || \ -
defined (CONFIG_CMDLINE_TAG) || \ -
defined (CONFIG_INITRD_TAG) || \ -
defined (CONFIG_SERIAL_TAG) || \ -
defined (CONFIG_REVISION_TAG) -
setup_start_tag (bd); -
#ifdef
CONFIG_SETUP_MEMORY_TAGS -
setup_memory_tags (bd);//内存有关的定义 -
#endif
-
#ifdef
CONFIG_CMDLINE_TAG -
setup_commandline_tag (bd, commandline);//将bootargs传给tag -
#endif
-
#ifdef
CONFIG_INITRD_TAG -
if (images->rd_start && images->rd_end)//没有ramdisk所以不会执行这个路径 -
setup_initrd_tag (bd, images->rd_start, images->rd_end); -
#endif
-
setup_end_tag (bd); -
#endif
-
-
printf ("\nStarting kernel );//引导内核之前最后一次打印信息。...\n\n" -
cleanup_before_linux ();//禁用中断和cache. -
theKernel (0, machid, bd->bi_boot_params);//跳到内核中执行。<<<<全剧终>>>> -
-
return 1; -
}
4.
Cpp代码
-
arch/arm/include/asm
-
-
#define
ATAG_CORE 0x54410001 -
struct
tag_core { -
u32 flags; -
u32 pagesize; -
u32 rootdev; -
};
-
-
#define
ATAG_CMDLINE 0x54410009 -
struct
tag_cmdline {//bootargs保存在它的后面 -
char cmdline[1]; -
};
-
-
-
#define
ATAG_INITRD 0x54410005 -
-
#define
ATAG_INITRD2 0x54420005 -
struct
tag_initrd {//描述ramdisk的分布 -
u32 start; -
u32 size; -
};
-
-
#define
ATAG_MEM 0x54410002 -
struct
tag_mem32 { -
u32 size; -
u32 start; -
};
-
struct
tag_header { -
u32 size; -
u32 tag; -
};
-
struct
tag { -
struct tag_header hdr; -
union { -
struct tag_core core; -
struct tag_mem32 mem; -
struct tag_videotext videotext; -
struct tag_ramdisk ramdisk; -
struct tag_initrd initrd; -
struct tag_serialnr serialnr; -
struct tag_revision revision; -
struct tag_videolfb videolfb; -
struct tag_cmdline cmdline; -
-
struct tag_acorn acorn; -
-
struct tag_memclk memclk; -
} u; -
};
5.
Cpp代码
-
arch/arm/include/asm/setup.h
-
#define
tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))//跳到下一个tag地址处 -
arch/arm/lib/bootm.c
-
static
void setup_start_tag (bd_t *bd) -
{
-
params = (struct tag *) bd->bi_boot_params; //CFG_ENV_ADDR(0x80000100)设置环境变量的头地址。 -
params->hdr.tag = ATAG_CORE; //第一个tag默认为 tag_core。ATAG_CORE 是默认的开始类型。 -
params->hdr.size = tag_size (tag_core); -
params->u.core.flags = 0; -
params->u.core.pagesize = 0; -
params->u.core.rootdev = 0; -
params = tag_next (params); //跳到下一个tag地址处 -
}
-
#ifdef
CONFIG_SETUP_MEMORY_TAGS -
static
void setup_memory_tags (bd_t *bd)//设置内存分布的tag -
{
-
int i; -
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {//如果有多个内存芯片,则会循环多次。对3250来说,只有一片。 -
params->hdr.tag = ATAG_MEM; -
params->hdr.size = tag_size (tag_mem32); -
params->u.mem.start = bd->bi_dram[i].start;//内存块的开始地址。PHYS_SDRAM_1;在smartarm3250.h中,起始地址(0x80000000) -
params->u.mem.size = bd->bi_dram[i].size;//内存块的大小 -
params = tag_next (params);//跳到下一个tag地址处 -
} -
}
-
#endif
-
static
void setup_commandline_tag (bd_t *bd, char *commandline) -
{
-
char *p; -
if (!commandline) -
return; -
-
for (p = commandline; *p == ' ' ;p++);//跳过开头的空格 -
-
if (*p == '\0') -
return; -
params->hdr.tag = ATAG_CMDLINE; -
params->hdr.size = -
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2; -
strcpy (params->u.cmdline.cmdline, p);//将bootargs复制到cmdline后面。 -
params = tag_next (params);//跳到下一个tag地址处 -
}
-
#ifdef
CONFIG_INITRD_TAG -
static
void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end) -
{
-
-
params->hdr.tag = ATAG_INITRD2; -
params->hdr.size = tag_size (tag_initrd); -
params->u.initrd.start = initrd_start; -
params->u.initrd.size = initrd_end - initrd_start; -
params = tag_next (params); -
}
-
#endif
-
static
void setup_end_tag (bd_t *bd) -
{
-
params->hdr.tag = ATAG_NONE;//最后一个tag是一个空类型,标志这tag的结束。 -
params->hdr.size = 0; -
}