u-boot代码分析


一、第1阶段:arch/arm/arm920t/start.S
1. 硬件初始化:
1.1 把CPU切换到SVC32模式
1.2 关看门狗
1.3 屏蔽中断
1.4 初始化SDRAM

2. 重定位代码

3. 跳转到SDRAM去继续执行
3.1 设置栈
3.2 清除BSS
3.3 跳转


二、第2阶段:从lib_arm/board.c: start_armboot函数分析
1. 一系列的初始化:
1.1 单板初始化:board_init (设置时钟、GPIO、......)
1.2 环境变量初始化:env_init (如果FLASH上有正确的环境变量,则用它;否则用默认的)
1.3 "输入输出系统printf,scanf"初始化:init_baudrate、serial_init、console_init_f

2. 其他部件的初始化
2.1 NOR FLASH初始化:flash_init
2.2 NAND FLASH初始化:nand_init
2.3 网卡初始化:

三、主循环
    for (;;) {
        main_loop ();
    }
1. 获得bootdelay:
    s = getenv ("bootdelay");
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

2. 获得"启动命令"
    s = getenv ("bootcmd"); // s="nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0"
                                  "tftp 0x30007FC0 uImage; bootm 0x30007FC0"
                                  " cp 10000000 0x30007FC0; bootm  "

0x30007FC0 + 64
0x30008000
    
3. 倒数计时:abortboot
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
}

4. 执行"启动命令"
     run_command (s, 0);  // 如果倒数期间没有按下按键

5. 如果第4步失败,
for (;;) {
    len = readline (CFG_PROMPT);   // 从串口读入一行数据,存在console_buffer
    strcpy (lastcommand, console_buffer);
    rc = run_command (lastcommand, flag);
}   


四、u-boot的核心:命令

run_command
    argc = parse_line (finaltoken, argv);  // "md.l 0" => argc = 2, argv[0]="md.l", argv[1]="0"
    cmdtp = find_cmd(argv[0]);             // 根据"md.l"来找到"命令"
    (cmdtp->cmd) (cmdtp, flag, argc, argv)
    
怎么找到命令:
find_cmd
    len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd); // “md.l“ ==> len = 2
    在__u_boot_cmd_start~__u_boot_cmd_end找出cmd_tbl_t,
    if (strncmp (cmd, cmdtp->name, len) == 0) // 返回找到的cmd_tbl_t


__u_boot_cmd_start、__u_boot_cmd_end在哪定义呢?
在board/smdk2410/u-boot.lds里有:
    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;   

在源码里搜"u_boot_cmd"
Command.h (include):#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

举例:
U_BOOT_CMD(
    md, 3,  1,  do_mem_md,
    "md  - memory display\n",
    "[.b, .w, .l] address [# of objects]\n    - memory display\n"
);


cmd_tbl_t __u_boot_cmd_md __attribute__ ((unused,section (".u_boot_cmd"))) = 
{"md", 3, 1, do_mem_md, 
"md  - memory display\n", 
"[.b, .w, .l] address [# of objects]\n    - memory display\n"}

五、bootm命令分析:common/cmd_bootm.c
do_bootm : "bootm 31000000", argc=2, argv[0]="bootm", argv[1]="31000000"
// 1. 读取uImage的头部,获得信息:加载地址、入口地址、长度、操作系统类型、是否压缩
/* get kernel image header, start address and length */
			
// os_data = 0x31000000+64; os_len = 0x902d1c00
os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &os_data, &os_len);
img_addr = simple_strtoul(argv[1], NULL, 16); //img_addr=0x31000000
*os_data = *os_len = 0;
switch (genimg_get_format ((void *)img_addr)) {
	hdr = (image_header_t *)img_addr;
	if (image_check_magic(hdr))
	{
		format = IMAGE_FORMAT_LEGACY;
	}
	case IMAGE_FORMAT_LEGACY:
		// 作一些检查,比如CRC
		// hdr = img_addr = 0x31000000
		hdr = image_get_kernel (img_addr, images->verify);
		switch (image_get_type (hdr)) {
			case IH_TYPE_KERNEL:
			// *os_data = hdr+sizeof(hdr) = 0x31000000+64
			*os_data = image_get_data (hdr);
			// *os_len = 0x902d1c00
			*os_len = image_get_data_size (hdr);
		}
										
		// 把头部拷到全局变量里去
		memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));
	}
			
	/* get image parameters */
		switch (genimg_get_format (os_hdr)) {
			case IMAGE_FORMAT_LEGACY:
			type = image_get_type (os_hdr);
			comp = image_get_comp (os_hdr);
			os = image_get_os (os_hdr);
			
			image_end = image_get_image_end (os_hdr);
			load_start = image_get_load (os_hdr);
			break;
		    
	
	// 2. 把内核移到加载地址去:移到哪、移多大?这些信息存在uImage的头部: uImage = 头部+真正的内核(zImage等)
		switch (comp) {
		case IH_COMP_NONE:
			if (load_start == (ulong)(os_hdr+sizeof(image_header_t))) {
				printf ("   XIP %s ... ", type_name);
			} else {
				printf ("   Loading %s ... ", type_name);
	
	            /* 如果当前真正的内核不位于uImage头部指示的加载地址
	             * 移动
	             */
				memmove_wd ((void *)load_start,
					   (void *)os_data, os_len, CHUNKSZ);
			}
	
	// 3. 根据内核的类型调用不同的处理函数
			switch (os) {
			default:			/* handled by (original) Linux case */
			case IH_OS_LINUX:
					do_bootm_linux (cmdtp, flag, argc, argv, &images); // Bootm.c (lib_arm)
						
	// 4. 设置参数:把参数存在双方定死的位置
			int	machid = bd->bi_arch_number; // MACH_TYPE_SMDK2410,193
			void	(*theKernel)(int zero, int arch, uint params);
			
			#ifdef CONFIG_CMDLINE_TAG
				char *commandline = getenv ("bootargs"); /* 传给内核的命令行参数 */
			#endif
			
			ep = image_get_ep (&images->legacy_hdr_os_copy); // 0x30008000
			
			theKernel = (void (*)(int, int, uint))ep; // 0x30008000
			
			s = getenv ("machid");
			machid = simple_strtoul (s, NULL, 16);
			
			/* 把参数存在双方定死的位置 */
			setup_start_tag (bd);
			
			setup_memory_tags (bd);
			
			char *commandline = getenv ("bootargs");
			setup_commandline_tag (bd, commandline);  /* root=/dev/mtdblock3 console=ttySAC0,115200 */
			
			setup_end_tag (bd);
			

	
	// 5. 启动:跳到内核的入口地址
			theKernel (0, machid, bd->bi_boot_params);


你可能感兴趣的:(image,cmd,command,OS,header,代码分析)