uboot从bootm跳到内核

============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu


版权没有,但是转载请保留此段声明
============================================


main_loop中执行的最重要的操作便是引导内核。引导分两步。第一步先读取内核镜像uImage到内存。然后再使用bootm引导内核。
读取内核只是进行内存复制,因此仅仅需要分析bootm。
/*******************************************************************/ /* bootm - boot application image from image in memory */ /*******************************************************************/ 引导应用程序在内存中的镜像。 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; /* determine if we have a sub command */检查是否有子命令 if (argc > 1) { char *endp; simple_strtoul(argv[1], &endp, 16); //调用字符串转无符号整形的函数,endp指向尾字符。 /* 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); } if (bootm_start(cmdtp, flag, argc, argv)) //bootm_start的分析见下一篇文章。这个函数执行成功返回0,失败返回1。这个函数主要用于获取镜像的信息并存入images。 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();//禁用中断。 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(); /* This may return when 'autostart' is 'no' */ 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
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。
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 %08lx) .../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 /* we assume that the kernel is in place */ printf ("/nStarting kernel .../n/n");//引导内核之前最后一次打印信息。 cleanup_before_linux ();//禁用中断和cache. theKernel (0, machid, bd->bi_boot_params);//跳到内核中执行。<<<<全剧终>>>> /* does not return */ return 1; }


4.
arch/arm/include/asm /* The list must start with an ATAG_CORE node */ #define ATAG_CORE 0x54410001 struct tag_core { u32 flags; /* bit 0 = read-only */ u32 pagesize; u32 rootdev; }; /* command line: /0 terminated string */ #define ATAG_CMDLINE 0x54410009 struct tag_cmdline {//bootargs保存在它的后面 char cmdline[1]; /* this is the minimum size */ }; /* describes where the compressed ramdisk image lives (virtual address) */ /* * this one accidentally used virtual addresses - as such, * its depreciated. */ #define ATAG_INITRD 0x54410005 /* describes where the compressed ramdisk image lives (physical address) */ #define ATAG_INITRD2 0x54420005 struct tag_initrd {//描述ramdisk的分布 u32 start; /* physical start address */ u32 size; /* size of compressed ramdisk image in bytes */ }; /* it is allowed to have multiple ATAG_MEM nodes */ #define ATAG_MEM 0x54410002 struct tag_mem32 { u32 size; u32 start; /* physical start address */ }; 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; /* * Acorn specific */ struct tag_acorn acorn; /* * DC21285 specific */ struct tag_memclk memclk; } u; };
5.
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 /* CONFIG_SETUP_MEMORY_TAGS */ static void setup_commandline_tag (bd_t *bd, char *commandline) { char *p; if (!commandline) return; /* eat leading white space */ for (p = commandline; *p == ' '; p++);//跳过开头的空格 /* skip non-existent command lines so the kernel will still * use its default command line. */ 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) { /* an ATAG_INITRD node tells the kernel where the compressed * ramdisk can be found. ATAG_RDIMG is a better name, actually. */ 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 /* CONFIG_INITRD_TAG */ static void setup_end_tag (bd_t *bd) { params->hdr.tag = ATAG_NONE;//最后一个tag是一个空类型,标志这tag的结束。 params->hdr.size = 0; }




你可能感兴趣的:(linux,struct,image,header,command,OS)