paint-brush
ファームウェアの秘密を探る旅: BIOS/UEFI から OS まで@tristejoursoir
730 測定値
730 測定値

ファームウェアの秘密を探る旅: BIOS/UEFI から OS まで

Aleksandr Goncharov20m2024/08/22
Read on Terminal Reader

長すぎる; 読むには

従来の BIOS から最新の UEFI ファームウェアへの進化を探り、ブート シーケンスの管理方法を理解し、ブート サービスとランタイム サービスの役割を確認します。OS ブート ローダーの複雑さを詳しく調べ、ファームウェアが高度な機能とアプリケーションをどのようにサポートしているかを確認します。
featured image - ファームウェアの秘密を探る旅: BIOS/UEFI から OS まで
Aleksandr Goncharov HackerNoon profile picture
0-item
1-item


コンピュータの電源ボタンを押した瞬間に何が起こるのか疑問に思ったことはありませんか? 画面が点灯する前のその短い休止の背後で、一連の複雑なプロセスが進行しています。この記事では、ファームウェアの魅力的な世界に飛び込み、ブート プロセス中にさまざまなコンポーネントがどのように相互作用するかを探ります。


これらのつながりを理解することで、システムを動かす基礎要素をより明確に把握できるようになります。ここでは主にIntel x86 アーキテクチャに焦点を当てますが、多くの原則は他のアーキテクチャにも当てはまります。


このシリーズの第 1 部を見逃した方は、 こちらをクリックしてご覧ください。それでは、ファームウェアの背後にある謎を解き明かしましょう。

目次:

  • 定義
  • 全体的なファームウェアアーキテクチャ
  • 第一段階ブートローダー (FSBL)
    • BIOS (POST フェーズ)
    • UEFI プラットフォーム初期化 (PI)
    • コアブート
    • その他の解決策
  • 第 2 ステージ ブート ローダー (SSBL)
    • BIOS
    • UEFI
  • OS ブートローダー


定義

  • ファームウェア: ハードウェアに組み込まれた特殊なタイプのソフトウェアで、低レベルの制御を提供し、ハードウェアが正しく機能し、他のシステム コンポーネントと対話できるようにします。


  • 基本入出力システム (BIOS) : プラットフォームの電源投入後にハードウェアの初期化を行うレガシー ファームウェア (元々はIBM PC用に作成されたもの)。今日では、漠然とファームウェアの完全なセットと呼ばれることがよくあります。


  • ブートローダ: コンピュータの起動を担当するファームウェアの一般的な名称。 BIOSに代わる最新の概念として使用され、プロセッサとチップセットを初期化するためのブートストラップ コードを含むフレームワークや、サードパーティ (マザーボード開発者など) がプラットフォーム固有の初期化を実行するためのインターフェイスを提供することがよくあります。


  • ペイロード: ブートローダの終了時に実行されるソフトウェア。第 2 段階のブートローダ、オペレーティング システム、BIOS/UEFI アプリケーションなどです。通常は、ファームウェアの設計に従ってブートストラップ フローを処理します。


  • BIOSブートローダという用語の使い方は、その意味が文脈によって異なるため、混乱を招く可能性があります。ただし、ファームウェアBIOS 、またはブートローダについて言及する場合、通常はオペレーティング システムとハードウェアの間で実行されるファームウェアの完全なセットを指します。


  • EFIUEFI : Extensible Firmware Interface (EFI) は、 Intel によって開発されたオリジナルの仕様です。Unified Extensible Firmware Interface (UEFI) は、オリジナルの仕様を標準化および拡張するためにUEFI フォーラムによって作成された、 EFIの後継です。ほとんどの場合、 EFIUEFI は同じ意味で使用されます。

全体的なファームウェアアーキテクチャ

ファームウェア コンポーネントがどのように相互作用するかを理解するために、接続されているすべての部分を含むアーキテクチャ全体を調べます。下の図に示す実行フローは、第 1 ステージ ブートローダの一部であるリセット ベクターから始まります。そこから、さまざまなファームウェア ステージを経て進行します。



