paint-brush
ファームウェアの隠された世界: コンピューターの起動プロセスを探る@tristejoursoir
3,131 測定値
3,131 測定値

ファームウェアの隠された世界: コンピューターの起動プロセスを探る

Aleksandr Goncharov15m2023/04/21
Read on Terminal Reader

長すぎる; 読むには

この記事では、さまざまな段階、関連する主要コンポーネント、プロセス中に直面する課題など、ブート プロセスの概要を説明します。主に **x86 アーキテクチャ** (最も広く使用されている) に焦点を当てますが、他のアーキテクチャのブート プロセスには多くの類似点があります。
featured image - ファームウェアの隠された世界: コンピューターの起動プロセスを探る
Aleksandr Goncharov HackerNoon profile picture


多くの人が、コンピュータがどのように起動するかに興味を持っています。ここから魔法が始まり、デバイスがオンになっている限り続きます。この記事では、さまざまな段階、関連する主要コンポーネント、プロセス中に直面する課題など、 ブートプロセスの概要を説明します。


主にx86 アーキテクチャ(最も広く使用されている) に焦点を当てますが、他のアーキテクチャのブート プロセスには多くの類似点があります。この記事が、この分野の知識を深めようとしている人にとって貴重なリソースになることを願っています。どうぞ!

目次:

  • ブートロム
    • 不揮発性メモリ
      • ワンタイムプログラマブル
      • フィールドプログラマブル
    • その場で実行 (XIP)
      • Cache-As-Ram (CAR)
    • レイアウトとメモリ マッピング
      • 非記述子モード
      • Intel フラッシュ ディスクリプタ / ディスクリプタ モード
      • インテル ファームウェア インターフェイス テーブル (FIT)
      • AMD 組み込みファームウェアの構造
  • シリコンの初期化
    • インテル ファームウェア サポート パッケージ (FSP)
    • AMD Generic Encapsulated Software Architecture (AGESA)
  • 自律サブシステム
    • インテル ME
    • AMD PSP
  • ハードウェアの電源シーケンス

ブートロム

マザーボード上にあり、コンピューターの起動を担うファームウェア コードを格納する集積回路(チップ) は、 BOOT ROMと呼ばれます。この名前は標準化されていないため、他の開発者はしばしばFLASH ROMBIOS FLASHBOOT FLASHSPI FLASHなどと呼んでいます (このような名前は、テクノロジ、インターフェイス、および目的の名前から付けられています)。心配する必要はありません。これらの用語は交換可能です。コンピュータの電源を入れると、最初にBOOT ROMのファームウェア コードが実行されます。基本的なテストを実行し、ハードウェアを初期化してから、OS ローダーをハード ドライブや USB ドライブなどの起動可能なデバイスからメモリにロードします。このチップは、不揮発性メモリ (NVM)から作られています。

不揮発性メモリ

不揮発性メモリは、電源を切っても内容が保持されるコンピュータ メモリの一種です。このタイプのメモリは、コンピュータの電源がオフになっていても保持する必要がある重要なデータを保存するのに理想的です。さらに、説明はファームウェアコードを保持するメモリにのみ焦点を当てます。ハードディスク ドライブ (HDD)、ソリッド ステート ドライブ (SSD)、フロッピー ディスクなどのストレージについては説明しません。


基本的に、このタイプのメモリは次のグループに分類できます。

ワンタイムプログラマブル

  • マスクROM:製造時に内容が確定し、その後変更することはできません。
  • プログラマブル ROM (PROM): マスク ROM とは異なり、このタイプのメモリは製造後にプログラムできます。でもまだ一度だけ。

