现在的位置: 首页 > 综合 > 正文

uboot源码阅读(十)bootm内核的最终启动

2013年12月08日 ⁄ 综合 ⁄ 共 3240字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.