一、第1階段:arch/arm/arm920t/start.S1. 硬體初始化:1.1 把CPU切換到SVC32模式1.2 關看門狗1.3 屏蔽中斷1.4 初始化SDRAM2. 重定位代碼3. 跳轉到SDRAM去繼續執行3.1 設定棧3.2 清除BSS3.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_f2. 其他組件的初始化2.1 NOR FLASH初始化:flash_init2.2 NAND FLASH初始化:nand_init2.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 + 640x30008000 3. 倒數計時:abortbootif (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.cdo_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 = 0x902d1c00os_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 = 0x31000000hdr = 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. 設定參數:把參數存在雙方定死的位置intmachid = bd->bi_arch_number; // MACH_TYPE_SMDK2410,193void(*theKernel)(int zero, int arch, uint params);#ifdef CONFIG_CMDLINE_TAGchar *commandline = getenv ("bootargs"); /* 傳給核心的命令列參數 */#endifep = image_get_ep (&images->legacy_hdr_os_copy); // 0x30008000theKernel = (void (*)(int, int, uint))ep; // 0x30008000s = 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);