1、Uboot2017編譯配置流程
/Uboot-2017.03$ make distclean /Uboot-2017.03$ make mx6ull_14x14_evk_defconfig /Uboot-2017.03$ make
最后會編譯出u-boot-dtb.imx文件,可以燒入板子中啟動了。
2、Uboot2017的啟動流程分析
1)內核啟動的第一階段
首先,經過上面的編譯后,會在頂層目錄下發現 自動生成了u-boot.lds鏈接文件,有了這個文件后,我們就會很容易找到我們需要分析的第一個文件是什么:
因此,我們就可以從arch/arm/cpu/armv7/start.S這個文件出發,去分析;但是當打開start.S這個文件時,並不會發現有程序的入口,也就是上圖的_start這個標志,這個標志定義在arch/arm/lib/vectors.S文件中:
從上面也可以看到,主要定義了異常與中斷的跳轉函數,而第一個跳轉到的是reset標志,可以發現,reset標志是定義在start.S中的,然后順着程序向下執行:
1)將CPU從用戶模式切換到管理員模式
2)禁止中斷
這個函數是對CPU進行初始化
搜索_main,該函數定義在crt0.S中,這個函數是第一階段的關鍵,第一階段中最主要的函數是為了調用board_init_f:
由於此時RAM還並沒有初始化,不能使用,因此使用gd結構體進行數據的傳輸
1)設置c代碼的運行環境,為調用board_init_f作准備
a) 設置堆棧
b) 調用board_init_f_alloc_reserve接口,從堆棧開始的地方,為uboot的gd結構分配空間
c) 調用board_init_f_init_reserve接口,對gd進行初始化
2)調用board_init_f函數,完成一些前期的初始化工作
a)點亮一個Debug用的LED燈,表示u-boot已經活了
b)初始化DRAM,DDR等system范圍的RAM等
c)計算后續代碼需要使用的一些參數,包括relocation destination,the future stack,the future GD location等.
3).如果當前是SPL(由CONFIG_SPL_BUILD控制),則_main函數結束,直接返回.如果是正常的u-boot,則繼續執行后續的動作
4).根據board_init_f指定的參數,執行u-boot的relocation操作
5).清除BSS段
6).調用board_init_r函數,執行后續的初始化操作
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) ldr sp, =(CONFIG_SPL_STACK) #else ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) #endif #if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */ mov r3, sp bic r3, r3, #7 mov sp, r3 #else bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ #endif mov r0, sp bl board_init_f_alloc_reserve mov sp, r0 /* set up gd here, outside any C code */ mov r9, r0 bl board_init_f_init_reserve mov r0, #0 bl board_init_f
在board_init_f中
會順序的執行init_sequence_f中定義的函數指針,函數指針中,比較關鍵的是初始化時鍾、初始化內核啟動的環境參數、設置串口波特率、初始化串口、初始化i2c、初始化SPI、初始化ram、設置重定位地址、重定位
get_clocks env_init init_baud_rate serial_init init_func_i2c init_func_spi dram_init jump_to_copy . . . .
jump_to_copy函數調用crt0.S文件中的重定位函數,之后便進行清除bss段,之后便調用board_init_r函數,進入內核啟動的第二階段。
2)內核啟動的第二階段
在第一階段中,為第二階段的函數調用提供了基礎,比如gb結構、堆棧等
在board_init_r函數中,同樣也有
順序執行init_sequence_r函數指針的函數。
調用一系統函數之后,會調用到
run_main_loop main_loop() s = bootdelay_process() /* 獲得uboot傳入的bootcmd bootdelay參數,並將bootcmd參數保存在s中 */
autoboot_command(); /* run_command s中的命令 */
if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) /* 如果在bootdelay時間內,沒有按下其他按鍵,便進入if判斷 */
run_command_list(s, -1, 0) /* 執行uboot環境中bootcmd所指向的代碼 */
/* 如果在啟動過程中,按下了空格,就會從autoboot_command()函數中返回 */
cli_loop();
parse_file_outer();
/* 對uboot傳入的命令進行必要的初始化 */
rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); /* 執行uboot中的命令行參數 死循環 */
do{
run_list();
}while();
如果在uboot命令行中輸入了boot或bootm (地址),uboot便會再次啟動內核。
3、bootm命令
對於uboot中,每一個命令行參數都會有一個相應的函數對應,對於bootm命令,會執行do_bootm函數(為什么調用略)
do_bootm do_bootm_subcommand do_bootm_states bootm_os_get_boot_func for (i = 0; i < ARRAY_SIZE(boot_os); i++) static boot_os_fn *boot_os[] = { ... #ifdef CONFIG_BOOTM_LINUX [IH_OS_LINUX] = do_bootm_linux, .... } do_bootm_linux boot_prep_linux setup_start_tag(gd->bd); if (BOOTM_ENABLE_SERIAL_TAG) setup_serial_tag(¶ms); if (BOOTM_ENABLE_CMDLINE_TAG) setup_commandline_tag(gd->bd, commandline); if (BOOTM_ENABLE_REVISION_TAG) setup_revision_tag(¶ms); if (BOOTM_ENABLE_MEMORY_TAGS) setup_memory_tags(gd->bd); setup_board_tags(¶ms); setup_end_tag(gd->bd); boot_jump_linux void (*kernel_entry)(int zero, int arch, uint params); unsigned long machid = gd->bd->bi_arch_number; kernel_entry = (void (*)(int, int, uint))images->ep;
r2 = gd->bd->bi_boot_params; kernel_entry(0, machid, r2); /* 啟動內核 */