ファームウェアまたは BIOS は、通常、2 つの主要な部分に分けられ、その間のインターフェースは通常最小限です。


  1. ハードウェア初期化: システムのハードウェア コンポーネントの初期化を担当します。
  2. OS およびユーザーへのインターフェース: オペレーティング システムおよびユーザーへの必要なインターフェースを提供します。


プラットフォーム ファームウェアの設計は、ハードウェアの初期化とブート機能を組み合わせたモノリシックにすることも、モジュール式段階的なブート フローに従うこともできます。設計の選択はシステム要件によって異なり、特定のデバイスに適している場合があります。


次の図は、さまざまなファームウェア コンポーネントがどのように相互作用し、ブート プロセスをサポートするために一緒に使用されるかを示しています (矢印は実行の順序を示します)。



これらの図が今は複雑に思えても心配しないでください。この記事を読んだ後にもう一度見直すと、より明確になります。

第一段階ブートローダー (FSBL)

このファームウェアは、最小限のハードウェア初期化に重点を置いてコンピューターと組み込みシステムを初期化するように設計されています。つまり、絶対に必要なことだけを実行し、制御を第 2 ステージ ブートローダーに渡してオペレーティング システムを起動します。FSBLは、フラッシュ チップ以外のストレージ メディアからオペレーティング システムをロードしません。基礎となるハードウェアを初期化するだけで、ハード ドライブ、SSD、USB フラッシュ ドライブなどのブート メディアは処理しないため、実際にオペレーティング システムを起動するには別のソフトウェアが必要です。


FSBLの主な責任:


  1. CPU : 16 ビットリアル モードから 32 ビット保護モードに切り替えます (: BIOS の場合は仮想 8086 モード)。
  2. キャッシュ使用率: FSP-Tを呼び出して、 C 環境Cache-As-RAMを構成します。
  3. デバッグ ポート: ボード固有の初期化メソッドを呼び出して、構成されたデバッグ ポートを初期化します。
  4. メモリの初期化: FSP-Mを呼び出してシステムのメインメモリを初期化し、重要なシステムメモリ情報を保存します。
  5. GPIO : 外部デバイスとのインターフェース用に汎用入出力 (GPIO) ピンを構成します。
  6. シリコン: 早期プラットフォーム初期化を実行し、 FSP-Sを使用してチップセット、CPU、および IO コントローラーの初期化を完了します。
  7. PCI 列挙: PCI デバイスを列挙し、メモリ アドレスや IRQ などのリソースを割り当てます。
  8. ペイロードの準備: ペイロードに渡す必要がある準備情報 (コアブート テーブル、HOB) を含むSMBIOSおよびACPIテーブルを設定します。
  9. ロードとハンドオフ: ペイロードへの制御のロードと転送。

BIOS (POST フェーズ)

コンピューティングの初期の頃は、オープンソース ソフトウェアは広く普及しておらず、ほとんどの BIOS 実装は独自のものでした。Super PC/Turbo XT BIOSGLaBIOSなど、BIOS POST ソース コードを提供するオープン ソリューションはわずかしかありません。これらのプロジェクトは、IBM 5150/5155/5160 システムとほとんどの XT クローンで動作するように設計されました。


ただし、 OpenBIOSSeaBIOSなどのよく知られているオープンソースの BIOS 実装は、ベアハードウェア上で実行することを目的としていないため、ハードウェアの初期化を実行しません。ただし、これらは第 2 ステージ ブートローダとして広く使用されており、QEMU や Bochs などの仮想環境でネイティブに実行されます。


いずれにせよ、これらの初期の BIOS を直接操作したり、その詳細を深く調べる必要はほとんどありません。ただし、探索することに興味がある場合は、前述のリポジトリが適切な出発点になります。


現在の開発動向から判断すると、独自の BIOS ソリューションの開発は進行中ではないようで、このようなプロジェクトは最新の代替手段の登場により時代遅れになっています。

UEFI プラットフォーム初期化 (PI)

ブート プロセスは、次の図に示すように、左から始まり右に進む段階的なフローに従います。プラットフォーム ブート プロセスのタイムラインは、黄色のボックスで示されるように、次のフレーズに分割されます。



  • セキュリティ (SEC) :リセット ベクター後の最初のフェーズで、主な機能は一時 RAM (CPU Cache-As-RAMまたは SRAM) をセットアップすることです。
  • Pre-EFI 初期化 (PEI) : このフェーズでは、Pre-EFI 初期化モジュール (PEIM)と呼ばれる特殊なドライバーがディスパッチされます。これらのモジュールは、CPU とチップセットの構成やメイン メモリ (DRAM)のセットアップなど、重要なハードウェア初期化を処理します。
  • ドライバー実行環境 (DXE) : このフェーズでは、システムの残りの初期化が実行されます。DXE フェーズは、 UEFI サービスを提供して、システムの動作に必要なさまざまなプロトコルとドライバーをサポートします。
  • ブート デバイス選択 (BDS) : このフェーズでは、プラットフォーム ブート ポリシーを実装し、ブート シーケンスを決定して、適切なブート デバイス/ローダーを選択します。
  • 一時システム ロード (TSL) : このフェーズでは、システムは UEFI サービスを使用してアプリケーションを実行し、OS を準備します。これには、UEFI 環境からオペレーティング システムへの移行が含まれ、 ExitBootServices()呼び出しで終了します。
  • 実行時 (RT) : このフェーズでは、オペレーティング システムは完全に動作し、その制御下でシステムを管理します。
  • After Life (AL) : このフェーズでは、ハードウェアまたは OS がクラッシュ/シャットダウン/再起動するシナリオに対処します。ファームウェアは回復アクションを試行する場合がありますが、UEFI PI 仕様では、このフェーズの特定の要件や動作は定義されていません。


このプロセスとその実行フェーズは、UEFI プラットフォーム初期化 (PI) 仕様でカバーされています。ただし、 UEFI インターフェイス(図の太い青い線で示されています) もあります。これは前のドキュメントの一部ではなく、 UEFI 仕様で説明されています。UEFI名前と頻繁な使用は混乱を招く可能性がありますが、これら 2 つのドキュメントの焦点は異なります。


  • UEFI PI 仕様: 低レベルのファームウェア コンポーネント間のインターフェイスに焦点を当て、これらのモジュールがプラットフォームを初期化するためにどのように相互作用するかを詳細に説明します。


  • UEFI 仕様: オペレーティング システム (OS) とファームウェア間のやり取りのためのインターフェイスを定義します。これについては、第 2 ステージ ブートローダのコンテキストでさらに詳しく説明します。UEFI 仕様は PI 仕様に依存していることに注意してください。


基本的に、どちらの仕様もインターフェースに関するものですが、レベルが異なります。詳細については、 UEFI フォーラムの Web サイトで両方の仕様にアクセスできます。


UEFI PI は当初、第 1 ステージ ブートローダと第 2 ステージ ブートローダの区別を考慮せずに、統合ファームウェア ソリューションとして設計されました。ただし、 UEFI第 1 ステージ ブートローダと呼ぶ場合、 SECPEI 、および初期の DXEフェーズが含まれます。DXE を初期段階後期段階に分ける理由は、初期化プロセスにおける役割が異なるためです。


初期の DXEフェーズでは、ドライバーは通常、重要な CPU/PCH/ボードの初期化を実行し、DXE フェーズをプラットフォーム固有のハードウェアから分離するのに役立つDXE アーキテクチャ プロトコル (AP)も生成します。APプラットフォーム固有の詳細をカプセル化し、後期の DXEフェーズがハードウェアの詳細とは独立して動作できるようにします。



コアブート

Coreboot の仕組みに関する詳細な記事が近日公開されます。私のソーシャル メディアをフォローしてください。近日中に公開されます。

その他の解決策

  • Intel Slim Bootloader (SBL) : コアハードウェアコンポーネントの初期化のみを提供し、その後ペイロードをロードする純粋な第 1 段階のブートローダ。ただし、 Intel x86 プラットフォームでのみ動作し、AMD x86 やその他のアーキテクチャはサポートされていません。
  • U-Boot : 第一段階と第二段階の両方のブートローダーです。ただし、プラットフォームの x86リセット ベクターから直接ブートする (ベア モードと呼ばれる) ためのサポートは、他のファームウェアに比べて制限されています。組み込みシステムや ARM ベースのデバイスでより人気があります。第二段階のブートローダーとして、U-Boot はUEFI のサブセットを実装しますが、組み込みシステムに重点を置いています。

第 2 ステージ ブート ローダー (SSBL)

初期のハードウェア セットアップが完了すると、第 2段階が始まります。その主な役割は、オペレーティング システムとプラットフォーム ファームウェアの間にソフトウェア インターフェイスを設定し、OS がシステム リソースを管理し、ハードウェア コンポーネントと対話できるようにすることです。


SSBL は、ハードウェアのバリエーションを可能な限り隠し、ハードウェア レベルのインターフェイスのほとんどを処理することで OS とアプリケーションの開発を簡素化することを目的としています。この抽象化により、開発者は基盤となるハードウェアの違いを気にすることなく、より高レベルの機能に集中できます。


SSBLの主な責任:


  1. プラットフォーム情報の取得: メモリ マッピング、SMBIOS、ACPI テーブル、SPI フラッシュなど、プラットフォーム固有の情報を第 1 段階ブートローダから取得します。


  2. プラットフォームに依存しないドライバーを実行します: SMM、SPI、PCI、SCSI/ATA/IDE/DISK、USB、ACPI、ネットワーク インターフェイスなどのドライバーが含まれます。


  3. サービス実装 (別名インターフェイス) : オペレーティング システムとハードウェア コンポーネント間の通信を容易にする一連のサービスを提供します。


  4. セットアップ メニュー: システム構成のセットアップ メニューを提供し、ユーザーは起動順序、ハードウェア設定、その他のシステム パラメータに関連する設定を調整できます。


  5. ブート ロジック: 利用可能なブート メディアからペイロード (おそらくオペレーティング システム) を見つけてロードするメカニズム。

BIOS

BIOS のインターフェースは、BIOS サービス/関数/割り込み呼び出しと呼ばれます。これらの関数は、ハードウェア アクセス用の一連のルーチンを提供しますが、システムの特定のハードウェア上でどのように実行されるかという具体的な詳細は、ユーザーには表示されません。


16 ビットリアル モードでは、 INT x86 アセンブリ言語命令を介してソフトウェア割り込みを呼び出すことで簡単にアクセスできます。32 ビットプロテクト モードでは、セグメント値の処理方法が異なるため、ほぼすべての BIOS サービスが利用できません。




このインターフェイスの使用方法の例として、シリンダ ヘッド セクター (CHS)アドレス指定を使用してセクター ベースのハード ディスクとフロッピー ディスクの読み取りおよび書き込みサービスを提供するディスク サービス( INT 13h ) を取り上げます。2 つのセクター (1024 バイト) を読み取り、メモリ アドレス0x9020にロードするとすると、次のコードを実行できます。


 mov $0x02, %ah # Set BIOS read sector routine mov $0x00, %ch # Select cylinder 0 mov $0x00, %dh # Select head 0 [has a base of 0] mov $0x02, %cl # Select sector 2 (next after the # boot sector) [has a base of 1] mov $0x02, %al # Read 2 sectors mov $0x00, %bx # Set BX general register to 0 mov %bx, %es # Set ES segment register to 0 mov $0x9020, %bx # Load sectors to ES:BX (0:0x9020) int $0x13 # Start reading from drive jmp $0x9020 # Jump to loaded code


このサービスが SeaBios でどのように記述されているかに興味がある場合は、 src/disk.cを参照してください。

BOOTフェーズ

  • デバイスから最初の 512 バイトのセクター(セクター 0) を読み取ることによって、起動可能なデバイス(ハード ドライブ、CD-ROM、フロッピー ディスクなど) の検索を開始します。


  • BIOS のブートストラップ シーケンスは、見つかった最初の有効なマスター ブート レコード (MBR)を、コンピューターの物理メモリの物理アドレス0x7C00にロードします (ヒント: 0x0000:0x7c000x7c0:0x0000 は同じ物理アドレスを参照します)。


  • BIOS はペイロードの最初の 512 バイトに制御を移します。このロードされたセクターはペイロード コード全体を格納するには小さすぎますが、ブート可能なデバイスからペイロードの残りをロードする目的で使用されます。この時点で、ペイロードは BIOS によって公開されたインターフェイスを使用できます。


初期の頃にはBIOS 仕様が存在しなかったことは注目に値します。BIOS は事実上の標準であり、1980 年代の実際の IBM PC で動作していたのと同じように動作します。他のメーカーは、IBM 互換の BIOS をリバース エンジニアリングして作成しただけです。その結果、BIOS メーカーが新しい BIOS 機能を発明したり、重複する機能を持たせたりすることを防ぐ規制はありませんでした。

統合拡張ファームウェア インターフェース (UEFI)

前述のように、UEFI 自体は単なる仕様であり、多くの実装があります。最も広く使用されているのは、UEFI および PI 仕様のオープンソースリファレンス実装であるTianoCore EDK IIです。EDKII だけでは完全に機能するブート ファームウェアを作成するには不十分ですが、ほとんどの商用ソリューションの強固な基盤を提供します。


さまざまなファーストステージ ブートローダをサポートし、UEFI インターフェイスを提供するために、 UEFI ペイロードプロジェクトが使用されます。これは、実行された初期セットアップとブート ファームウェアによって提供されるプラットフォーム情報に依存して、システムを UEFI 環境用に準備します。


UEFI ペイロードは、プラットフォームに依存しないDXEフェーズとBDSフェーズを使用します。さまざまなプラットフォームに適応できる汎用ペイロードを提供します。ほとんどの場合、カスタマイズやプラットフォーム固有の調整は必要なく、ファーストステージ ブートローダーからプラットフォーム情報を取得してそのまま使用できます。


UEFI ペイロードのバリアント:


  1. レガシー UEFI ペイロード: 必要な実装固有のプラットフォーム情報を抽出するための解析ライブラリが必要です。ブートローダが API を更新する場合は、ペイロードも更新する必要があります。



  2. ユニバーサル UEFI ペイロード:ユニバーサル スケーラブル ファームウェア (USF) 仕様に準拠し、共通イメージ形式として実行可能およびリンク可能形式 (ELF)またはフラット イメージ ツリー (FIT)を使用します。ペイロード自体を解析するのではなく、ペイロード エントリでハンドオフ ブロック (HOB)を受信することを想定しています。


レガシー UEFI ペイロードは問題なく動作しますが、EDK2 コミュニティは業界をユニバーサル UEFI ペイロードへと移行させようとしています。ペイロードの選択は、ファームウェア コンポーネントによって異なります。たとえば、私のパッチなしでは、 Slim Bootloaderで SMM サポート付きのレガシー ペイロードを実行することはできません。一方、コアブートでユニバーサルペイロードを使用するには、コアブート テーブルをHOBに変換するためのシム レイヤーが必要です。これは、 StarLabs EDK2 フォークでのみ利用可能な機能です。

インタフェース

すべての UEFI 準拠システムは、UEFI 環境で実行されるすべてのコード (ドライバー、アプリケーション、OS ローダー) に渡されるシステム テーブルを提供します。このデータ構造により、UEFI 実行可能ファイルは、 ACPISMBIOS、 UEFI サービスのコレクションなどのシステム構成テーブルにアクセスできます。



