一 start_armboot函式簡介
start_armboot函式是乙個長函式,在uboot/lib_arm/board.c的第444——908行,其中也呼叫了其他函式,共同構成了u-boot的第二階段。
1.第二階段的主要工作
我們之前已經分析過了第一階段,主要是初始化了soc內部的一些部件和初始化了ddr以及重定位,第二部分主要是初始化soc外部的一些硬體設施(第一階段沒有初始化完生下來的)。
2.整個u-boot在什麼地方結束
u-boot的目標是啟動核心,我們在啟動u-boot時,最後會出現倒數啟動核心時間,如果使用者沒有干涉則會執行bootcmd進入自動啟動核心流程;此時使用者可以按下回車鍵打斷uboot的自動啟動進入u-boot的命令列下。
u-boot的命令列實際上是乙個死迴圈,**如下:
for (;;)
迴圈體內不斷重複:接收命令、解析命令、執行命令。
接下來進行函式**的分析;
二 變數的定義和初始化
**1.init_fnc_t **
**為:init_fnc_t **init_fnc_ptr
其中init_fnc_ptr是乙個二重指標,在c語言中二重指標有兩個作用:乙個是指向乙個一重指標;第二個是指向乙個指正陣列,這裡的init_fuc_ptr可以用來指向乙個函式指標陣列。
我們可以找到它的宣告,typedef int (init_fnc_t) (void),這是乙個函式型別。
2.declare_global_data_ptr
在變數的初始化過程中常見到「gd」和「bd」,那麼是**來的呢?
在大部分的.c檔案中,都有declare_global_data_ptr這個巨集,這個巨集的定義如下:
#define declare_global_data_ptr register volatile gd_t *gd asm ("r8")
定義了乙個全域性變數名字叫gd,這個全域性變數是乙個指標型別,佔4位元組。用volatile修飾表示可變的,用register修飾表示這個變數要盡量放到暫存器中,後面的asm(「r8」)是gcc支援的一種語法,意思就是要把gd放到暫存器r8中。
簡而言之,declare_global_data_ptr就是定義了乙個要放在暫存器r8中的全域性變數,名字叫gd,型別是乙個指向gd_t型別變數的指標。
(1)為什麼要用register修飾?
因為這個全域性變數gd(global data的簡稱)是uboot中很重要的乙個全域性變數(準確的說這個全域性變數是乙個結構體,裡面有很多內容,這些內容加起來構成的結構體就是uboot中常用的所有的全域性變數),這個gd在程式中經常被訪問,因此放在register中提公升效率。
(2)gd是乙個結構體指標,這個結構體的定義如下:
typedef struct global_data gd_t;
typedef struct bd_info bi_dram[config_nr_dram_banks];
#ifdef config_has_eth1
/* second onboard ethernet port */
unsigned char bi_enet1addr[6];
#endif
} bd_t;
三 記憶體排布
1.上一節定義了gd和bd這兩個結構體指標,但是並沒有分配記憶體,也就是說這兩個指標還是野指標,下面就開始為它們分配記憶體。
注:u-boot還是裸機程式,所以沒有作業系統管理記憶體,所以也就沒法使用malloc等函式。
#ifdef config_memory_upper_code /* by scsuh */
ulong gd_base;
gd_base = cfg_uboot_base + cfg_uboot_size - cfg_malloc_len - cfg_stack_size - sizeof(gd_t);
#ifdef config_use_irq
gd_base -= (config_stacksize_irq+config_stacksize_fiq);
#endif
gd = (gd_t*)gd_base;
#else
gd = (gd_t*)(_armboot_start - cfg_malloc_len - sizeof(gd_t));
#endif
**分析:
首先定義了乙個ulong型別的變數gd_base,然後對其進行賦值,其中
cfg_uboot_base = 0x33e00000
cfg_uboot_size = 210241024 = 2m
cfg_malloc_len = cfg_env_size + 8961024 = 912kb(分配的堆區大小)
cfg_stack_size = 5121024 = 512kb
sizeof(gd_t) 大約36位元組,算的時候可以忽略不計
所以gd_base的位址大約可以算出來,大約在0x33e00000網上624kb左右的位置處。
然後將gd指標給例項化:gd = (gd_t*)gd_base;
這是將gd_base指標強制型別轉換為gd_t*型別。
2.內嵌彙編
/* compiler optimization barrier needed for gcc >= 3.4 */
__asm__ __volatile__("": : :"memory");
這行**的作用是為了防止高版本的gcc的優化造成錯誤。
3.記憶體清零
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
需要注意的是第二行**中將指標gd強制型別轉換為char*是因為指標相減的話,char減1就是減1,int減1就是減4。 u boot第二階段分析(二)
接著上一章節的內容,繼續往下分析start armboot函式 1.for迴圈執行init sequence 如下 for init fnc ptr init sequence init fnc ptr init fnc ptr 分析 1 init fnc ptr二重指標指向了init sequen...
u boot第二階段原始碼分析
typedef int init fnc t void init fnc t init sequence void start armboot void 理解 1 init fnc t宣告為函式型別,這個函式型別的引數為空,函式返回值為int整型。2 init fnc t init sequence...
uboot第二階段啟動流程
include typedef unsigned long ulong typedef struct environment s env t typedef struct bd info bi dram 1 bd t int main int argc,const char argv include...