在uboot源码阅读(六)大佬的命令这篇文章中,知道了内核的启动是通过命令nand read.i c0008000 80000 500000;bootm c0008000,先把flash的数据读到内存中,然后执行这段内存的命令。看上去bootm和go还是很相近的嘛。但是go仅仅是开始执行而已,并没做任何的操作,比如GPIO编程(二)led灯的控制中执行内存中的一小段程序。而内核的启动需要满足下列条件:
(1)CPU 寄存器的设置。
• R0=0。
• R1=机器类型ID;对于ARM 结构的CPU,其机器类型ID 可以参见linux/arch/arm/tools/mach-types。
• R2=启动参数标记列表在RAM 中起始基地址。
(2)CPU 工作模式。
• 必须禁止中断(IRQs 和FIQs)。
• CPU 必须为SVC 模式。
(3)Cache 和MMU 的设置。
• MMU 必须关闭。
• 指令Cache 可以打开也可以关闭。
• 数据Cache 必须关闭。
bootm命令:
检测数据是否正确,解压内核到对映的地址位置.
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { s = getenv ("verify");//是否对内核进行crc校验 verify = (s && (*s == 'n')) ? 0 : 1; if (argc < 2) { addr = load_addr; //操作系统启动地址0x50000000,mini6410 } else { addr = simple_strtoul(argv[1], NULL, 16); } printf ("## Booting image at %08lx ...\n", addr); /* Copy header so we can blank CRC field for re-calculation */ memmove (&header, (char *)addr, sizeof(image_header_t));//拷取头部数据64字节,下面用来进行crc校验 if (ntohl(hdr->ih_magic) != IH_MAGIC) {//判断是否是uboot镜像格式 } SHOW_BOOT_PROGRESS (2); data = (ulong)&header; len = sizeof(image_header_t); checksum = ntohl(hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (uchar *)data, len) != checksum) {//头部数据时行crc校验 puts ("Bad Header Checksum\n"); SHOW_BOOT_PROGRESS (-2); return 1; } /* for multi-file images we need the data part, too */ print_image_hdr ((image_header_t *)addr); data = addr + sizeof(image_header_t);//去掉image的头部,只对数据部分进行校验 len = ntohl(hdr->ih_size); if (verify) { puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { } puts ("OK\n"); } len_ptr = (ulong *)data; iflag = disable_interrupts(); //禁止中断(IRQs 和FIQs) switch (hdr->ih_comp) { case IH_COMP_NONE: break; case IH_COMP_GZIP: //这里使用gzip对内核进行解压缩,从data开始不含头 printf (" Uncompressing %s ... ", name); if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, (uchar *)data, &len) != 0) { } break; } puts ("OK\n"); switch (hdr->ih_os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX: //调用do_bootm_linux进一步启动内核 do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; } return 1; }
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) { #ifdef CONFIG_CMDLINE_TAG char *commandline = getenv ("bootargs");//取得内核启动参数 #endif theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);//在mkimage.c里面指定的内核入口地址 /* * Check if there is an initrd image */ if (argc >= 3) {//检测initrd临时要文件系统,包括:magic number,头和数据的crc校验,和前面类似 SHOW_BOOT_PROGRESS (9); addr = simple_strtoul (argv[2], NULL, 16);//取得initrd的地址,下面检测过程类似内核 } if (data) { initrd_start = data; initrd_end = initrd_start + len; } //下面开始向内核传递参数 #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); #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 setup_end_tag (bd); #endif /* we assume that the kernel is in place */ printf ("\nStarting kernel ...\n\n"); cleanup_before_linux ();//启动内核之前需要进行的设置 theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//启动内核,uboot使命到此全部完成. }
转载请注明出处:http://blog.csdn.net/ecbtnrt/article/details/6707113