1. ホーム
  2. Qt

Androidブートローダー:3分で徹底理解するubootの起動と機能

2022-02-23 11:38:45

1. ブートローダーの紹介

      システムの電源が入ったとき、それを初期化するためのプログラムが必要になります。ウォッチドッグをオフにする、システムクロックを変更する、メモリコントローラーを初期化する、メモリにさらにコードをコピーするなどです。これがブートローダです。

      ブートローダの実装は、ハードウェアに大きく依存します。組み込みシステムでは、ハードウェアの構成が大きく異なり、同じCPUでも周辺機器(フラッシュなど)が異なる場合があり、すべてのCPU、すべてのボードに対応したブートローダを用意することは不可能です。より多くのCPUアーキテクチャに対応したUBootでも、持ち込めばすぐに使えるというわけではありません(中の構成がたまたま自分のボードと同じであれば別ですが)。ある程度の設定が必要です。

      CPUは電源を入れると、あるアドレスから実行を開始します。例えば、MIPSアーキテクチャのCPUは0xBFC00000から、ARMアーキテクチャのCPUは0x000000から最初の命令を受け、組み込み開発ボードでは、このアドレスにメモリデバイスのROMやフラッシュをマッピングする必要があり、Bootloaderはこのアドレスの先頭に格納されて、電源を入れるとすぐに実行を開始することになります。(携帯電話のRAMとROMは、それぞれコンピュータのメモリとハードディスクに相当する)

2.ブートプロセス。

u-bootのシステムブートプロセス ほとんどのブートローダはstage1とstage2に分かれており、u-bootも例外ではありません。

CPUアーキテクチャに依存するコード(デバイスの初期化コードなど)は通常ステージ1に置かれ、アセンブリ言語で実装することができます。ステージ2は通常C言語で実装され、複雑な機能を実現するとともに可読性や移植性に優れています。

1.ステージ1  Sコードの構造 u-bootのstage1コードは通常start.Sファイルに配置され、このファイルはアセンブリ言語で書かれており、以下の主要なコードセクションがあります。

(1)エントリーポイントを定義する。これは、コネクタスクリプトを修正することによって行われます。

(2) Exception Vectorを設定します。 

(3) CPU速度、クロック周波数、ターミナルコントロールレジスタを設定します。 

(4) メモリコントローラを初期化します。 

(5) ROMからRAMにプログラムをコピーする。 

(6) 割り込みの停止、ウォッチドッグの停止

(7) スタックを初期化し、bssセグメントをクリアし、第2ステージに備える。

(8) 実行するために RAM に移動します。これは ldr pc という命令で実行できます。

2. ステージ2

      起動アームブートのCコードセクションlib_arm/board.cは、C言語の開始関数は、ブートコード全体のC言語の主な機能だけでなく、全体のUブート(armboot)の主な機能は、関数だけで次の操作を完了しますです。 

(1) 一連の初期化関数を呼び出す。 

(2) ストレージデバイスの初期化

(3) シリアルポート、LCDなどの簡単なハードウェアを初期化する。 

(4) 関連するネットワークデバイスの初期化、IP、MACアドレスなどの記入。 

(5) コマンドループ(=ブート全体のワークループ)に入り、シリアルポートからユーザが入力したコマンドを受け付け、適切な作業を行う。

3. U-Bootのブートシーケンス

主なシーケンスを下図に示します。


                                 写真はU-Bootのシーケンス
以下、コードを元に解説します。
/******************* 割り込みベクター ********************/
.globl _start //u-bootブートエントリー
_start: b reset //リセットベクターとリセットへのジャンプ
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq //割り込みベクター
ldr pc, _fiq //割り込みベクター
b sleep_setting //sleep_settingにジャンプする。

でメモリにコピーし、以下のコードで

       リロケートします。// uboot を RAM に再配置する。
       adr r0, _start // r0 はコードの現在の位置です。 
       ldr r2, _armboot_start // r2はarmbootの開始アドレスです。
       ldr r3, _armboot_end //r3はarmbootの終了アドレスです。
       sub r2, r3, r2 // r2 は armboot のサイズを取得します。 

       ldr r1, _TEXT_BASE // r1 がターゲットアドレスを取得  
       add r2, r0, r2 // r2 はソースエンドアドレスを取得します。 
       copy_loopです。// コードを再配置する