フィールドプログラマブル

  • Erasable Programmable ROM (EPROM): 複数回プログラムできますが、その内容は紫外線を使用して消去および再プログラムできます。


  • 電気的消去可能プログラマブル (EEPROM):電気信号を使用して複数回再プログラムできます。


    • NOR フラッシュ メモリ: データがブロック レベルで消去され、バイト レベルで読み取りまたは書き込みが可能なブロックにアーキテクチャ的に配置されます。 NOR メモリは、バイト パラレル、I2C、または SPI などの標準インターフェイスを使用して直接アクセスできます。


      業界では、ブロック単位で消去可能なフラッシュメモリと比較して、 EEPROMという用語をバイト単位で消去可能なメモリに限定する慣例があります。


プログラマブル メモリには、書き込み前に消去するという1 つのルールがあります。このようなメモリでは、データがフローティングゲートに電荷として保存されるため、新しいデータの書き込みはより複雑になります(その理由のほとんどは、メモリセルの物理学にあります)。ゲートの電荷量によって、セルが「0」または「1」のどちらを保存するかが決まります。


フラッシュ メモリ チップを消去すると、そこに保存されているデータのすべてのビットが既知の (デフォルト) 状態 (通常は論理 "1") に設定されます。これにより、いわば白紙の状態から始めて、古いデータの残りがまだチップに保存されていなくても、チップに新しいデータをプログラムすることができます。新しいデータがチップに書き込まれると、個々のビットの状態が「1」から「0」に変わり、新しいデータを表します。


最初にチップを消去せずに単に新しいデータをチップに書き込むと、新しいデータが古いデータと結合され、予期しない結果が生じます。たとえば、値「0110 0010」を格納する 8 ビットのメモリを持つフラッシュ メモリ チップを考えてみましょう。最初にチップを消去せずに新しいデータ「1100 1001」をチップに書き込むと、結果としてチップの状態は「0100 0000」になり、これは意図したものではない可能性があります。


主な混乱は、 Read Only Memoryを表すROMという単語に関連しています。 「読み取り専用メモリ」という用語は、永続的でユーザーが変更できないメモリを指すために歴史的に使用されてきました。しかし、技術の進歩に伴い、ROM の定義が変化し、現在では、工場で事前にプログラムされ、エンド ユーザーが簡単に変更できないメモリを指すために使用されることがよくあります。しかし、ユーザーが必要なスキルと特殊な機器 (プログラマーなど) を持っている場合、その人はチップを再プログラムすることができます。 ROM という名前は、定義が変更されたにもかかわらず、メモリの本来の目的への歴史的な参照として残っています。


一部のタイプのリプログラマブル ROM は、書き込み保護を適用することにより、一時的に読み取り専用メモリになる場合があります。


これらは既存のタイプの不揮発性メモリのすべてではありませんが、たまたま耳にする人気のあるタイプのほとんどです。現在、ほとんどのマザーボードでは、これらのチップはNOR フラッシュ テクノロジを使用して作られています。

その場で実行 (XIP)

Execute in Place (XIP) は、最初に揮発性メモリ ( RAMなど) にコードをコピーすることなく、プロセッサがフラッシュ メモリからコードを直接実行できるようにする方法です。これは、フラッシュメモリをプロセッサのアドレス空間にマッピングすることで実現され、フラッシュから直接コードを実行できるようになります。そのため、システムは、RAM が最初に初期化されるのを待たずに、できるだけ早くコードの実行を開始できます。


待って... CPU は SPI/Parallel/etc プロトコル経由で BOOT ROM と通信できますか?もちろんそうではありません。システム メモリから命令をフェッチするだけです。このメモリ領域への要求は、Intel Direct Media Interface (DMI )または AMD Infinity Fabric (IF) / Unified Media Interface (UMI) (前身) にリダイレクトされます。これは、マザーボード上の CPU とチップセットの間のリンクです。この時点で、アドレスのデコードがチップセット内のデコーダーを介して実行され、チップからのデータがプロセッサーに返されます。


