1. 程式人生 > >u-boot啟動Linux核心分析

u-boot啟動Linux核心分析

一、uImage的結構

通過前面分析u-boot的啟動流程,我們可以知道,u-boot啟動核心的命令是bootcmd=nand read.jffs 0x30007FC0  kernel:bootm 0x30007FC0;也就是先吧核心讀到記憶體上,再去啟動核心。在此之前我們先來明確一個定義,nandflash上的核心成為:uImage

其格式為:一個64k的頭部+真正的核心

其中頭部的定義如下:


我們重點關注的是ih_load(載入地址)和ih_ep(入口地址)這兩個變數。

二、bootm執行流程

bootm首先讀取頭部,知道它的載入地址和入口地址,如果bootm發現核心並不在載入地址上,那麼就把核心放到載入地址上,並跳到入口地址去執行

而如果核心剛好在載入地址上,那就不用轉移,節約時間。程式碼如下:


321行,這個判斷的意思是說如果核心剛好在載入地址上,那麼bootm就直接跳到入口地址執行,而如果bootm發現核心並沒有在載入地址上,那麼就先將其轉移到載入地址上,具體實現的語句是340行的呼叫memmove函式,將data也就是真正的核心資料轉移到load(載入地址)上。

而一旦把核心轉移到載入地址上,那麼bootm就跳到入口地址處執行,下面來分析具體的程式碼是如何實現的。


418行,bootm通過do_bootm_linux這個函式來執行啟動核心,我們跟蹤這個函式看看它的結構:


而在這個函式裡面,我們真正要關心的是theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

這個函式的呼叫,繼續檢視kernel的定義:

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

很明顯,:theKernel就是入口的地址。也就是說,執行theKernel這個函式實際上就是在入口函式執行核心。而我們看一下theKernel的第二個引數:bi_boot_params,也就是一些引數設定。引數分析如下:


在do_bootm_linux函式下,呼叫這樣一些函式,這些函式就是進行一些引數的設定,對應的我們可以看到這些設定引數以setup_start_tag (bd)開始,以setup_end_tag (bd);結束。我們先跟蹤一下setup_start_tag (bd):


在setup_start_tag 函式中,283行要做的事情就是確定tag這個結構體的起始地址,bi_boot_params這個變數的定義是0x30000100,也就是tag的起始地址,而在setup_start_tag 具體給 size、flag、pagesize、rootdev這些變數設定函式,接著指向下一個tag。

同樣地,我們可以分析接下來的幾個函式,最後它們要做的事情如下:


就是說,要啟動核心的時候,bootm要進行這些引數的設定,最後才是跳到入口地址處執行。

最後還是來總結一下u-boot啟動整個核心的過程:

整個u-boot的內心函式是:

s = getenv ("bootcmd");和run_command(s…),即獲取並且執行命令。

而在run_command(s…)這個函式中,最重要的是這個條命令:bootcmd=nand_read.jffs 0x30007FC0  kernel:bootm 0x30007FC0 

也就是,從flash把uImage讀到記憶體中,然後做一些引數的設定,之後啟動核心。