uboot加载内核
1.bootcmd:这个参数包含了一些命令,这些命令将在u-boot进入主循环后执行示例:
bootcmd=boot_logo;nand read 10000003c0000 300000;bootm //需要注意的是在bootcmd变量的最后添加了bootm命令。
意思是启动u-boot后,执行boot_logo显示logo信息,然后从nand flash中读内核映像到内存,然后启动内核。
2.bootargs这个参数设置要传递给内核的信息,主要用来告诉内核分区信息和根文件系统所在的分区。示例:
root=/dev/mtdblock5 rootfstype=jffs2console=ttyS0,115200 mem=35M mtdparts=nand.0:3840k(u-boot),4096k(kernel),123136k(filesystem)
其中:
root=/dev/mtdblock5 表示根文件系统在第五分区
rootfstype=jffs2 表示根文件系统的类型是jffs2
console=ttyS0,115200 表示终端为ttyS0,串口波特率为115200
mem=35M 表示内存大小为35M
mtdparts告诉内核MTD分区情况
超时之前用户没有输入,uboot就会自动加载linux内核,其加载时将使用变量“bootcmd”和 “bootargs”,其值可以在在加载linux内核前在uboot的命令行中进行修改。
在main_loop()函数中,执行了"bootcmd" 所定义的命令bootm,bootm命令执行过程中调用了bootm_start函数:
common/cmd_bootm.c:
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { void *os_hdr; int ret; memset ((void *)&images, 0, sizeof (images)); images.verify = getenv_yesno ("verify"); bootm_start_lmb(); /* get kernel image header, start address and length 寻找可用的内核镜像*/ os_hdr = boot_get_kernel (cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); //返回指向内存中镜像头指针 if (images.os.image_len == 0) { puts ("ERROR: can't get kernel image!\n"); return 1; } /* get image parameters */ switch (genimg_get_format (os_hdr)) { case IMAGE_FORMAT_LEGACY: images.os.type = image_get_type (os_hdr); //镜像类型 images.os.comp = image_get_comp (os_hdr); //压缩类型 images.os.os = image_get_os (os_hdr); //操作系统类型 images.os.end = image_get_image_end (os_hdr); //当前镜像的尾地址 images.os.load = image_get_load (os_hdr); //镜像数据的载入地址 break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: if (fit_image_get_type (images.fit_hdr_os, images.fit_noffset_os, &images.os.type)) { puts ("Can't get image type!\n"); show_boot_progress (-109); return 1; } if (fit_image_get_comp (images.fit_hdr_os, images.fit_noffset_os, &images.os.comp)) { puts ("Can't get image compression!\n"); show_boot_progress (-110); return 1; } if (fit_image_get_os (images.fit_hdr_os, images.fit_noffset_os, &images.os.os)) { puts ("Can't get image OS!\n"); show_boot_progress (-111); return 1; } images.os.end = fit_get_end (images.fit_hdr_os); if (fit_image_get_load (images.fit_hdr_os, images.fit_noffset_os, &images.os.load)) { puts ("Can't get image load address!\n"); show_boot_progress (-112); return 1; } break; #endif default: puts ("ERROR: unknown image format type!\n"); return 1; } /* find kernel entry point */ if (images.legacy_hdr_valid) { images.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, &images.ep); if (ret) { puts ("Can't get entry point property!\n"); return 1; } #endif } else { puts ("Could not find kernel entry point!\n"); return 1; } if (((images.os.type == IH_TYPE_KERNEL) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX)) { /* find ramdisk */ ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH, &images.rd_start, &images.rd_end); if (ret) { puts ("Ramdisk image is corrupt or invalid\n"); return 1; } #if defined(CONFIG_OF_LIBFDT) #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC) /* find flattened device tree */ ret = boot_get_fdt (flag, argc, argv, &images, &images.ft_addr, &images.ft_len); if (ret) { puts ("Could not find a valid device tree\n"); return 1; } set_working_fdt_addr(images.ft_addr); #endif #endif } images.os.start = (ulong)os_hdr; //指向内存中镜像的头地址 images.state = BOOTM_STATE_START; return 0; }
接下来:
//寻找内核映像、校验它的完整性和定位内核数据位置
static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],bootm_headers_t *images, ulong *os_data, ulong *os_len){...}
//校验早期格式内核映像
static image_header_t *image_get_kernel (ulong img_addr, int verify){...}
/* bootm - boot application image from image in memory引导应用程序在内存中的镜像 */
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
...
ret = bootm_load_os(images.os, &load_end, 1); //将镜像的数据从images.os.image_start复制到images.os.load 打印:Loading Kernel Image ... OK
...
boot_fn = boot_os[images.os.os]; //根据操作系统的类型获取引导操作系统的函数
...
}
lib_arm/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 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); #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_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); //将bootargs传给tag #endif #ifdef CONFIG_INITRD_TAG if (images->rd_start && images->rd_end) setup_initrd_tag (bd, images->rd_start, images->rd_end); #endif #if defined (CONFIG_VFD) || defined (CONFIG_LCD) setup_videolfb_tag ((gd_t *) gd); #endif 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 cleanup_before_linux (); theKernel (0, machid, bd->bi_boot_params); //执行内核代码 /* does not return */ return 1; }
完毕!