チップが NOR フラッシュ メモリから作られている場合、ランダム アクセス読み取りはサポートされますが、ランダム アクセス書き込みはサポートされません。書き込み可能なメモリが利用できない限り、すべての計算はプロセッサ レジスタ内で実行する必要があります。この時点では、コードはアセンブリ言語でしか記述できず、高級言語 (通常はC 言語) の環境をセットアップする傾向があります。その理由は、メモリの初期化が非常に複雑になり、純粋にアセンブリで記述することが困難になるためです。そのような言語には少なくともヒープとスタックが必要なので、書き込み可能なメモリが必要です。一部のプロセッサにはチップ自体に SRAM が組み込まれていますが、より最新のアプローチは、オンボードのキャッシュ メモリを RAM (CAR) として使用することです。


Cache-As-Ram (CAR)

CPU キャッシュは、頻繁に使用されるデータとメイン メモリからの命令のコピーを格納する高速メモリです。キャッシュはプロセッサの近くに配置され、複数のレベル (L1、L2、L3、...) に編成され、各レベルは前のレベルより大きく、低速です。


データがキャッシュにある場合、CPU は要求されたデータをキャッシュから取得できます (キャッシュ ヒットと呼ばれます)。 CPU キャッシュが必要なデータを見つけられない場合、キャッシュ ミスが発生します。これは、データがキャッシュに保存されていないか、データが以前に保存されていたがキャッシュから削除されたために発生する可能性があります。いずれにせよ、プロセッサはデータにアクセスしてキャッシュにコピーするために、メイン メモリまでずっと移動する必要があります。


キャッシュの削除は、キャッシュからデータを削除して、新しいデータ用にスペースを解放するプロセスです。データの削除は、キャッシング システム (通常、キャッシュがいっぱいで新しいデータを格納する必要がある場合、またはデータの有効期限ポリシーが期限切れになった場合) または明示的な要求によって開始できます。


ただし、CPUキャッシュを RAM として使用する場合は、キャッシュをNon-Eviction Mode ( No-Fill Modeとも呼ばれる) で動作するように設定する必要があります。この手法により、キャッシュ ミスによるエビクションが回避されます。代わりに、キャッシュは通常の SRAM として扱われ、すべてのアクセス (読み取り/書き込み) はキャッシュにヒットし、メイン メモリにヒットしません。このモードは、ベンダー固有の CPU 命令を使用してアクティブ化できます。

レイアウトとメモリ マッピング

実際には、BOOT ROM には数種類のファームウェアが含まれています。ファームウェアの束が BOOT ROM に格納されると、それらを区別するために何らかの方法で整理する必要があります。それがどのように行われるか見てみましょう。

非記述子モード

本来、チップセットは、ブート ROM の内容全体を直接メモリにマッピングします (4GB から 4GB - 16MB へ)。通常、BOOT ROM が 16 MB 未満の場合、コンテンツは繰り返しマップされます。 CPU とファームウェアは、制限なしにフラッシュに読み書きできます。





非記述子モードは、新しいチップセットではサポートされなくなりました。

Intel フラッシュ ディスクリプタ / ディスクリプタ モード

最終的に、ICH8 で、Intel は BOOT ROM に特別なレイアウトを導入します。フラッシュは次の領域に分割されます。


  • フラッシュ記述子 (FD) - このデータ構造は、 0x10オフセットでデバイスの先頭に配置する必要があります。次の図に示すように、11 のセクションで構成されています。



Descriptor MAP には、他の領域へのポインタとそれぞれのサイズも含まれています。


コンポーネントセクションには、システム内のフラッシュに関する情報 (コンポーネントの数、それぞれの密度、無効な命令など) があります。


マスターのセクションでは、リージョンの読み取り/書き込み権限を定義します。読み取り/書き込みに関する限り、権限は読み取り専用に設定する必要があります。この領域に格納されている情報は、製造プロセス中にのみ書き込むことができます。


  • BIOS - この領域のみがメモリにマップされます。





  • Intel Converged Security and Management Engine (CSME / ME) - さまざまな Intel テクノロジーと ME をサポートするファームウェア。
  • ギガビット イーサネット (GbE) - ギガビット イーサネット コントローラーからのみ直接アクセスできます。
  • プラットフォーム データ
  • 組み込みコントローラー (EC)