テーブル構造はMdePkg/Include/Uefi/UefiSpec.hに記述されています。


 typedef struct { EFI_TABLE_HEADER Hdr; CHAR16 *FirmwareVendor; UINT32 FirmwareRevision; EFI_HANDLE ConsoleInHandle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; EFI_HANDLE ConsoleOutHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; // // A pointer to the EFI Runtime Services Table. // EFI_RUNTIME_SERVICES *RuntimeServices; // // A pointer to the EFI Boot Services Table. // EFI_BOOT_SERVICES *BootServices; UINTN NumberOfTableEntries; EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE;


サービスには、ブート サービスランタイム サービスプロトコルによって提供されるサービスなどのタイプが含まれます。


UEFI は、UEFI プロトコルを設定することでデバイスへのアクセスを抽象化します。これらのプロトコルは関数ポインターを含むデータ構造であり、他のモジュールがそれらを見つけて使用できるようにするグローバル一意識別子 (GUID)によって識別されます。これらはブート サービスを通じて検出できます。


UEFI ドライバーはこれらのプロトコルを生成し、実際の関数 (ポインターではありません!) はドライバー自体に含まれています。このメカニズムにより、UEFI 環境内のさまざまなコンポーネントが相互に通信できるようになり、OS が独自のドライバーをロードする前にデバイスと対話できるようになります。



一部のプロトコルは UEFI 仕様で事前定義および説明されていますが、ファームウェア ベンダーは独自のカスタム プロトコルを作成してプラットフォームの機能を拡張することもできます。


ブートサービス

起動時にのみ使用できる関数を提供します。これらのサービスはEFI_BOOT_SERVICES.ExitBootServices()関数が呼び出されるまで利用可能です ( MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c )。


すべてのブート サービスへのポインターは、ブート サービス テーブル( MdePkg/Include/Uefi/UefiSpec.h ) に格納されます。


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_MEMORY_MAP GetMemoryMap; EFI_ALLOCATE_POOL AllocatePool; EFI_FREE_POOL FreePool; ... EFI_HANDLE_PROTOCOL HandleProtocol; ... EFI_EXIT_BOOT_SERVICES ExitBootServices; ... } EFI_BOOT_SERVICES;


ランタイムサービス

オペレーティング システムの実行中も、最小限のサービス セットにアクセスできます。ブート サービスとは異なり、これらのサービスは、任意のペイロード (OS ブートローダーなど) がEFI_BOOT_SERVICES.ExitBootServices()の呼び出しによってプラットフォームを制御した後も有効です。


すべてのランタイム サービスへのポインターは、ランタイム サービス テーブル( MdePkg/Include/Uefi/UefiSpec.h ) に格納されます。


 typedef struct { EFI_TABLE_HEADER Hdr; ... EFI_GET_TIME GetTime; EFI_SET_TIME SetTime; ... EFI_GET_VARIABLE GetVariable; EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; EFI_SET_VARIABLE SetVariable; ... EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; EFI_RESET_SYSTEM ResetSystem; ... } EFI_RUNTIME_SERVICES;


下の図は、ブート サービスとランタイム サービスのタイムラインを示しており、各サービスがいつアクティブになるかを正確に確認できます。



ブートデバイス選択 (BDS) フェーズ

