第一、二期銜接——5.3 u-boot分析與使用—源碼分析

u-boot分析與使用—源碼分析


一、前言

在linux系統下,執行makeu-boot進行編譯時,輸出以下信息:
在這裏插入圖片描述
可以看到,除了關注腳本文件,也要關注cpu/arm920t/start.o文件
通過前面的分析可知,u-boot的主要目的如下:

  1. 從FLASH讀出內核
  2. 啓動內核

抱着這個目的,我們cpu/arm920t/start.o文件入手進行分析

二、第一階段

這個階段分析的是cpu/arm920t/start.o文件中的彙編代碼實現的功能
展示的代碼並不是完整的代碼,是根據前言中的目的來進行分析與展示

1、設置CPU爲管理模式

可以看到彙編文件一開始會跳到reset:執行
在這裏插入圖片描述

2、關看門狗

在這裏插入圖片描述

3、關中斷

在這裏插入圖片描述

4、設置時鐘

在這裏插入圖片描述

5、根據情況判斷是否初始化SDARM

  1. 比較r0+_start的值與_TEXT_BASE的值不相等則跳去執行cpu_init_crit
  2. cpu_init_crit進行:關閉flush、清除caches、關閉MMU、跳去執行lowlevel_init
  3. lowlevel_init,對SDRAM進行相關初始化
    在這裏插入圖片描述

6、設置棧(只有設置棧之後纔可以調用C函數)

在這裏插入圖片描述

7、根據情況判斷是否提前清bss段

  1. 比較r0+_start的值與_TEXT_BASE的值不相等則跳去執行clean_bss
  2. clean_bss進行:清除操作

就算這裏不清除,後面彙編代碼也會清除。
在這裏插入圖片描述

8、重定位

  1. CopyCode2Ram中判斷爲NOR啓動還是NAND啓動
  2. 從NOR啓動,copy工作簡單
  3. 從NAND啓動先初始化NAND FLASH,後進行copy

在這裏插入圖片描述

9、調用start_armboot(u-boot的第二階段)

在這裏插入圖片描述

10、總結

到此爲止,u-boot的第一階段的分析已經結束。
總體的流程如下:

  1. 設置爲管理模式
  2. 關看門狗
  3. 關中斷
  4. 設置時鐘
  5. 根據情況判斷是否初始化SDARM
  6. 設置棧(只有設置棧之後纔可以調用C函數)
  7. 根據情況判斷是否提前清bss段
  8. 重定位
  9. 調用start_armboot(u-boot的第二階段)
  • 其中1~8步驟的設置稱爲硬件相關的設置,主要通過彙編代碼完成
  • 9步驟後的設置纔是啓動內核的代碼實現,比較複雜,需要通過C語言實現

三、第二階段分析

這裏抱着啓動內核的目標,分析start_armboot()函數,所在的位置爲u-boot-1.1.6/lib_arm/board.c

1、進行一系列的初始化工作

  1. 通過如下函數進行對應的初始化如CPU初始化、板載資源的初始化、中斷初始化等等
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
  1. 分析板載資源初始化
    2_1. 進行把對應IO口拉高
    2_2. 根據判斷結果設置機器ID
    2_3. 設置啓動參數
    在這裏插入圖片描述

2、初始化NOR FLASH

在這裏插入圖片描述

3、在內存中分配堆區

在這裏插入圖片描述

4、初始化NAND FLASH

在這裏插入圖片描述

5、設置環境變量

在這裏插入圖片描述

6、進入到main_lopp()死循環過程

運行到這個函數這裏,就可以
在這裏插入圖片描述

6.1 資源的加載與版本號的設置

在這裏插入圖片描述

6.2 設置超時時間並打印一些信息

在這裏插入圖片描述

6.3 獲取環境變量bootcmd,以便後面內核的啓動

這個參數當我們啓動bootloader時,執行print指令輸出的信息有它的顯示,這個參數與內核的啓動有關,後面會進行介紹。
在這裏插入圖片描述
在這裏插入圖片描述

6.4 在超時時間內判斷鍵盤是否有輸入,無的話

如果此時鍵盤無輸入,則會與如下信息:最明顯的就是打印"Booting Linux ...\n"

  • 實際運行bootlloader的界面
    在這裏插入圖片描述

  • 此時會運行run_command(s, 0),根據上面的到的**bootcmd環境變量來啓動內核**
    如何啓動我這裏只說結論,具體的分析過程可以看韋老師的分析博客【Uboot到底如何啓動內核】

    1. nand read.jffs2 0x30007FC0 kernel等價於:nand read.jffs20x30007FC0 0x00060000 0x00200000
    1. bootm 0x30007FC0 關鍵函數do_bootm(),具體做了如下:讀取頭部,將內核移動到加載地址,啓動內核
      在這裏插入圖片描述

6.5 在超時時間內判斷鍵盤是否有輸入,有的話,此時如果想啓動內核的話,需要通過輸入命令實現

6.5.1 進入菜單 run_command("menu", 0);
  • 實際運行的顯示
    在這裏插入圖片描述
    在這裏插入圖片描述
6.5.2 等待此時鍵盤輸入的命令,若按下’q’
  • 如果此時按下的是’q’,則程序會卡死在這個界面,並且等待命令的輸入:
    在這裏插入圖片描述
    在這裏插入圖片描述

7、總結

第二階段的作用大致如下:

  1. 進行CPU、中斷、設置啓動參數等初始化
  2. 初始化NOR FLASH、NAND FLASH,以便後面代碼的重定位
  3. 設置好環境變量
  4. 進入bootloader啓動界面,根據超時時間進行對應操作
    4.1 超時時間內鍵盤不輸入過了超時時間則啓動內核
    4.2 超時時間內鍵盤輸入進入菜單界面,根據命令進行相關操作
    其中,在4.1和4.2中都有執行了相同的函數run_command(),下面來分析它。

8、分析run_command()

8.1 處理多條命令情況

在這裏插入圖片描述

8.2 拆分命令

如果此時命令爲md.w 0則拆分後結果如下:
在這裏插入圖片描述

8.3 分析find_cmd()

這個函數的作用是對拆分後得到的命令進行匹配
在這裏插入圖片描述

8.4 分析cmd_tbl_s結構體

  • 原型如下:在這裏插入圖片描述
  • 在鏈接腳本中有如下段.u_boot_cmd : { *(.u_boot_cmd) }
    通過搜索.u_boot_cmd,並進行以下關鍵詞搜索得到如下結果:
    在這裏插入圖片描述
  • cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}進行拆分得到:
    在這裏插入圖片描述

四、總結

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章