必要なリージョンは、 Flash DescriptorIntel MEだけです。

インテル ファームウェア インターフェイス テーブル (FIT)

FIT はBIOS 領域内のデータ構造であり、プラットフォーム構成を記述するさまざまなエントリが含まれています。テーブルの各エントリのサイズは 16 バイトです。 1 つはFIT ヘッダーと呼ばれ、もう 1 つはFIT エントリと呼ばれます。これは、物理アドレス0xFFFFFFC0 (4GB - 0x40) のFIT ポインターによって配置されます。


これらのコンポーネントは、リセット ベクターからの最初の CPU 命令を実行する前に処理する必要があります。エントリには、CPU マイクロコードの更新、スタートアップ ACM、プラットフォーム ブート/TPM/BIOS/TXT ポリシーなどがあります。ただし、少なくとも FIT にはFIT ヘッダーマイクロコード アップデートエントリが含まれている必要があります。したがって、FIT の一般的な使用法は、リセット ベクターを実行する前にマイクロコードを更新することです。


メモリ マップは次のようになります。






AMD 組み込みファームウェアの構造

残念ながら、情報ははるかに少なく、レイアウトに関する詳細が記載されたリークされた AMD チップセットのドキュメントは見つかりませんでした。したがって、コアブートのドキュメントにある以上のことは言えません。これは、NDA の下でのみ入手可能なAMD のドキュメントに基づいて作成されています。


実際には、Flash Descriptor の AMD アナログがEmbedded Firmware Structureであり、 PSP ディレクトリ テーブルBIOS ディレクトリ テーブル、およびその他のファームウェアへのポインタが含まれていることを知っていれば十分です。


シリコンの初期化

最新のメモリと CPU がどのように正確に初期化されるかを確認したい場合は、動揺させなければなりません。 Intel と AMD は、コミュニティへのシリコン初期化コードのリリースを急いでいません。そのような情報が公開されていない限り、必要なシリコン初期化コードのバイナリ配布を提供しています。これは、ファームウェア開発者向けのライブラリと見なされ、メモリ コントローラー、チップセット、CPU、およびシステムの他のさまざまな部分を初期化するためのバイナリ コードが含まれています。

インテル ファームウェア サポート パッケージ (FSP)

そのバイナリは、次の 4 つのコンポーネントに分割できます。


  • FSP-T: C コードを実行できる初期実行環境 (「一時 RAM」) をセットアップします。実際には、このバイナリは CAR を設定しますが、PCIe メモリにマップされた構成空間の設定など、初期のハードウェア初期化も行います。
  • FSP-M: 永続メモリ (DRAM など) を初期化しています。
  • FSP-S: CPU および IO コントローラーの初期化を含むシリコンの初期化を完了します。
  • FSP-O: OEM デバイスの初期化を提供するオプションのコンポーネント。


Intel によって投稿されたIntel FSP バイナリのリポジトリは、GitHub にあります。 FSP 仕様 v2.1 は、インテルの Web サイトから入手できます。

AMD Generic Encapsulated Software Architecture (AGESA)

ファミリ 17h より前の製品の AGESA はv5またはArch2008と呼ばれます。当時、AGESA はオープンソースであり、コードはcoreboot リポジトリで利用可能でした (リリース 4.18 以降は廃止されました)。 Arch2008 の仕様は、 AMD の Web サイトで見つけることができます。


ファミリ 17h (Zen マイクロアーキテクチャ) 製品の導入により、AMD は AGESA ソース コードを公開せず、ビルド済みのバイナリ ソリューションのみを公開しました。このような後継はAGESA v9と呼ばれ、ファミリ 17h 以降をサポートします。

openSIL

詳細な情報はなく、ニュースのみです。

自律サブシステム

最新の x86 ブート プロセスの不可欠な部分であり、これがなければ x86 コアがアクティブ化されることはありません。したがって、それらを完全に無効にすることは不可能です。これらのテクノロジは、ハードウェアの初期化、システムの整合性の検証、電源管理、および CPU の起動を担当します。これらのサブシステムのファームウェアは、メイン プロセッサが独自のファームウェアの実行を開始する前にロードされ、実行されます。このようなシステムのコードは、プラットフォームの CPU コアから独立して実行されます。


多くのハードウェア企業があいまいさによるセキュリティの原則を組み込んでいる限り、これらのサブシステムのソース コードもドキュメントも入手できません。幸いなことに、それが起動プロセスにどのように影響するかはわかっています。ハードウェアの電源シーケンスを参照してください。


詳細については説明しません。インターネット上には、世界中の研究者による広範な記事が既に存在するためです。しかし、それが何であるかを簡単に説明します。

インテル マネジメント エンジン (ME)

Intel ME は、2008 年以降、Intel チップセット (PCH) に統合された個別のi486/80486マイクロプロセッサです。独自の RAM、内蔵 ROM、チップセット内のすべてのバスへのバス ブリッジを備えています (その結果、ネットワークにアクセスできます)。 CPU のメイン RAM など) などです。 MINIX ベースのカスタム OS を実行します。

AMD プラットフォーム セキュリティ プロセッサ (PSP)

AMD PSP は、コプロセッサとして CPU ダイに挿入される Trustzone 拡張に依存するARMコアです。このチップは、2013 年以降、ほとんどの AMD プラットフォームに統合されています。文書化されていない独自の OS を実行します。

ハードウェアの電源シーケンス

このプロセスは、パワーオン シーケンスまたはパワー シーケンシングとも呼ばれ、プラットフォームで必要な特定の順序で、多数の派生電圧レベルや電源レールを提供します。簡単に言えば、特定の順序で多数のプラットフォーム コンポーネントを起動します。プロセスはシステムまたはプラットフォームの設計によって異なりますが、通常、標準の PC には次の手順が含まれます。


  • 電源ボタンを押します。しかし、待ってください...このボタンは、コンピューターの必要な部分ではないコンピューターのケースにあります。通常、電源ボタンはケーブルです。片側にボタンがあり、反対側のマザーボードの 2 つの金属製突起スイッチがあります。ボタンを押すと、これらのプロングが接続され、電気が通過できるようになります。興味のある方は、電源ボタンのないコンピューターの電源を入れる方法について、以下のビデオをご覧ください。


  • マザーボードは電源ユニット (PSU) に信号を送信します。


  • 電源は信号を受信し、適切な量の電力を供給し、信号をマザーボードに送り返します。
  • マザーボードがパワー グッド信号を受信すると、コア、クロック、チップセット、メモリ、さまざまなコントローラなどのプラットフォーム コンポーネントに電力を供給します。
  • 自律型サブシステム (前述) を含むさまざまなサブシステムが、メイン プロセッサの前に開始される場合があります。


  • AMD ベースのシステム (ファミリ 17h 以降)


    • PSP はオンチップ BOOT ROM で実行されます。

    • PSP は、オフチップ BOOT ROM 内の組み込みファームウェア テーブルを見つけ、PSP ファームウェアを実行します。

    • PSP はPSP ディレクトリ テーブルを解析して ABL ステージを見つけ、実行します。

    • ABL ステージは、メイン メモリを初期化し、BOOT ROM で BIOS イメージを見つけて、DRAM にロードします (イメージが圧縮されている場合は解凍します)。


      このプラットフォームでは、DRAM が既に利用可能であり、PSP がファームウェア イメージをそこにロードするため、CAR を使用する理由はありません。


  • Intel ベースのシステム
    • チップセット (ICH/PCH) は、BOOT ROM でIntel Flash Descriptorを見つけます。
    • チップセットは、Intel ME がアクセスできる内部メモリに CSME ファームウェアをコピーし、最後のファームウェアが実行を開始します。
    • チップセットは、 BIOS 領域をメモリにマップします。
    • ファームウェア インターフェイス テーブルにあるマイクロコードの更新は、CPU にロードされます。これらは、システムの起動ごとに適用する必要があります。
    • (オプション) 認証済みコード モジュール (ACM) が見つかった場合、そのエントリが実行されます。


  • この間ずっと、システムの他の部分の準備が整う前に CPU が起動するのを防ぐために、 CPU リセット信号がアサートされます。プラットフォームの準備が整うと、 CPU リセット ラインがアサート解除されます。マルチプロセッサまたはマルチコア システムでは、すべてのファームウェア初期化コードを実行するブートストラップ プロセッサ (BSP)として 1 つの CPU が動的に選択されます。この時点でアプリケーション プロセッサ (AP)と呼ばれる残りのプロセッサは、後でファームウェア/カーネルによって明示的にアクティブ化されるまで停止したままになります。


  • CPU は、最初に電源を入れた後、リアル モードで動作します。ほとんどのレジスターには、命令ポインター (IP)、コード・セグメント (CS)、およびセグメント・メモリーへの高速アクセスを可能にするプロセッサー内の各セグメント記述子コピーである記述子キャッシュなど明確に定義された値があります。


    セグメント記述子は、グローバル記述子テーブル (GDT)のエントリであり、ベース アドレス、セグメント制限、およびアクセス情報が含まれています (リアル モードには保護モードのようなアクセス制御がないため、この部分は無視されます)。メモリ アクセスごとに GDT (メモリ内にある) にアクセスする代わりに、情報はディスクリプタ キャッシュに格納されます。


    ただし、GDT はリアル モードには関与しないため、プロセッサは内部的にエントリを生成します。セグメント記述子へのアクセスに使用される CS セレクタ レジスタには、 0xF000がロードされます。 CS ベースアドレスは0xFFFF_0000に初期化されます。 IP は0xFFF0に初期化されます。


    したがって、プロセッサは物理アドレス0xFFFF_FFF0 ( 0xFFFF_0000 + 0x0000_FFF0 ) にあるメモリから命令のフェッチを開始します。そのアドレスで実行される最初の命令は、リセット ベクタと呼ばれます。


    注: このトリックにより上位アドレス空間にアクセスできますが、 0xFFFF_0000アドレスより下のコードにはアクセスできません。 CS セレクタ レジスタがファームウェアによってロードされるまで、CS ベース アドレスはこの初期値のままです。 far jumpを実行することで実行できます。


    この時点で、最善の決定は、4 GB のアドレス可能度を持つ保護モードに切り替えることです。ファームウェアがそれを行わない場合、リアル モードが機能するには、チップセットが 1 MB 未満のメモリ範囲を 4 GB のすぐ下の同等の範囲にエイリアスできる必要があります。特定のチップセットにはこのエイリアシングがなく、最初のロング ジャンプが実行される前に別の動作モードへの切り替えが必要になる場合があります。


  • アドレスは不揮発性メモリのセクションにあるため、CPU は Execute In Place (XIP) メソッドを使用します。ただし、AMD ベースのシステムの場合は、おそらくメイン メモリから読み込んでいます。


  • CPU はファームウェア コードを実行します。


以下の電源投入シーケンスに関するビデオを見ることをお勧めします。このビデオでは、例として ASUS P9X79 マザーボードを使用してプロセスを説明しています。ロシア語ですが、自動生成された英語の字幕をオンにすれば、すべてを理解できます。




この記事では、ブートの仕組みに関する多くの理論的な情報を提供しました。ただし、このプロセスを真に理解するには、既存のファームウェアのソース コードとアーキテクチャを詳しく調べる必要があります。


次の記事では、 BIOSUEFI、およびコアブートをさらに掘り下げて詳しく調べます。

資力