UEFI 仕様では、UEFI ブート マネージャーと呼ばれるブート ポリシー エンジンが定義されています。これは、特定の順序でUEFI アプリケーションをロードしようとします。この順序とその他の設定は、グローバルNVRAM (不揮発性ランダム アクセス メモリ) 変数を変更することで構成できます。最も重要な変数について説明します。


  • Boot#### ( ####は一意の 16 進数値に置き換えられます) — ブート/ロード オプション。
  • BootCurrent — 現在実行中のシステムを起動するために使用されるブート オプション。
  • BootNext — 次回の起動のみの起動オプション。これは、1 回の起動のみBootOrderを置き換え、最初の使用後にブート マネージャーによって削除されます。これにより、 BootOrderを変更せずに、次回の起動の動作を変更できます。
  • BootOrder — 順序付けられたブート オプション ロード リスト。ブート マネージャーは、このリストの最初のアクティブ オプションのブートを試行します。失敗した場合は、次のオプションを試行します。
  • BootOptionSupport — ブート マネージャーによってサポートされるブート オプションの種類。
  • Timeout - BootNextまたはBootOrderから起動値を自動的に選択するまでの、ファームウェアのブート マネージャーのタイムアウト (秒単位)。


これらの変数は、efibootmgr(8)を使用してLinuxから簡単に取得できます。


 [root@localhost ~]# efibootmgr BootCurrent: 0000 Timeout: 5 seconds BootOrder: 0000,0001,2001,2002,2003 Boot0000* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi) Boot0001* Windows Boot Manager HD(1,GPT,6f185443-09fc-4f15-afdf-01c523565e52,0x800,0x32000)/File(\EFI\Microsoft\Boot\bootmgfw.efi)57a94e544f5753000100000088900100780000004200430044039f0a42004a004500430054003d007b00390064006500610038003600320063002d1139006300640064002d0034006500370030102d0061006300630031002d006600330032006200330034003400640034003700390035007d00000033000300000710000000040000007fff0400 Boot0002* ARCHLINUX HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000) Boot2001* EFI USB Device RC Boot2002* EFI DVD/CDROM RC Boot2003* EFI Network RC


上記のコード スニペットを参考にして、ブートを見てみましょう。UEFI はBootOrderリストの反復処理を開始します。リスト内の各エントリについて、対応するBoot####変数を検索します (0000 の場合はBoot0000の場合はBoot2003など)。変数が存在しない場合は、次のエントリに進みます。変数が存在する場合は、変数の内容を読み取ります。各ブート オプション変数には、可変長フィールドのバイト パック バッファーであるEFI_LOAD_OPTION記述子が含まれています (これは単なるデータ構造です)。