ldmia r0!, {r3-r10}. ソースアドレス[r0]から//コピー
STMIA R1!, {R3-R10}. //ターゲットアドレス[r1]にコピーする。
cmp r0, r2 //データブロックをコピー元データの終了アドレスまでコピー [r2]

       ble copy_loop

システムの電源投入またはRESET後、CPUのPCは一般にアドレス0x0を指し、アドレス0x0にある命令は

をリセットします。//ブートサブルーチンをリセットする

/******** CPU を SVC32 モードにする ********/

mrs r0,cpsr //CPSRステータスレジスタを読み込んでR0にセーブ
ビックR0,R0,#0x1f
Orr R0,R0,#0xD3
msr cpsr,r0   
                     //R0をステータス・レジスタに書き込む
/*********** ウォッチドッグをオフにする ************/
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*************** すべての割り込みをオフにする ****************/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
ldr r2, =0x7ff
ldr r0, =INTSUBMSK
str r2, [r0]
/************** システムクロックの初期化 ******************/
ldr r0, =LOCKTIME
ldr r1, =0xffffffff 
str r1, [r0].
clear_bssです。
        ldr r0, _bss_start //bssの開始アドレスを探す 
        add r0, r0, #4 //bssの1ワード目から 
        ldr r1, _bss_end // BSSアドレスの終わり 
        mov r2, #0x00000000 // ゼロクリア  
clbss_l:str r2, [r0] // BSSセグメント空間アドレスクリアループ 
        add r0, r0, #4
        cmp r0, r1
        BNE CLBSS_L

/***************** クリティカル初期化サブルーチン *******************/
/ * CPU初期化キーレジスタ
* クリティカルレジスタの設定
* メモリークロックの設定
* /
cpu_init_crit:
/* v4 I/Dキャッシュをフラッシュします*/。
mov r0, #0
MCR P15, 0, R0, C7, C7, 0 /* V3/V4キャッシュをフラッシュする。
MCR P15, 0, R0, C8, C7, 0 /* V4 TLBをフラッシュする。
/*************** MMU関連とキャッシュを無効にする ***************/
MRC P15, 0, R0, C1, C0, 0
bic r0, r0, #0x00002300 @ビット13, 9:8 をクリア (--V-- --RS)
bic r0, r0, #0x00000087 @ ビット7, 2:0 をクリア (B-- -CAM)
orr r0, r0, #0x00000002 @ビット2を設定 (A) Align
orr r0, r0, #0x00001000 @ セットビット12 (I) I-Cache
MCR P15, 0, R0, C1, C0, 0
/******* 位置を変更する前に、メモリクロックが開発ボードのハードウェアに依存するため、RAMの時間を設定する必要があります、ボードディレクトリの下にmemsetup.Sがあります。**************/
mov ip, lr
#IFNEF CONFIG_S3C2440A_JTAG_BOOT
bl memsetup // memsetupサブルーチンを呼び出す (board/smdk2442memsetup.S内)
#endif
mov lr, ip
mov pc, lr //サブルーチンリターン
memsetupを行います。   
/**************** メモリの初期化 *************/
        mov r1, #MEM_CTL_BASE
        adrl r2, mem_cfg_val
        add r3, r1, #52
1: ldr r4, [r2], #4
        str r4, [r1], #4
        cmp r1, r3
        bne 1b
