(注:本文參考資料:朱有鵬嵌入式課程。本文爲我的學習記錄,若有錯誤,歡迎指正。)linux
1)將內核搬移至DDR中;數據結構
2)校驗內核格式、CRC;ide
3)準備傳參;函數
4)跳轉執行內核。工具
s = getenv ("bootcmd"); //獲取bootcmd環境變量的值 debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); if (bootdelay >= 0 && s && !abortboot (bootdelay)) { ................................ #ifndef CFG_HUSH_PARSER run_command (s, 0); //執行bootcmd環境變量中的命令 ................................ }
#if defined(CFG_FASTBOOT_NANDBSP) #define CONFIG_BOOTCOMMAND "nand read C0008000 600000 400000; nand read 30A00000 B00000 180000; \ bootm C0008000 30A00000" #elif defined(CFG_FASTBOOT_SDMMCBSP) #define CONFIG_BOOTCOMMAND "movi read kernel C0008000; movi read rootfs 30A00000 180000; \ bootm C0008000 30A00000" #endif
bootcmd=nand read C0008000 600000 400000; /*將kernel(大小0x00400000字節)從nand中的0x00600000地址處拷貝到DDR中的 0xc0008000地址處*/ nand read 30A00000 B00000 180000; /*將rootfs(大小0x00180000字節)從nand中的0x00B00000地址處拷貝到DDR中的 0x30A08000地址處*/
bootm C0008000 30A00000 //啓動kernel、rootfs
zImage | Linux內核通過編譯後生成一個ELF格式的可執行文件,vmlinux。再經過arm-linux-objcopy工具進行加工,最後進行壓縮,獲得zImage格式的內核鏡像,能夠燒錄進啓動介質中。oop |
uImage學習 |
uImage是由zImage加工獲得的。uboot中的mkimage工具將zImage加工生成uImage來給uboot啓動。這個加工過程其實就是在zImage前面加上64字節的uImage的頭信息便可。ui |
typedef struct image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ uint32_t ih_time; /* Image Creation Timestamp */ uint32_t ih_size; /* Image Data Size */ uint32_t ih_load; /* Data Load Address */ uint32_t ih_ep; /* Entry Point Address */ uint32_t ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t;
after_header_check: os = hdr->ih_os; #endif switch (os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX: #ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux(); #endif do_bootm_linux (cmdtp, flag, argc, argv, &images); break; case IH_OS_NETBSD: do_bootm_netbsd (cmdtp, flag, argc, argv, &images); break; .........................................
#define ATAG_CORE 0x54410001 //起始標記 #define ATAG_NONE 0x00000000 //結束標記 #define ATAG_MEM 0x54410002 #define ATAG_VIDEOTEXT 0x54410003 #define ATAG_RAMDISK 0x54410004 #define ATAG_INITRD 0x54410005 #define ATAG_INITRD2 0x54420005 #define ATAG_SERIAL 0x54410006 #define ATAG_REVISION 0x54410007 #define ATAG_VIDEOLFB 0x54410008 #define ATAG_CMDLINE 0x54410009 #define ATAG_ACORN 0x41000101 #define ATAG_MEMCLK 0x41000402 #define ATAG_MTDPART 0x41001099
struct tag_header { u32 size; //表示標記的類型 u32 tag; //表示標記的結構 }; struct tag { struct tag_header hdr; //不一樣的標記類型使用不一樣的聯合,每個標記對應一個數據結構體 union { struct tag_core core; struct tag_mem32 mem; struct tag_videotext videotext; struct tag_ramdisk ramdisk; struct tag_initrd initrd; struct tag_serialnr serialnr; struct tag_revision revision; struct tag_videolfb videolfb; struct tag_cmdline cmdline; /* * Acorn specific */ struct tag_acorn acorn; /* * DC21285 specific */ struct tag_memclk memclk; struct tag_mtdpart mtdpart_info; } u; };
標記列表舉例:spa
static void setup_start_tag (bd_t *bd) { params = (struct tag *) bd->bi_boot_params; params->hdr.tag = ATAG_CORE; //起始標記 params->hdr.size = tag_size (tag_core); params->u.core.flags = 0; params->u.core.pagesize = 0; params->u.core.rootdev = 0; params = tag_next (params); } #ifdef CONFIG_SETUP_MEMORY_TAGS static void setup_memory_tags (bd_t *bd) { int i; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { params->hdr.tag = ATAG_MEM; params->hdr.size = tag_size (tag_mem32); params->u.mem.start = bd->bi_dram[i].start; params->u.mem.size = bd->bi_dram[i].size; params = tag_next (params); } } #endif ..........................................................//中間還有多個標記 static void setup_end_tag (bd_t *bd) { params->hdr.tag = ATAG_NONE; //結束標記 params->hdr.size = 0; }
1)0 : 至關於mov r0 #0。debug
2)machid : U-Boot中的機器碼,從全局變量bd中獲取。內核機器碼和U-Boot機器碼必須一致才能啓動內核。
3)bd->bi_boot_params : 啓動參數地址。
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], bootm_headers_t *images) { ..................................... //標記鏈表初始化 setup_start_tag (bd); setup_serial_tag (¶ms); setup_revision_tag (¶ms); setup_memory_tags (bd); setup_commandline_tag (bd, commandline); setup_initrd_tag (bd, initrd_start, initrd_end); setup_videolfb_tag ((gd_t *) gd); setup_mtdpartition_tag(); setup_end_tag (bd); ....................................... void (*theKernel)(int zero, int arch, uint params); //定義函數指針theKernel ...................................... theKernel = (void (*)(int, int, uint))ep; //將入口地址賦值給theKernel ...................................... theKernel (0, machid, bd->bi_boot_params); //傳參,調用theKernel ...................................... }