データ構造は[MdePkg/Include/Uefi/UefiSpec.h][ https://github.com/tianocore/edk2/blob/edk2-stable202405/MdePkg/Include/Uefi/UefiSpec.h#L2122 )に記載されています。


 typedef struct _EFI_LOAD_OPTION { /// The attributes for this load option entry. UINT32 Attributes; /// Length in bytes of the FilePathList. UINT16 FilePathListLength; /// The user readable description for the load option. /// Example: 'ARCHLINUX' / 'Windows Boot Manager' / `EFI USB Device` // CHAR16 Description[]; /// A packed array of UEFI device paths. /// Example: 'HD(5,GPT,d03ca3cf-1511-d94e-8400-c7a125866442,0x40164000,0x100000)/File(\EFI\ARCHLINUX\grubx64.efi)' // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; /// The remaining bytes in the load option descriptor are a binary data buffer that is passed to the loaded image. /// Example: '57a9...0400' in Boot0001 variable // UINT8 OptionalData[]; } EFI_LOAD_OPTION;


この時点で、ファームウェアはデバイス パス( EFI_DEVICE_PATH_PROTOCOL ) を調べます。ほとんどの場合、コンピューターはストレージ デバイス (ハード ドライブ/SSD/NVMe など) から起動されます。そのため、デバイス パスにはHD(Partition Number, Type, Signature, Start sector, Size in sectors)ノードが含まれます。


  • タイプ- パーティション スキームに使用される形式をキーワードMBR (1) またはGPT (2) で示します。
  • 署名- タイプがMBRの場合は 4 バイトの MBR 署名、タイプがGPTの場合は 16 バイトのUUID


: 他のパスを変換する方法に興味がある場合は、 UEFI 仕様 v2.10、10.6.1.6 テキスト デバイス ノード リファレンスを参照してください。


UEFI はディスクを調べて、ノードに一致するパーティションがあるかどうかを確認します。存在する場合は、 EFI システム パーティション (ESP)としてマークする特定のグローバル一意識別子 (GUID)でラベル付けされている必要があります。これは、 FAT ファイル システムの特定のバージョンに基づいて仕様が決められ、 EFI ファイル システムと呼ばれるファイル システムでフォーマットされています。実際は、通常のFAT12/16/32です。


  • ネイティブ ブート:デバイス パスにファイルへの明示的なパス File File(\Path\To\The\File.efi)が含まれている場合、UEFI はその特定のファイルを検索します。たとえば、 Boot0000オプションにはFile(\EFI\ARCHLINUX\grubx64.efi)が含まれています。
  • フォールバック ブート:デバイス パスが単にディスクを指している場合、ファームウェアはアーキテクチャに基づいたフォールバック ブート パス( \EFI\BOOT\BOOT{arch}.EFI ( amd64の場合はBOOTx64.EFIi386 / IA32の場合はBOOTia32.EFI )) を使用します。このメカニズムにより、ブート可能なリムーバブル メディア(USB ドライブなど) を UEFI で動作させることができます。フォールバック ブート パスのみが使用されます。たとえば、 Boot0002オプションはこのメカニズムを使用します。


注:上記のすべてのBoot####オプションは、 efibootmgrの出力例に表示されるブート オプションを指します。


どちらの場合も、 UEFI ブート マネージャーはUEFI アプリケーション( OS ブートローダー、UEFI シェル、ユーティリティ ソフトウェア、システム セットアップなど) をメモリにロードします。この時点で、制御はUEFI アプリケーションのエントリ ポイントに転送されます。BIOS とは異なりUEFI アプリケーションはファームウェアに制御を返すことができます (アプリケーションがシステムの制御を引き継ぐ場合を除く)。このような状況が発生した場合、または何か問題が発生した場合、ブート マネージャーは次のBoot####エントリに移動し、まったく同じプロセスに従います。


仕様では、ブート マネージャーがデータベース変数を自動的に維持できることが述べられています。これには、参照されていない、または解析できないロード オプション変数の削除が含まれます。さらに、順序付きリストを書き換えて、対応するロード オプション変数のないロード オプションを削除することもできます。


上記のテキストはUEFI ブートについて説明しています。また、UEFI ファームウェアは、BIOS をエミュレートする互換性サポート モジュール (CSM)モードで実行できます。

OS ブートローダー

ファームウェア (通常は第 2 ステージ ブートローダ) によって起動され、そのインターフェイスを使用してOS カーネルをロードするソフトウェア。OS と同じくらい複雑で、次のような機能を提供します。


  • さまざまなファイルシステム(HFS+、ext4、XFSなど)からの読み取り
  • ネットワーク経由のやり取り(例:TFTP、HTTP)
  • マルチブート対応カーネルの起動
  • チェーンローディング
  • 初期 RAM ディスクのロード ( initrd )
  • さらにもっと!


これらのプログラムの一般的な設計については、この記事の範囲外です。一般的な OS ブートローダーの詳細な比較については、 ArchLinux wikiWikipedia の記事を参照してください。


Windows システムは、Windows ブート マネージャー (BOOTMGR)と呼ばれる独自の OS ブートローダーを使用します。


ファームウェアはもはや小さくて複雑なコードではありません。膨大な量の複雑なコードになり、現在のトレンドはこれに拍車をかけています。ファームウェア上でDoomTwitterなど、多くの興味深いアプリケーションを実行できます。


全体的なアーキテクチャを理解することで、これらのコンポーネントを頭の中で整理しやすくなります。既存のファームウェアの設計を調べることで、コンピューターの電源を入れるたびに展開される魅力的なプロセスについて理解を深めることができます。このトップダウンの視点は、各部分の役割を明確にするだけでなく、最新のファームウェア システムの高度で進化する性質も強調します。

リソース