/*********** 元々入っていた次のコマンドにジャンプします(start.Sファイル内) ************/  
mov pc, lr // サブルーチンが戻る
/*************** スタックを構築する ***************/
ldr r0, _armboot_end //armboot_endリロケーション
add r0, r0, #CONFIG_STACKSIZE //スタック領域を下に割り当てる。
sub sp, r0, #12 //アボートスタック用に3ワードを確保する
/*************** Cコードにジャンプして************/へ
ldr pc, _start_armboot //start_armboot関数のエントリ、start_armbootにジャンプします。
ワードセーブ機能エントリポインタ
_start_armboot: .word start_armboot //start_armboot 関数は lib_arm/board.c に実装されています。
ここから第2段階のCコードセクションに移ります
/**************** 例外ハンドラ ********************/
.アライン 5
undefined_instruction です。//未定義命令
get_bad_stack
バッドセーブユーザレジスタ
bl do_undefined_instruction
.アライン 5
software_interrupt。//ソフトウエア割り込み
取得_bad_stack
バッドセーブユーザレジスタ
BL DO_SOFTWARE_INTERRUPT
.アライン 5
prefetch_abort: // プリフェッチ例外をアボートする
取得_bad_stack
バッドセーブユーザレジスタ
bl do_prefetch_abort
.アライン 5
data_abort。//データを破棄する
取得_bad_stack
バッドセーブユーザレジスタ
bl do_data_abort
.アライン 5
not_usedです。//not_used
取得_bad_stack
バッドセーブユーザレジスタ
BL DO_NOT_USED
.アライン 5
irq: //割り込み要求
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs(ユーザー登録)。
.アライン 5
fiq: //朝食のリクエスト
スタックを取得する
/* 誰かもっと効率的な fiq_save_user_regs を書いてくれないかな */
irq_save_user_regs
BL DO_FIQ
irq_restore_user_regs(ユーザー登録)。
sleep_setting: //sleep_setting
SDRAMのセルフリフレッシュモードを準備する
ldr r0, =0x48000024 @ REFRESH レジスタ
LDR R1, [R0]の場合
orr r1, r1,#(1bd = &bd_data;
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _armboot_end_data - _armboot_start;
/*** init_sequence配列の実行を呼び出し、順番に初期化を行う ***/
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr){ (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr <未定義

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

  { <未定義

  ハング()。

}

}

#if 0
/*********** 使用可能なフラッシュユニットの設定 **********/
size = flash_init (); //フラッシュの初期化

display_flash_config (size); //フラッシュのサイズを表示します。

/**** _arm_boot は armboot.lds のリンクスクリプトで定義されています ********/
#endif
#IFDEF CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*********** VFD表示用メモリ確保(ページ全体) **********/
/**** armboot_real_end はボード固有のリンクスクリプトで定義されています ********/
addr = (_armboot_real_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = vfd_setmem (addr)。
gd->fb_base = addr;
/******* 次の画面に進みます ********/
addr += サイズ。
addr = (addr + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
mem_malloc_init (addr)。
#else
/******** ボード固有のリンクスクリプトで定義された /**** armboot_real_end *******/
mem_malloc_init (_armboot_real_end)です。
#endif /* CONFIG_VFD */
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init(); /* NANDの初期化 */。
#endif
#IFDEF CONFIG_HAS_DATAFLASH
AT91F_DataflashInit()です。
dataflash_print_info()です。
#endif
/********* 環境の初期化 **********/
env_relocate () を使用します。
/*********** 環境変数の設定、再配置 **********/
#IFDEF CONFIG_VFD
/* フレームバッファが確保された後に実行する必要があります */
drv_vfd_init();
#endif
/* 環境からIPアドレスを取得します */
bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
/* イーサネットインターフェイスMACアドレス*/
{ <未定義
  int i;
  ulong reg;
  char *s, *e;
  uchar tmp[64];
  i = getenv_r ("ethaddr", tmp, sizeof (tmp));
  s = (i > 0) ? tmp : NULL;
  for (reg = 0; reg bd-> bi_enetaddr);
#endif
#IFDEF CONFIG_DRIVER_LAN91C96
if (getenv ("ethaddr")){。 <未定義
  smc_set_mac_addr(gd->bd->bi_enetaddr) とします。
}
/* eth_hw_init(); */
#endif /* CONFIG_DRIVER_LAN91C96 */
/* 環境変数による初期化 */
if ((s = getenv ("loadaddr"))さん ! = NULL) { (ロードアドレス) <未定義
  load_addr = simple_strtoul (s, NULL, 16);

#if (CONFIG_COMMANDS & CFG_CMD_NET)
if ((s = getenv ("ブートファイル")) ! = NULL) { (ブートファイル) <未定義
  copy_filename (BootFile, s, sizeof (BootFile));
}
#endif /* CFG_CMD_NET */
#IFDEF BOARD_POST_INIT
board_post_init () を使用します。
#endif
/* main_loop() は常に自動起動を試み、ループは実行し続ける */。
for (;;) { <未定義
  main_loop (); /* メインループ関数は、ユーザーコマンドの実行を処理します-common/main.c
}
/* NOTREACHED - ブートする以外にコマンドループから抜け出す方法はない */。
}

UBOOTラーニングインサイト(UBOOTプロセス分析)。

UBOOTラーニングインサイト(UBOOTプロセス分析)