プログラマーのクリスマス後-ゼロ

15391 ワード

u-boot-2014.10コード分析及び移植説明
 1 ENTRY(_main)

 2 

 3 /*

 4  * Set up initial C runtime environment and call board_init_f(0).

 5  */

 6 

 7 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)

 8     ldr    sp, =(CONFIG_SPL_STACK)

 9 #else

10     ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)

11 #endif

12     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */

13     mov    r2, sp

14     sub    sp, sp, #GD_SIZE    /* allocate one GD above SP */

15     bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */

16     mov    r9, sp        /* GD is above SP */

17     mov    r1, sp

18     mov    r0, #0
1 clr_gd:

2     cmp    r1, r2            /* while not at end of GD */

3     strlo    r0, [r1]        /* clear 32-bit GD word */

4     addlo    r1, r1, #4        /* move to next */

5     blo    clr_gd

_mainはcrt 0にある.Sでは,このセグメントは主にu−bootで最も根本的に最も重要な変数gdに空間を割り当て,クリアする.
gdは構造体変数であり、そのアドレスはr 9レジスタに格納され(記憶間違いがなければ、以前のバージョンはr 8レジスタに格納されていた)、u-bootプログラムで最も重要なグローバル情報、クロック関連変数、ページテーブル、再位置決め情報など、カーネルに伝達されるボードレベル情報も含まれている.
1 #if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)

2     sub    sp, sp, #CONFIG_SYS_MALLOC_F_LEN

3     str    sp, [r9, #GD_MALLOC_BASE]

4 #endif

5     /* mov r0, #0 not needed due to above code */

6     bl    board_init_f

relocationの前に必要なスタック空間アドレスを定義し、board_に転送します.init_fプログラムは,ここからSPLであるBL 1フェーズコードとU-BOOTであるBL 2フェーズコードとが別々に異なるルートに進む.
CONFIG_が定義されていない場合SYS_GENERIC_BOARDは/arch/arm/lib/boardである.c
CONFIGが決まったらSYS_GENERIC_BOARD、common/board_f.c.
考えたら、まず/arch/arm/lib/board.cを例に挙げると、結局これは具体的なarchitectureに対してです(本当の原因はcommonの下で私はまだ見たことがありません)
 1 void board_init_f(ulong bootflag)

 2 {

 3     bd_t *bd;

 4     init_fnc_t **init_fnc_ptr;

 5     gd_t *id;

 6     ulong addr, addr_sp;

 7 #ifdef CONFIG_PRAM

 8     ulong reg;

 9 #endif

10     void *new_fdt = NULL;

11     size_t fdt_size = 0;

12 

13     memset((void *)gd, 0, sizeof(gd_t));

ここでまたgdをクリアしたのは、ちょっと余計なようですが、SPL向けなのでしょうか.(common/board_f.cのため、このファイルの関数はgd初期化されていない)
 1     gd->mon_len = (ulong)&__bss_end - (ulong)_start;

 2 #ifdef CONFIG_OF_EMBED

 3     /* Get a pointer to the FDT */

 4     gd->fdt_blob = __dtb_dt_begin;

 5 #elif defined CONFIG_OF_SEPARATE

 6     /* FDT is at end of image */

 7     gd->fdt_blob = &_end;

 8 #endif

 9     /* Allow the early environment to override the fdt address */

10     gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,

11                         (uintptr_t)gd->fdt_blob);

gd->mon_lenはubootサイズです.
CONFIG_OF_EMBEDはdtbをuboot,libs-$(CONFIG_OF_EMBED)+=dts/
CONFIG_OF_SEPARATEもdtbを同時にコンパイルしていますが、別々にコンパイルしてubootに組み込まれていません.Makefileではわかりますが、なぜ_end後.
1     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

2         if ((*init_fnc_ptr)() != 0) {

3             hang ();

4         }

5     }

