基於imx6ull的uboot2017啟動流程


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(&params);
	if (BOOTM_ENABLE_CMDLINE_TAG)
		setup_commandline_tag(gd->bd, commandline);
	if (BOOTM_ENABLE_REVISION_TAG)
		setup_revision_tag(&params);
	if (BOOTM_ENABLE_MEMORY_TAGS)
		setup_memory_tags(gd->bd);
        setup_board_tags(&params);
	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); /* 啟動內核 */

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM