一、第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);