BIOSとUEFIはどこが違うのか?
現代のマシンがUEFIを使っているのに「BIOSに入る」と言い続けるのはなぜか。BIOS・UEFI・ブートフロー・Secure Boot・Boot####とOSが動く前にfirmwareがシステムを構築する仕組みを解説。
PCを自作したことがある人、Windowsをインストールしたことがある人、Linuxをデュアルブートしようとしたことがある人、あるいは単にハードドライブを認識しないマシンをネットで検索したことがある人なら、きっとこんなアドバイスを見たことがあるはずです。
「BIOSに入って設定を変えてみて。」
シンプルに聞こえます。でも、すべての問題が「BIOSに入れ」で解決されるBIOSとは何なのでしょうか。ブート順を変えるのもBIOS。TPMを有効にするのもBIOS。Secure Bootを切り替えるのもBIOS。RAMのXMPを有効にするのも、ファン曲線を調整するのも、SATAモードを変えるのも、USBブートを無効にするのもBIOS。
2000年代以前のコンピュータを使ったことがある人は覚えているでしょう。電源を入れた直後にDelかF2を押すと、白いテキストが並んだ青や灰色の画面が出てくる。矢印キーで移動、Enterで選択、+と-で値を変える。マウスなし、グラフィックなし、アニメーションなし。それがLegacy BIOS Setupでした。
でも現代のマシンをよく見ると、奇妙なことに気づきます。多くの場合、内部では従来の意味のBIOSはもう使われていません。内部はUEFIです。それなのに、技術者も、Windowsユーザーも、PCビルダーも、多くのエンジニアでさえ、いまだに「BIOS」と呼び続けています。
ではBIOSとは何か?UEFIとは何か?現代のマシンがUEFIを使っているのに、なぜ「BIOSに入る」と言い続けるのか?そして両者はどこが本当に違うのか――見た目の新旧以外の部分で?
これを明確にするために、私が最もなじみのある視点から始めたいと思います。組み込みfirmwareです。
組み込み開発からPC firmwareに移った当初、BIOSとUEFIはUIが違うだけだと思っていました。BIOSは青いテキスト画面。UEFIはマウス対応でカラフル。
しかしブートログを読み、ドライバーのソースコードを読み、「マシンはSSDを認識しているのにブートメニューに出てこない」というバグをデバッグするうちに、自分が間違った場所を見ていたことに気づきました。
本当の違いはUIにはありません。
firmwareがほぼ何もない状態からどのようにPCを構築するかという、その組織の仕方にあります。RAMはまだ初期化されていない、チップセットは設定されていない、PCIeはenumerateされていない、ストレージは見えない、OSも助けに来てくれない——そんな状態から。
組み込みfirmwareでは、ある程度形の決まったシステムのためにコードを書くのが普通です。BIOS/UEFIでは、firmwareがその形を先に作り、それからOSに渡す必要があります。
この記事は身近なことから始めます——USBブート、Secure Boot、Windows Boot Manager、ブートメニューに出てこないSSD——そして背後にあるアーキテクチャへと進んでいきます。Boot####、Device Path、Protocol、HII、NVRAMといった概念になじみがなくても大丈夫です。この記事を読み終えると、全体像が見えてきます。
PC firmwareと一般的な組み込みfirmwareはどこが違うか
組み込みの経験がある人なら、このモデルに慣れているでしょう。
電源オン
CPU/MCUがリセットベクターから実行を開始する
リセットハンドラー
.dataをコピー、.bssをゼロクリア、C環境を準備する
mainを実行
GPIO、UART、ペリフェラルを初期化する
メインループ / RTOS
firmwareがメインロジックを実行し始める
システムはすでに存在しています。フラッシュがあります。RAMがあります。あとはコードを書いて制御するだけです。
PC firmware——Legacy BIOSであれUEFIであれ——はその条件がありません。CPUがリセットされた瞬間、信頼できるものは何もありません。DRAMは初期化されていない、チップセットは設定されていない、何もenumerateされていない、OSもいません。firmwareはシステムを使う前に、そのシステムを作らなければならないのです。
組み込みfirmwareはすでに存在する工場を運転するオペレーターのようなものです。
PC firmwareはその工場をゼロから建設するエンジニアのようなものです。すべてが正しい順序で動くように構築し、それから引き渡す。
この違いはハードウェアに由来します。マイクロコントローラーは通常、フラッシュ、RAM、ペリフェラルを一つのチップに統合していて、電源を入れればすぐに動き始められます。x86 CPUは違います。外部DRAM、チップセット、PCIe、ストレージコントローラー、そして長いプラットフォームのブリングアップ手順が必要で、そのすべてが揃って初めてOSが動けます。
| 観点 | 組み込みfirmware | BIOS/UEFI |
|---|---|---|
| 起動時の環境 | ハードウェアはある程度安定している | ほぼ空の状態。DRAMは未初期化、チップセットは未設定 |
| 主な仕事 | デバイスを制御する | システム全体を構築し、OSに渡す |
| ライフタイム | デバイスの寿命の間ずっと動く | ブート中に動き、その後OSに制御を移す |
| アーキテクチャ | システムによってメインループ / RTOS | 複数のフェーズ、複数のレイヤー、独自のドライバーモデル |
ブートパスから見る: 二つの異なるアプローチ
Legacy BIOSとUEFIの違いを最も素早く見る方法は、それぞれのブートパスを見ることです。
Legacy BIOSはかなり線形のシーケンスで動きます。
POST
Power-On Self Test、基本的なハードウェアチェック
ブートデバイスを探す
優先順位順にデバイスリストをスキャンする
ブートセクターを読む
デバイスの先頭512バイトを読む。ファーストステージブートコードがここから始まる
ブートローダーを実行
MBR内のファーストステージブートローダーが次のステージをロードする
OSへ
カーネルに制御が移る
UEFIはブートを明確なフェーズに分けます。各フェーズには独自の責任があり、次のフェーズの基盤を作ります。
Security Phase
CPUリセット、テンポラリメモリ、最初期の環境構築。一部のプラットフォームではここで初期検証を行う
Pre-EFI Init
DRAMを初期化し、HOBリストを構築し、DXEにデータを渡す
Driver Execution
ドライバーをロードし、protocolをpublishし、すべてのデバイスをenumerateする
Boot Device Select
Boot####を読み取り、Device Pathを解決し、OSローダーをロードする
ExitBootServices
OSローダーがメモリマップを取得し、EBSを呼び出し、カーネルに制御を渡す
違いはステップが増えただけではありません。UEFIの各フェーズで、利用可能なリソースは本質的に異なります。
SECにはDRAMがないため、ヒープを通常通り使えません。PEIがDRAMを立ち上げてHOBを通じて情報をDXEに渡します。DXEになって初めて完全なドライバーモデルが利用可能になります。BDSはDXEがすでに構築したprotocolとブートvariableを使ってOSローダーを選択・ロードします。
フェーズ構造は複雑さを加えるためにあるのではありません。ほぼ何もない状態から大規模なプラットフォームを構築するには、この組織化が不可欠なのです。
Legacy BIOS: 役割は果たしたが、スケールできなかった
Legacy BIOSは何十年もうまく機能しました。その時代に必要だったことを正確にこなしていました。基本的なハードウェアの初期化、POSTの実行、ブートデバイスの検索、MBRの読み取り、ブートローダーへのジャンプ。
しかし、その設計は現代のPCが必要とする形でスケールするようには作られていませんでした。
- 標準的なドライバーモデルがない。各ベンダーが独自の方法で書いていて、再利用が困難
- MBRパーティションスキームはディスクを2TB以下、最大4つのプライマリーパーティションに制限
- ブートセクターはわずか512バイト
- ブートセキュリティはほぼなし。MBR内のどんなコードでも実行される
- コードは通常モノリシックで、コンポーネント間に標準インターフェースがない
- ネットワークブート、新しいストレージ、ファームウェアアップデート、セキュリティポリシーへの拡張が困難
NVMeコントローラーの何百ものバリアントをサポートしながら、ネットワークブート、RAID、Secure Boot、ファームウェアカプセルアップデートを追加しようとすると、問題が見えてきます。Legacy BIOSにはそのような拡張を行うクリーンなメカニズムがありませんでした。
UEFI: アーキテクチャであり、機能セットではない
UEFI (Unified Extensible Firmware Interface)はLegacy BIOSに機能を追加したものではありません。適切なドライバーモデルを持つfirmwareプラットフォームとして最初から設計し直されました。
核心的な違い: UEFIでは、firmwareモジュールはGUIDで識別されるprotocolを通じてお互いに通信します。
例えば、ストレージドライバーはハンドルにBlock I/O Protocolをpublishできます。
gBS->InstallProtocolInterface(
&Handle,
&gEfiBlockIoProtocolGuid,
EFI_NATIVE_INTERFACE,
&BlockIoProtocol
);
ファイルシステムドライバーやBDSはそのprotocolを検索して使用できます。
gBS->LocateProtocol(
&gEfiBlockIoProtocolGuid,
NULL,
(VOID **)&BlockIo
);
ストレージドライバーはファイルシステムドライバーがどう使うかを知る必要がありません。ファイルシステムドライバーはストレージがSSD、NVMe、SATA、USBのどれかを知る必要がありません。BDSはどのコントローラーが使われているかを知る必要がありません。publishされたprotocolを通じてアクセスするだけです。
これがUEFIを本当の意味でモジュラーにするものです。各レイヤーはそのインターフェースだけを知っていれば良い。
「BIOS Setup」画面とは実際に何なのか?
最初の日常的な疑問に戻りましょう。ブート順を変えたり、TPMを有効にしたり、Secure Bootを切り替えたり、SATAモードを変えたり、XMPを有効にするために「BIOSに入る」とき、実際にどこに入っているのでしょうか?
古いマシンであれば、本当のLegacy BIOS Setupかもしれません。しかしほとんどの現代のハードウェアでは、UEFI Setupです。人々は習慣で「BIOS」と言い続けていますが、内部のアーキテクチャはまったく異なります。
UEFIでは、現代のSetup画面は通常HII (Human Interface Infrastructure)と呼ばれるアーキテクチャの上に構築されています。
Legacy BIOS Setupが画面に直接描画するモノリシックなCコードだとすれば、UEFI HIIはデータ、インターフェース、ストレージを明確に分離した構造化されたパイプラインです。
フォームソース
フォーム、クエスチョン、表示条件を記述する
文字列パッケージ
多言語表示文字列
HII Database
DXEドライバーがフォームパッケージをデータベースにinstallする
Setup Browser
IFRを読み取り、UIをレンダリングし、入力を処理する
バッキングストレージ
各クエスチョンの値の一時データまたはバッファ
永続ストレージ
UEFI variable pathを通じて値が保存される
HIIの優れた点: 各DXEドライバーはBrowserのコードを変更せずに独自のフォームをSetupに追加できます。BrowserはHII Databaseを読み取ってレンダリングするだけで、何個のドライバーがフォームを提供しているかを知る必要がありません。
これが現代のサーバーのSetupメニューが何百ものオプションを多くのタブやサブメニューにわたって整理できる理由であり、それでもコードベースは明確な構造を持っています。
Setupオプションから NVRAMへ
Setupに入って「SATAモードをRAIDに変える」などのオプションを変更したとき、それは単にUIの更新ではありません。
内部では、そのオプションは通常VarStore内のフィールドにマップされています。ユーザーが保存すると、firmwareは新しい値をNVRAMまたは同等のストレージに書き込まなければなりません。次のブート時に、PEIまたはDXEドライバーがその設定を読み戻してコントローラーを設定します。
オプションを変更
例: SATAモードをRAIDに切り替える
一時的に保持
Setup Browserがブラウザーストレージを更新。すぐにNVRAMには書かない場合がある
検証 / 通知
ドライバーがConfig Accessを登録していればコールバックを処理できる
Save & Exit
BrowserがFormSetを所有するドライバーのRouteConfig()を呼ぶ
SetVariable()
ドライバーが設定をvariable storeに書き込む
PEI/DXEが読み戻す
Consumerが設定を読み取りハードウェアを設定する
見落としやすいステップ: 多くの実装では、Setup Browserはユーザーがオプションを変更した瞬間にNVRAMを書き込みません。Save & Exitのときに初めてRouteConfig()が呼ばれ、Config Accessドライバーが実際のvariable storeに書き込みます。
SetVariable()がエラーを返した場合(例えばフラッシュ保護がすでに有効でEFI_WRITE_PROTECTEDが返る場合)、UIは新しい値を表示しますが、NVRAMには古い値のままです。リセット後、すべてが元に戻ります。
実際の成果物での違い
Legacy BIOSとUEFIのアーキテクチャの違いは、実際に作業する際に遭遇するものに明確に現れます。
| 成果物 | Legacy BIOS | UEFI |
|---|---|---|
| ブートターゲット | MBRブートセクター、512バイト | ESP上の.efiファイル (EFI System Partition) |
| ブートメタデータ | firmwareセットアップ/旧式NVRAMの単純な優先リスト | NVRAMのBoot#### variable、BootOrder、BootNext。UEFI APIで読み書き可能 |
| パーティションスキーム | MBR、最大4プライマリーパーティション、2TB制限 | GPT、MBRの実用的な制限をはるかに超える。ほとんどのシステムがデフォルトで128パーティションエントリに対応 |
| ドライバー/拡張モデル | Option ROM、ベンダー固有、非標準 | Protocol + Driver Binding、標準化、拡張しやすい |
| Setup UI | モノリシックなSetup、クラシックなテキストインターフェース | HII、VFR/IFR、String Package、FormSet、VarStore、Config Access |
| 設定の永続化 | CMOS/NVRAM、プラットフォーム固有 | UEFI variable store、SetVariable/GetVariable、実装によってポリシーとSMMパス |
| ブートセキュリティ | 非常に限定的 | Secure Boot、db/dbx/PK/KEK、Measured Boot、TPM統合 |
| ブート後のランタイム | 割り込みベースのBIOSサービス、非常に限定的 | GetVariable、SetVariable、GetTimeなどのRuntime ServicesはExitBootServices後も利用可能 |
Windows、Linux、macOSとUEFIの関係
これはspecの中だけの話ではありません。毎日使うOSに直接現れます。
WindowsはUEFIをWindows Boot Manager、Secure Boot、TPM、Boot####/BootOrder、ESPパーティションとして露出させます。ブートメニューに「Windows Boot Manager」が表示されるとき、firmwareセットアップでSecure Bootを切り替えるとき、ディスクをクローンした後にWindowsが起動しないとき——これはWindowsではなくUEFIの成果物をデバッグしています。
LinuxはUEFIをGRUB、systemd-boot、shim、efibootmgr、ESP、EFIブートスタブとして露出させます。デュアルブートでGRUBが消えるとき、Secure Bootがカーネルやモジュールをブロックするとき、efibootmgrがBoot####を書けないとき——問題はLinuxとUEFI firmwareの境界にあります。
macOSは明確に区別が必要です。Intel MacはEFIの世界に近いブートプロセスを持ちますが、Apple SiliconはApple独自のBoot ROMとセキュリティポリシーを持つ独自のブートチェーンを使います。標準的なPC UEFIとして説明すべきではありません。しかしmacOSも同じ基本原則を示しています: OSが動く前に、常に検証、環境構築、引き渡しを担当するfirmware/セキュリティチェーンが存在します。
UEFIはfirmwareエンジニアだけが扱うものではありません。WindowsユーザーはSecure BootやWindows Boot Managerを扱うときにUEFIと出会います。LinuxユーザーはデュアルブートやESP、efibootmgrでUEFIと出会います。実装は異なりますが、根本的な問題は同じです: OSが実行を許可される前に、firmwareは信頼できるブートパスを確立しなければならない。
クイック比較
| 観点 | Legacy BIOS | UEFI |
|---|---|---|
| アーキテクチャ | モノリシック | フェーズベース、モジュール型 |
| ドライバーモデル | 標準なし | Protocol + Driver Binding |
| ブート | MBRブートセクター | EFIアプリケーション、Boot Manager |
| ディスク | MBRの制限 | GPT、MBRの実用的な制限をはるかに超える |
| Setup UI | クラシックなテキストSetup | HII、VFR/IFR、Setup Browser |
| 設定ストレージ | CMOS/NVRAM、プラットフォーム固有 | UEFI variable、VarStore、NVRAM |
| セキュリティ | 非常に限定的 | Secure Boot、Measured Boot、TPM |
| 拡張性 | 拡張困難 | Protocolによるモジュラーな拡張 |
| ソース構造 | 体系化が難しい | EDK IIのINF/DEC/DSC/FDFで明確に構造化 |
デバッグ時に違いがどう現れるか
これが最も重要だと感じています——アーキテクチャを理解することは、問題へのアプローチを変えることにつながって初めて価値があります。
ケース1: ディスクをクローンした後に起動しない
Legacy BIOSの考え方では、MBRが有効かどうか、パーティションがアクティブかどうかをチェックします。
UEFIの考え方では: 新しいディスクにESPが正しく作成されているか?NVRAMのBoot####のDevice Pathは正しいディスク/パーティションを指しているか?ディスクをクローンまたはリストアすると、GPTパーティションGUIDまたはDevice Pathが変わったり重複したりする可能性があります。古いBoot####は古いDevice Pathを参照し続けているため、ブートオプションがstaleになります。
ケース2: デバイスはシステムにあるがブートメニューに出てこない
Legacy BIOSの考え方では、ディスクがブートデバイスかどうかをチェックします。
UEFIの考え方では、チェーンをたどります: バスドライバーはデバイスをenumerateして子ハンドルを作成したか?Block I/O Protocolはpublishされたか?パーティションドライバーはバインドしてパーティションハンドルを作成したか?ファイルシステムドライバーはSimple File System Protocolをinstallしたか?BDSはSFSPを持つハンドルを見つけたか?
チェーンが切れた場所を見つけてそこを修正します。
ケース3: BIOSで保存した設定がリブート後に消える
Legacy BIOSの考え方では、CMOSバッテリーやCMOSクリアを疑います。
UEFIの考え方では、NVRAMのvariable storeとHIIの保存フローを考えます: RouteConfig()は実行されたか?SetVariable()はエラーを返さなかったか?variableのattributeは正しいか?variable storeはいっぱいか?platformポリシーが書き込みをブロックしていないか?SMM variable pathは正しく動いているか?consumerは正しいGUID、名前、オフセットを読んでいるか?
ケース4: 小さなオプションを追加しただけでハードドライブが見えなくなった
これはfirmware特有のケースです。UIは通常通りオプションを表示し、ビルドにエラーはなく、フラッシュは成功し、マシンはまだSetupに入れます。しかしリブート後、ストレージの動作がおかしい。
この場合、UIだけを見るのは不十分です。structレイアウト、VarStoreオフセット、古いNVRAMデータ、デフォルトパス、その設定を実際に読んでいるモジュールを確認する必要があります。SETUP_DATA内の1バイトのズレで、全く別のフィールドがSATAモード、TPMフラグ、ブートポリシーとして誤読される可能性があります。
最初の3つのケースはブートパスでUEFIがLegacy BIOSとどう違うかを示します。4つ目のケースは、UEFIの世界での「BIOS設定を変える」という行為が実際にはかなり長いパイプラインを通ることを示しています: UI → HII → VarStore → コールバック → NVRAM → consumer。
組み込みエンジニアはなぜ知っておくべきか
STM32や単純なMCUだけを扱うなら、UEFIは直接関係ないかもしれません。しかしPOS端末、キオスク、決済デバイス、産業用PC、シンクライアント、ミニPC、またはx86プラットフォーム上で動作するシステムのfirmwareを書くなら、これは日常の実務知識です。
純粋な組み込みの仕事でも、UEFIがfirmwareをどう整理するかを理解することは、次の点でより良い思考の助けになります。
- ブートローダーのステージング: 早期initとメインfirmwareの分離。SEC/PEI境界に似ている
- メモリ初期化シーケンス: フルスタックを持つ前に何ができて何ができないか
- ドライバーの初期化順序: ドライバー間の依存関係。UEFIのDEPEXに似ている
- インターフェースファーストの設計: Direct callではなくprotocolに対してコーディングし、実装を差し替えやすくする
- 設定の永続化: 設定はグローバル変数ではない。ストレージ、バージョニング、マイグレーションが必要
- ステージ間のハンドオフ: HOBパターン、境界を越えて安全にデータを渡す
これらはUEFI固有のパターンではありません。複雑なfirmwareを体系的に整理する方法です。UEFIはその最大かつ最もよくドキュメント化された例の一つです。
よくある誤解
「UEFIはUIがきれいになったBIOSだ」
UIは最も小さな違いです。本当の違いはドライバーモデル、protocolシステム、Boot Manager、HII、NVRAM variable、そしてソースコードの整理です。グラフィカルなUIを持たないUEFI firmwareを書くことも完全に可能で、それでも完全なUEFIです。
「BIOSに入ることはハードウェアを直接設定することだ」
必ずしもそうではありません。現代のUEFIでは、通常はSetup UIの設定を編集しています。その設定はNVRAMや同等のストレージに保存されます。次のブート時に、PEIまたはDXEドライバーがそれを読んでからハードウェアを設定します。UIは見えている部分にすぎません。
「BIOS/UEFIは組み込みと関係ない」
単純なMCUだけなら、確かに直接関係は少ないかもしれません。しかしx86ボードのブリングアップやPCプラットフォーム上で動くデバイスのfirmwareを書くなら、これは実務知識です。
「UEFIを学ぶにはブートフローを学べばいい」
ブートフローは出発点です。しかし実際のUEFIの作業には、Protocol、Handle Database、GUID、Driver Model、Boot Services、Runtime Services、HII/Setup、NVRAM variable、Device Path、SMMの理解が追加で必要です。各レイヤーに独自のデバッグアプローチがあります。
デバッグの視点から学ぶ
多くのUEFIリソースはspecと定義から始めます。それは正しいですが遅い——特にブートしないマシンを前にして何が起きているかを理解しようとしているときは。
より効果的だと感じるのは、実際のデバッグ質問から始めることです。
- 「なぜこのデバイスはシステムにあるのにブートメニューに出てこないのか?」
- 「なぜこの設定は保存されてもリブート後に消えるのか?」
- 「なぜ新しいfirmwareをフラッシュした後にマシンがリセットループするのか?」
- 「なぜSetupに小さなオプションを一つ追加しただけでストレージの動作が変わったのか?」
各質問が、理解する必要があるレイヤーへと導いてくれます。なぜ壊れるかを理解したとき、どう正しく動くべきかも理解できます。
振り返ると、最も重要だったのはUEFIのフェーズ数を暗記することでも、Legacy BIOSの制限を覚えることでもありませんでした。
思考の転換が重要だったのです。
組み込みでは、すでに存在するシステムのためにfirmwareを書きます。
PC firmwareでは、firmwareこそがそのシステムを作るものです。
そして現代のUEFIでは、誰もが「BIOS」と呼ぶ画面は、その背後にあるはるかに大きなアーキテクチャへの小さな扉にすぎません。
参考資料
- UEFI Specification
- EDK II Project
- EDK II HII Database modules
- Linux kernel EFI stub documentation
- Microsoft Secure Boot overview
次に読む
- UEFIブートフロー: リセットベクターからExitBootServicesまで
- DXEフェーズ: ドライバー、Protocolと何も動かないときのログの読み方
- BIOS Setup、HII、NVRAMの仕組み
- SECとは?
- PEIとは?
- DXEとは?
- BDSとは?
- Protocolとは?
- ハンドルデータベースとは?
この記事は役に立ちましたか?
ファームウェア、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.
BIOS Setupとは: クラシックな青い画面からHIIと現代のNVRAMまで
現代のBIOS SetupはHII上に構築されている: VFR、VarStore、NVRAM。structの途中にフィールドを追加するとなぜシステムが壊れるのか、そして保存されない設定のデバッグ方法。
UEFIブートフロー: リセットベクターからExitBootServicesまで
フェーズ名を暗記するためではなく、マシンがどこで死んでいるかを知りデバッグする方向を掴むためにブートフローを学ぶ。SECからRuntimeまでの実際の障害モードへの地図。
ACPIとは: firmwareがGPIOをトグルして電源を切ってはいけない理由
なぜfirmwareがGPIOをトグルして電源を落としてはいけないのか。ACPIはfirmwareが書きOSが読む契約: テーブル、AML、電力状態、壊れたスリープ/ウェイクのデバッグ。
Đọ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.