このセグメントは一部の初期化を行い、init_sequenceは関数ポインタ配列であり、
 1 init_fnc_t *init_sequence[] = {

 2     arch_cpu_init,        /* basic arch cpu dependent setup */

 3     mark_bootstage,

 4 #ifdef CONFIG_OF_CONTROL

 5     fdtdec_check_fdt,

 6 #endif

 7 #if defined(CONFIG_BOARD_EARLY_INIT_F)

 8     board_early_init_f,

 9 #endif

10     timer_init,        /* initialize timer */

11 #ifdef CONFIG_BOARD_POSTCLK_INIT

12     board_postclk_init,

13 #endif

14 #ifdef CONFIG_FSL_ESDHC

15     get_clocks,

16 #endif

17     env_init,        /* initialize environment */

18     init_baudrate,        /* initialze baudrate settings */

19     serial_init,        /* serial communications setup */

20     console_init_f,        /* stage 1 init of console */

21     display_banner,        /* say that we are here */

22     print_cpuinfo,        /* display cpu info (and speed) */

23 #if defined(CONFIG_DISPLAY_BOARDINFO)

24     checkboard,        /* display board info */

25 #endif

26 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)

27     init_func_i2c,

28 #endif

29     dram_init,        /* configure available RAM banks */

30     NULL,

31 };

注意そこは実際には関数ポインタを指す配列であり,その利点は末尾のNULLであり,ポインタがNULLであることによって終了フラグとして判断される点である.以下、各初期化関数を逐一分析し、
1.arch_cpu_init
この関数は当然,各チップに対して独自に実現する必要があり,通常はこの関数においてcacheイネーブルの制御を実現することができる.
2.mark_bootstage
1     /* Record the board_init_f() bootstage (after arch_cpu_init()) */

2 static int mark_bootstage(void)

3 {

4     bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");

5 

6     return 0;

7 }

ubootの流れの中でタグをつけて、bootstage_mark_name関数は最終的に、プレートレベル自身が実現した1つの関数と接続することによって、印刷やledランプなどの様々な方法でubootに反応するプロセスを実現することができる.
3.fdtdec_check_fdt
fdtが存在するかどうかを検出する
4.board_early_init_f
初期化のいくつか
必要に応じて、マクロCONFIG_を定義します.BOARD_EARLY_INIT_F、そしてこの関数を実現する
5.timer_init
timer初期化,題外:u-bootにおけるtimer駆動の役割はdelayを実現するためであるため,timer駆動もudelayをめぐって展開される.
6.board_postclk_init
初期クロック関連初期化
必要に応じて、マクロCONFIG_を定義します.BOARD_POSTCLK_INIT、そしてこの関数を実現する
7.get_clocks
実際には主にgd->archを取得するために見える.sdhc_clkクロック、すなわちsdmmcクロックを取得するためですが、必要ではありません.
必要に応じて、マクロCONFIG_を定義します.FSL_ESDHCは、この関数を実装します.
8.env_init
gdの2つのメンバー、すなわち環境変数テーブルのアドレス、valid値を初期化する
9.init_baudrate
gdにおけるボーレートメンバー変数の初期化
ここでBAUDRATEのマクロ定義を設計する
10.serial_init
シリアルポート駆動の初期化
対応するシリアルポートドライバに追加する必要がある2つの関数default_serial_コンソール、およびserial_デバイス構造体のstartメンバー関数
11.console_init_f
実は何もなくて、ただ存在するCONFIG_PRE_CONSOLE_BUFFERの場合はbuffer初期化のプロセスがあります
12.display_banner
ubootバージョン情報等の印刷
13.print_cpuinfo
これは各チップが自分で実現し、cpu関連情報を印刷します.
14.checkboard
board関連情報の印刷
15.init_func_i2c
i 2 cが必要であれば初期化
16.dram_init
自己実現、gd->ram_sizeの初期化、もちろんありますよねdram_bankの初期化はここに書いてあります
全体init_sequence初期化は終了しました.
残りは次号にしよう.