u-boot分析與使用—啓動內核
- 硬件平臺:韋東山嵌入式Linxu開發板(S3C2440.v3)
- 軟件平臺:運行於VMware Workstation 12 Player下UbuntuLTS16.04_x64 系統
- 參考資料:《嵌入式Linux應用開發手冊》、《嵌入式Linux應用開發手冊第2版》
- 開發環境:Linux 2.6.22.6 內核、arm-linux-gcc-3.4.5-glibc-2.3.6工具鏈、u-boot-1.1.6
一、前言
在上一篇博文【5.3 u-boot分析與使用—源碼分析】中,我們對源碼進行了分析,知道的u-boot爲了實現做了以下的事情:
下面則對u-boot啓動內核進行細緻的分析。
二、把內核讀入到FLASH中
- 對於
bootcmd
環境變量,進行拆分解讀,再解讀
bootcmd=nand read.jffs2 0x30007FC0 kernel;
- 具體的意思就是:從nand flash中把
kernel
讀到0x30007FC0
,
1、從哪裏讀
根據指令可以知道,從kernel
分區讀,但是對於嵌入式Linux是沒有分區的,那如何表示?
- 在
100ask24x0.h
文件的代碼中寫死
- uboot執行
mtd
可以查看分區
kernel的所在地址爲:0x00020000----0x00040000
2、讀到哪裏去
根據指令可以知道,讀到去地址爲0x30007FC0
的內存中去
3、總結
-
對於指令
nand read.jffs2 0x30007FC0 kernel
意思就是nand flash從kernel分區(地址爲0x00020000----0x00040000)把內核讀到地址爲0x30007FC0
的內存中去 -
補充:使用r
.jffs2
後綴時,輸入的起始地址與結束地址不需要塊對齊或頁對齊
三、啓動內核
- 對於
bootcmd
環境變量,進行拆分解讀,再解讀
bootm 0x30007FC0
- 具體的意思就是:從
0x30007FC0
中啓動內核
1、FLASH上存的內核的實質
FLASH上存的內核 = 頭部 + 真正的內核,對於頭部結構體,原型如下:
- booitm對應的操作函數爲
do_bootm()
2、do_bootm()
函數分析
2.1 讀出頭部,做些相關的校驗工作
對於頭部信息的加載地址與入口地址,下面分析會使用到。
3、根據頭部的加載信息把內核移動到合適的地方
3.1 如果內核位於加載地址
3.1 如果內核不位於加載地址
4、跳到入口地址啓動內核
4.1 設置啓動參數
在這裏會對啓動參數、內存參數、串口參數、命令行參數等等進行初始化設置,後面會具體分析。
4.2 啓動內核
此時會調用theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
來啓動內核
- theKernel 的由來:
1、定義一個theKernel函數指針
2、定義一個hdr結構體指向2.1 中所說的頭部,用來獲取入口地址
3、讓theKernel = hdr->ih_op
,此時theKernel
就是入口地址了
5、總結
對於整個啓動內核的流程總結如下:
-
讀取頭部,根據頭部的加載信息把內核移動到合適的地方
1_1. 先從頭部知道加載地址與入口地址
1_2. 如果發現內核不位於加載地址,則把內核移動到加載地址
1_3. 如果發現內核位於加載地址,則打印相關信息 -
啓動內核
2_1. 設置啓動參數
2_2. 跳到入口地址啓動內核
6、分析啓動參數
提問:當你跳到內核時,u-boot不存在,二者怎麼交互數據?
解答:按照某種協議:在某個地址,按某種格式 ,對數據進行保存。
在這個分析中就是:在0x30000100
中把啓動參數入棧保存,內核可以進入到0x30000100
內存空間讀取數據。
6.1 setup_start_tag()
函數分析
這個函數的功能是設置啓動的參數,找到棧中對應存放參數的起始地址,放入參數。
6.2 setup_memory_tag()
函數分析
這個函數設置的是內存的相關參數,如下圖所示:
6.3 setup_commandline_tag()
函數分析
這個函數設置的是命令行參數bootcmd
6.4 setup_end_tag()
函數分析
在這個函數中設置的是參數結束設置的標誌
6.5 總體的入棧分析
-
根據
start_tag
的參數tag:0x30000100
,在地址爲0x30000100
的內存中進行入棧 -
在每設置完一個參數後,
params
指針移動到下一個tag的位置
,進行下一個參數的入棧
四、總結
u-boot會根據bootcmd
這個環境變量,對啓動內核進行相關操作: