u boot第二階段分析(一)

2021-08-03 01:54:17 字數 3182 閱讀 8659

一 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...