UEFIブートフロー: リセットベクターからExitBootServicesまで
フェーズ名を暗記するためではなく、マシンがどこで死んでいるかを知りデバッグする方向を掴むためにブートフローを学ぶ。SECからRuntimeまでの実際の障害モードへの地図。
外から見ると似た障害があります。電源を入れても画面が真っ黒のまま。ベンダーロゴが表示されてからリセットする。SSDはSetupで見えているのにブートメニューに出てこない。Windows Boot Managerはリストにあるのに選ぶとブート画面に戻ってくる。
ユーザーの視点からは、すべては「マシンが起動しない」にすぎません。
しかしfirmwareエンジニアの視点からは、これらの障害はまったく異なるレイヤーにあります。DRAMがまだ初期化されていない非常に早い段階で死ぬものもあります。firmwareがドライバーをロードしている最中に起きるものもあります。BDSがNVRAMからBoot####を読むときだけ現れるものもあります。そしてOSローダーがExitBootServicesを呼ぶ最後の境界でだけ出現するものもあります。
これがUEFIブートフローを学ぶことがフェーズ名を暗記するためではない理由です。SEC、PEI、DXE、BDS、TSL、Runtimeは、各フェーズが何のリソースを持っているか、システムのどの部分を構築しているか、そこで何かが失敗したときにどの方向でデバッグするかを知っているときに初めて意味を持ちます。
私の仕事はPOSシステム、キオスク、決済端末のBIOSカスタマイズです。そういった環境では「ゆっくり見ていこう」の余裕はありません。ピーク時間にお店でマシンが死んだら、最優先事項は素早く特定することです: firmwareはどのフェーズで死んでいるのか?
この記事はリセットベクターからExitBootServicesまでを、まさにその角度から追っていきます。覚えるための図としてではなく、デバッグの地図として。
なぜフェーズ構造が必要なのか
根本的な問題: CPUがリセットされた瞬間、システムにはほとんど何も作業できるものがありません。DRAMは初期化されていない、チップセットは設定されていない、通常の意味のスタックも存在しない。firmwareは一度にすべてを行うことができません。
UEFIはブートをフェーズに分割することでこれを解決します。各フェーズが次のフェーズの基盤を構築します。
Security Phase
CPUリセット。リソースはほぼゼロ。PEIが動けるようテンポラリRAMを確立する
Pre-EFI Init
DRAMを初期化する。HOBリストを構築する。プラットフォームデータをDXEに渡す
Driver Execution
ドライバーをロードする。Protocolをpublishする。デバイスをenumerateする。firmware全体のエコシステムを構築する
Boot Device Select
BootOrderとBoot####を読む。Device Pathを解決する。OSローダーをロードする
Transient System Load
OSローダーが動いている。ExitBootServicesの呼び出しを準備している
Runtime Phase
OSが引き継いだ。Runtime Servicesのみ残る: variable、時刻、リセット
覚えておくべき重要なこと: 各フェーズの障害は異なる形で現れます。 PEIに本当の問題があるのにBDSをデバッグしても意味がありません。PEIからのHOBが間違っているのにDXEドライバーをデバッグしても意味がありません。
SEC: システムに何もない段階
CPUがリセットされた直後、システムは極めて制約された状態にあります。DRAMは初期化されておらず、通常の意味のスタックも存在しません。firmwareはこの条件下で動き始めなければなりません。
SECはただ一つのことをします: PEIが動けるための最小限の環境を確立します。
リセットベクター
↓
テンポラリRAMを設定 (cache-as-RAMまたは内部SRAM)
↓
プラットフォームが要求する場合の初期firmware検証
↓
PEI Coreに制御を移す
SECは多くのポリシーを実装しません。PEIが立つ場所を「整地する」コードです。
SECを疑うのはいつか?
ボードが非常に早い段階で死ぬとき——POST codeなし、シリアルログなし、最初からリセットループ。その時点では通常のツールがまだ使えないため、POST code LEDかハードウェアデバッグポートだけが情報を提供します。
PEI: DXEの基盤を構築する
PEIはDXEが動くための最小限のインフラを構築します。最も重要なタスク: DRAMの初期化。RAMが利用できなければ、firmwareはドライバーをロードできず、サービスを作れず、最小限以上のことは何もできません。
メモリの初期化以外に、PEIはHOBリスト (Hand-Off Block)——メモリマップ、firmware volumeの場所、ブートモード、プラットフォーム情報を記述するデータ構造——を作成してDXEに渡します。
PEIが構築するHOBリスト:
├─ Memory Resource HOB: DXEはRAMがどこにどれだけあるかを知る
├─ Firmware Volume HOB: DXE dispatcherはどこでドライバーを探すかを知る
├─ GUID HOB (プラットフォーム固有): ボード情報、シリコン、ポリシーデータ
└─ Boot Mode: Normal / S3 Resume / Recovery
HOBはPEIとDXEの橋渡しです。 DXEはPEIがHOBに書いたこと以外、ハードウェアについて何も知りません。HOBが欠けていたり間違っていたりすると、DXEは起動できるかもしれませんが、間違ったプラットフォームデータで動くことになります。
PEIを疑うのはいつか?
- POST codeがPEIのレンジで止まる
- メモリトレーニング後にリセットループ
- DXEは始まるがドライバーやリソースが欠けている——DXEを急いで直そうとせず、まずHOBリストを確認する
DXE: ドライバーとサービスのエコシステム
メモリが利用可能でHOBリストに必要なデータが揃ったら、DXE Coreはドライバーをロードし、handle databaseを作成し、protocolをpublishし、デバイスをenumerateして、UEFIの「エコシステム」を構築し始めます。
DXE Dispatcherはfirmware volumeをスキャンし、各ドライバーのDEPEX (dependency expression)をチェックし、必要なprotocolがすべてinstallされたときだけドライバーをdispatchします。つまりdispatch順序はFV内のファイルの順序ではなく、依存関係チェーンに従います。
DXE Dispatcherループ:
FVをスキャン → DEPEXをチェック
Protocolがまだない: ドライバーは待機
Protocolが存在する: dispatch → ドライバーが新しいprotocolをinstall → 待機中のドライバーをunlock
dispatchするものがなくなるまで繰り返す → BDSへ移行
DXEを疑うのはいつか?
デバイスがブートメニューに出てこないからといってBDSが間違っているとは限りません。この順序で確認します。
DXEデバッグチェックリスト
BDS: firmwareからOSローダーへ
BDSはNVRAMからブートオプションを読み取り、必要なデバイスを接続し、Device Pathを解析し、.efiファイルをロードして、OSローダーに制御を渡します。
各ブートオプションはNVRAMにBoot#### variableとして保存されています。
BootOrder: 0000, 0001, 0002
Boot0000: Windows Boot Manager
├─ Device Path: HD(1,GPT,...)/File(\EFI\Microsoft\Boot\bootmgfw.efi)
└─ Attributes: LOAD_OPTION_ACTIVE
Boot0001: UEFI Shell
Boot0002: PXE Boot
BDSはBootOrderを読み、各オプションを順番に試します。各オプションに対してDevice Pathを解決し(コントローラーを接続し、ESPを見つけ)、.efiファイルをロードしてStartImage()を呼びます。
BDSを疑うのはいつか?
SSDはDXEで認識されているのにWindowsが起動しない。Windows Boot Managerを疑う前に確認します。
BDSデバッグチェックリスト
TSL: OSが引き継ぐ前の移行期間
TSLはBDSがOSローダーをロードして動いているが、OSがまだ完全に制御を引き継いでいない時間帯です。ブートローダーはUEFI servicesを使ってカーネルを読み込み、メモリを準備し、ExitBootServices()を呼びます。
ExitBootServices()は引き返せないポイントです。この呼び出し後、Boot Servicesは無効になり、Runtime Servicesだけが残ります。
TSLの障害はfirmwareとOSの境界で起きるため、最もデバッグが難しいものの一つです。
// ブートローダーはメモリマップを取得してExitBootServicesを呼ばなければならない
// 正しいMapKeyで。2つのステップの間にメモリマップが変わったら: 失敗
GetMemoryMap(&MapSize, MemMap, &MapKey, ...);
// ここでメモリの確保/解放をしないこと
ExitBootServices(ImageHandle, MapKey); // MapKeyは一致しなければならない
TSLを疑うのはいつか?
- OSローダーは起動したがカーネルが立ち上がらない
ExitBootServices()がEFI_INVALID_PARAMETERを返すStartImage()が成功した後に障害が起きる
Runtime: OSが引き継いだ後
ExitBootServices()後、OSカーネルが動きます。UEFI Boot Servicesはなくなりますが、Runtime Servicesは正しくマップされていればOSから呼べます: NVRAMのvariableの読み書き、システムリセット、システム時刻の取得。
多くのプラットフォームでは、SetVariableの実際のパスは次のようになります。
OSがSetVariable("BootOrder", ...)を呼ぶ
↓
Runtime Variable Service
↓ (多くのプラットフォームで)
SMM Variable Driver
↓
SPI flashへの書き込み
OS動作後のvariable障害——特にefibootmgrの書き込みが効かないとき——はRuntime variable path、SMM variable driver、SPI flashを確認する必要があります。Setupで変更した設定がリブート後に消えるときは、HII保存フロー、NVRAM、consumerモジュールも確認する必要があります。
症状別デバッグ
ブート障害が起きたとき、最初の質問は「何のエラーか?」ではなく「どのフェーズで死んでいるか?」です。
| 症状 | 疑うべきフェーズ | 確認すること |
|---|---|---|
| ログなし、早期リセットループ | SEC | DRAMが未初期化。POST code LEDかハードウェアトレースのみ。 |
| PEI POST codeで停止、メモリトレーニング後にリセット | PEI | メモリの初期化、HOBリスト、PEI→DXEハンドオフ。 |
| デバイスがブートメニューに出てこない | DXE | ドライバーdispatch、DEPEX、Driver Binding、protocolチェーン。 |
| ブートメニューにはあるがOSが起動しない | BDS | BootOrder、Boot####、Device Path、LoadImage。 |
| OSローダーは動くがカーネルが立ち上がらない | TSL | ExitBootServices、メモリマップキー、ローダーの障害。 |
| 設定を保存してもリブート後に消える | Runtime / HII / NVRAM | OSからかSetup UIからかによる。RuntimeパスとHII保存フローの両方を確認。 |
まとめ
UEFIブートフローは最初から最後まで走る単一のmain()関数ではありません。各フェーズが独自の環境、独自の責任、独自の障害モードを持つフェーズのチェーンです。
テンポラリRAM
CPUリセット、最初期の環境構築、PEIを呼ぶ
メモリ初期化
DRAMを初期化し、HOBリストを構築し、DXEに渡す
ドライバーモデル
Dispatcher、protocol、handle database、driver binding
ブートオプション
BootOrder、Boot####、Device Path、LoadImage、StartImage
OSローダー
GetMemoryMap、ExitBootServices
Runtime Services
NVRAM variable、時刻、リセット、プラットフォームによるSMMパス
デバッグするとき、最初のステップは詳細なソースコードを読むことではありません——このチェーンのどこでfirmwareが死んでいるかを正確に特定することです。フェーズがわかれば、どのレイヤーを見るべきかと、どのレイヤーをスキップできるかがわかります。
参考資料
次に読む
各フェーズには詳細なノートがあります。
- SECとは?
- PEIとは?
- DXEとは?
- DXE Dispatcherとは?
- BDSとは?
- ExitBootServicesとは?
- DXEフェーズ: ドライバー、Protocolと何も動かないときのログの読み方
- UEFIのSMM: デバッグ視点からのSystem Management Mode
この記事は役に立ちましたか?
ファームウェア、BIOS/UEFI、組み込みシステムを学んでいる人に共有できます。
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
DXEフェーズ: ドライバー、Protocolと何も動かないときのログの読み方
DXEの深掘り: dispatcher、DEPEX、Driver Binding、protocolデータベース。シリアルログ、POST code、UEFI Shellを使って実際の障害をデバッグする方法。
BIOSとUEFIはどこが違うのか?
現代のマシンがUEFIを使っているのに「BIOSに入る」と言い続けるのはなぜか。BIOS・UEFI・ブートフロー・Secure Boot・Boot####とOSが動く前にfirmwareがシステムを構築する仕組みを解説。
Boot Failure Checklistとは?
BIOS/UEFIおよびembedded firmware学習者向けにBoot Failure Checklistを説明するクイックノート。
Đọc thêm về BIOS/UEFI
Khám phá các bài viết về BIOS/UEFI, embedded firmware, debugging và system-level thinking.