Androidブートローダー:3分で徹底理解するubootの起動と機能
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プロセス分析)。
関連
-
undefinedmakefile:4: *** セパレータがありません。
-
エラー: $PATH に受け入れ可能な C コンパイラが見つかりません。
-
ソリューションが不完全なタイプである
-
find:表現上の問題と解決策の前に、道筋がなければならない
-
エラー: 'for' ループの初期宣言は C99 モードでのみ許可されます。
-
ImportError: libSM.so.6: cannot open shared object file: そのようなファイルやディレクトリはありません 解決方法
-
を作ってください。*** ターゲットが指定されておらず、makefileも見つかりませんでした。
-
テキストファイルのビジー状態解消
-
Werror=unused-but-set-variableエラーの解決法
-
elasticsearchを解決する。例外 BindTransportException [9300-9400]へのバインドに失敗しました]。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Linuxシェルプログラミングにおける不正な置換の解決法
-
ベクターに型名がない
-
オフラインのデバイスをadbで表示させる解決方法
-
ubuntu installationEnvironmentError: mysql_config not found エラー
-
エラーについて: error: 'QApplication app' variable has initializer but incomplete type
-
linuxのCコンパイルで、整数からキャストをせずにポインタを作る代入が行われる理由
-
AttributeError: モジュール 'tensorflow' には 'get_default_graph' という属性がありません。
-
makeの問題解決。*** ターゲットが指定されておらず、makefileも見つかりません。
-
mfsmount トランスポートエンドポイントが接続されていない
-
mysqlbinlog: 不明な変数 'default-character-set=utf8mb4' の問題を解決する。