UEFIブートフロー: リセットベクターからExitBootServicesまで

フェーズ名を暗記するためではなく、マシンがどこで死んでいるかを知りデバッグする方向を掴むためにブートフローを学ぶ。SECからRuntimeまでの実際の障害モードへの地図。

更新 3 分で読めます
Đọc bằng 日本語 Tiếng Việt English
BIOS / UEFI cover

外から見ると似た障害があります。電源を入れても画面が真っ黒のまま。ベンダーロゴが表示されてからリセットする。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はブートをフェーズに分割することでこれを解決します。各フェーズが次のフェーズの基盤を構築します。

01 SEC

Security Phase

CPUリセット。リソースはほぼゼロ。PEIが動けるようテンポラリRAMを確立する

02 PEI

Pre-EFI Init

DRAMを初期化する。HOBリストを構築する。プラットフォームデータをDXEに渡す

03 DXE

Driver Execution

ドライバーをロードする。Protocolをpublishする。デバイスをenumerateする。firmware全体のエコシステムを構築する

04 BDS

Boot Device Select

BootOrderとBoot####を読む。Device Pathを解決する。OSローダーをロードする

05 TSL

Transient System Load

OSローダーが動いている。ExitBootServicesの呼び出しを準備している

06 Runtime

Runtime Phase

OSが引き継いだ。Runtime Servicesのみ残る: variable、時刻、リセット

UEFI/PIブートフロー: 各フェーズが独自のリソースを持ち、次のフェーズの基盤を構築する

覚えておくべき重要なこと: 各フェーズの障害は異なる形で現れます。 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()関数ではありません。各フェーズが独自の環境、独自の責任、独自の障害モードを持つフェーズのチェーンです。

01 SEC

テンポラリRAM

CPUリセット、最初期の環境構築、PEIを呼ぶ

02 PEI

メモリ初期化

DRAMを初期化し、HOBリストを構築し、DXEに渡す

03 DXE

ドライバーモデル

Dispatcher、protocol、handle database、driver binding

04 BDS

ブートオプション

BootOrder、Boot####、Device Path、LoadImage、StartImage

05 TSL

OSローダー

GetMemoryMap、ExitBootServices

06 Runtime

Runtime Services

NVRAM variable、時刻、リセット、プラットフォームによるSMMパス

デバッグ視点からのUEFIブートフローまとめ

デバッグするとき、最初のステップは詳細なソースコードを読むことではありません——このチェーンのどこでfirmwareが死んでいるかを正確に特定することです。フェーズがわかれば、どのレイヤーを見るべきかと、どのレイヤーをスキップできるかがわかります。


参考資料

次に読む

各フェーズには詳細なノートがあります。

この記事は役に立ちましたか?

ファームウェア、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.

Đọ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.