ブートシーケンスとファームウェア ─ リセットからOSハンドオフまで
電源投入からOSが起動するまでの数秒間で何が起きているか。リセットベクタ・POST・UEFIのDXE/BDSからSecure BootとMeasured Bootまでを原理で押さえれば、ブート不能や署名エラーの切り分けが効くようになります。
- 1.CPUはリセット解除後、固定のリセットベクタ(x86-64では物理アドレス0xFFFFFFF0)からフェッチを開始する。そこはROM/SPIフラッシュに張られており、まだDRAMもキャッシュも使えないため初期コードはレジスタやキャッシュをRAM代わりに使うCAR(Cache-as-RAM)で動く。
- 2.UEFIはSEC→PEI→DXE→BDS→TSLと段階的に環境を整える。PEIでメモリを初期化し、DXEで多数のドライバを読み込んでサービスを構築し、BDSがブート対象を選んでブートローダ(例 GRUB/Windows Boot Manager)へ制御を渡す。
- 3.Secure Bootは各段の実行前に署名をDB/KEK/PKの鍵階層で検証して未署名コードを止める(信頼の連鎖)。Measured BootはコードのハッシュをTPMのPCRへ拡張(extend)して測定値を残し、後からリモート認証(attestation)で改竄を検出できるようにする。両者は目的が異なる。
電源投入からの数秒で何が起きるか
電源ボタンを押してからOSのログイン画面が出るまで、CPUは「ほぼ何も使えない」状態から一歩ずつ実行環境を組み立てています。DRAMは未初期化、キャッシュコヒーレンシも未設定、デバイスは沈黙したまま。この空白からOSへ制御を渡すまでの連鎖がブートシーケンスであり、各段が次段の正当性を保証していく構造が**信頼の連鎖(chain of trust)**です。原理を押さえると、ブート不能や署名エラーがどの段で起きたのかを切り分けられます。
電源が安定すると、電源管理回路(PCHやPMIC)がリセット信号をアサートし続け、クロックが安定したところでリセットを解除します。CPUコアはこの瞬間に既知の初期状態へ落ち、最初の命令フェッチを始めます。
リセットベクタ ─ 最初の命令はどこから来るか
CPUがリセット解除後に最初にフェッチするアドレスをリセットベクタと呼びます。これはアーキテクチャで固定されています。x86-64では物理アドレス 0xFFFFFFF0(4GB境界の直下16バイト)、ARMでは実装定義のベクタ(多くは 0x0 付近やブートROM)です。重要なのは、ここがDRAMではなくROM/SPIフラッシュに張り付けられている点です。
リセット直後はメモリコントローラが未初期化でDRAMが使えず、スタックも置けません。そこで初期ファームウェアは**Cache-as-RAM(CAR / NEM: No-Eviction Mode)**という技法を使います。CPUのキャッシュを一時的に「追い出しの起きない書き込み可能なRAM」として構成し、DRAMが立ち上がるまでの間スタックや変数領域として使うのです。x86のリセットベクタにあるのは16ビットのリアルモードコードで、ここからプロテクトモード・ロングモードへ昇格しながら環境を広げていきます。
リセットベクタにある最初のコードは、書き換えにくいROM領域に置かれることで信頼の起点(Root of Trust)になります。近年はこの起点をハードウェアで固定するHardware Root of Trust(Intel Boot Guard、AMD PSP、ARM の BL1 など)が前提で、ROM内の不変コードが次に実行するファームウェアの署名を検証してから渡します。
BIOS と UEFI ─ 何が変わったのか
初期化を担うファームウェアには、レガシなBIOSと現代のUEFIがあります。両者は役割は同じでも構造がまったく異なります。
| 観点 | レガシBIOS | UEFI |
|---|---|---|
| 実行モード | 16ビットリアルモードが主体 | 32/64ビットで動作 |
| ブート情報の在処 | MBR(先頭512バイト)のブートコード | GPT上のESP(EFI System Partition)内の.efi実行ファイル |
| 拡張性 | オプションROMの寄せ集め | ドライバ/アプリのモジュール構成(PE/COFF) |
| 署名検証 | 標準では持たない | Secure Bootを標準サポート |
| プリブート環境 | 限定的(INT割り込みサービス) | Boot Services/Runtime Servicesという豊富なAPI |
レガシBIOSはディスク先頭のMBRにある446バイト程度のブートコードを 0x7C00 に読み込んで実行する、というシンプルかつ窮屈な方式でした。UEFIはこれを刷新し、ディスクをGPTで管理してESP(FAT32の専用パーティション)に置かれた .efi 実行ファイルを直接ロードします。割り込みベースの貧弱なサービスではなく、メモリ確保やデバイスアクセスをC言語のAPIで呼べるBoot Servicesを提供する点が決定的に異なります。
POST と UEFIのフェーズ ─ SEC/PEI/DXE/BDS
電源投入時の自己診断をPOST(Power-On Self-Test)と呼びます。CPU・メモリ・主要デバイスの存在と健全性を確認し、致命的な異常はビープ音やPOSTコードで知らせます。UEFI実装ではこのPOSTが、仕様で定義された一連のフェーズの中で進みます。
UEFIブートフェーズ(PI仕様)
SEC Security : リセットベクタ直後。CARを立て、Root of Trustを確立し次段を検証
PEI Pre-EFI Init : メモリ初期化(DRAM training)が主役。CPU/チップセットの最小構成を整える
DXE Driver Exec : 本番。多数のDXEドライバを順次ロードしProtocol(サービス)を構築
BDS Boot Dev Sel : ブート対象を選ぶ。BootOrder/BootXXXX変数に従いブートローダを起動
TSL Transient OS : ブートローダ稼働中。最後にExitBootServices()でBoot Servicesを終了
RT Runtime : OSへ完全移譲。Runtime Servicesだけが残る
実務上の勘所はPEIでのメモリ初期化です。DDRはただ通電すれば使えるわけではなく、信号タイミングを実測して最適点を探すDRAM trainingが必要で、これがブート時間の体感に効きます。続くDXEが最も重く、ストレージ・USB・ネットワークなどのドライバを次々ロードして「Protocol」という形でサービスを公開します。そしてBDSが BootOrder という不揮発変数(NVRAM)を見て、どのブートローダを起動するかを決めます。
UEFIで最も象徴的な瞬間が、ブートローダが呼ぶ ExitBootServices() です。これを境にファームウェアのBoot Services(メモリ確保やデバイスドライバ)は無効化され、メモリの所有権がOSへ移ります。以降残るのは時刻取得やNVRAM変数アクセスといった最小限のRuntime Servicesだけです。OS起動後に「UEFI変数は読めるがドライバは使えない」のはこの線引きのためです。
ブートローダ ─ ファームウェアからカーネルへの橋
BDSが選んだ .efi がブートローダ(Linuxなら GRUB や systemd-boot、Windowsなら Windows Boot Manager / winload)です。役割はカーネルイメージと初期RAMディスク(initramfs)をメモリへ読み込み、カーネルが期待する状態(メモリマップ、コマンドライン、ハンドオフ構造体)を整えてからカーネルのエントリポイントへジャンプすることです。
ここでブートローダは「ファームウェアの作法」と「OSの作法」の両方を翻訳します。UEFIのメモリマップを取得し、ExitBootServices() を呼び、Linuxならブートプロトコルに従ってカーネルへ制御を渡します。カーネルは渡されたメモリマップを元に自前のページテーブルを組み、割り込みやスケジューラを初期化していきます。この先は割り込み・例外ハンドリングや仮想メモリとTLBの世界です。
Secure Boot ─ 署名検証による信頼の連鎖
ブート経路を乗っ取るマルウェア(ブートキット)は、OSが立ち上がる前に潜り込むため検知が極めて困難です。これを防ぐのがSecure Bootで、UEFIが各実行前にコードの署名を検証し、信頼できる鍵で署名されていないものを実行しません。
検証は鍵の階層で成り立ちます。
Secure Bootの鍵階層
PK Platform Key : 最上位。プラットフォーム所有者(通常メーカ)。KEKの更新を許可する根
KEK Key Exchange Key : DB/DBXを更新する権限を持つ鍵(OSベンダ等)
DB Signature Database : 許可リスト。ここの鍵/ハッシュで署名されたものだけ実行可
DBX Forbidden Database : 失効リスト。脆弱なローダ等を名指しで拒否
UEFIはブートローダの署名を DB の鍵で検証し、ブートローダはさらにカーネルやドライバの署名を検証する、という具合に各段が次段を検証します。これが信頼の連鎖です。一段でも検証に失敗すれば連鎖は途切れ、実行は止まります。Linuxでは Microsoft が署名した小さな shim を入口に置き、shimがディストリ独自鍵でGRUB以降を検証する構成が広く使われます。
Secure Bootが保証するのは署名が有効であることだけで、「正規かつ無改竄であること」とは厳密には別です。署名鍵が漏れたり、脆弱性のある署名済みローダ(いわゆるBYOVDの温床)が悪用されれば、検証を通過してしまいます。だからこそ DBX(失効リスト)の更新が重要で、既知の危険な署名済みバイナリを後から拒否できるようにしてあります。署名検証はあくまで「許可された鍵で署名されているか」の判定です。
Measured Boot ─ PCRへの測定とリモート認証
Secure Bootが「不正なら止める」仕組みなのに対し、Measured Boot は「実行を止めはしないが、何を実行したかを記録する」仕組みです。両者は目的が異なり、しばしば併用されます。
中核はTPM(Trusted Platform Module)のPCR(Platform Configuration Register)です。各段は次段を実行する前に、そのコードのハッシュを計算してPCRへ**extend(拡張)**します。extendは上書きではなく連鎖ハッシュです。
PCR extendの定義(上書きではない)
PCR_new = Hash( PCR_old || measured_hash )
最初 PCR = 0...0
段1 PCR = Hash(0...0 || H(firmware))
段2 PCR = Hash(PCR || H(bootloader))
段3 PCR = Hash(PCR || H(kernel))
...
-> 測定の順序と内容がすべて織り込まれた一意の値が残る
この連鎖構造のため、途中で一つでも別のコードが実行されれば最終的なPCR値は別物になります。後からリモート認証(remote attestation)で、TPMが署名した現在のPCR値(Quote)を検証サーバーへ提示すれば、起動経路が期待どおりだったかを遠隔から判定できます。ディスク暗号化の鍵をPCR値にシール(seal)しておけば、ブート経路が改竄された環境では鍵が封印解除(unseal)されず、データを守れます。
「リセットベクタは固定アドレス(x86-64で 0xFFFFFFF0)でROM/SPIフラッシュに張られ、DRAM未初期化のためCache-as-RAMで動く」「UEFIは SEC→PEI→DXE→BDS と進み、PEIでメモリ初期化、DXEでドライバ群、BDSでブートローダ選択、ExitBootServices() でOSへ移譲」「Secure Bootは署名検証で止める(PK/KEK/DB/DBXの鍵階層)、Measured BootはハッシュをPCRへextendして記録する(attestationで検証)」の3点が核心です。Secure BootとMeasured Bootを混同しないことが頻出の落とし穴です。
まとめ
- CPUはリセット解除後、固定のリセットベクタからフェッチを始める。そこはROM/SPIフラッシュ上にあり、DRAM未初期化のためCache-as-RAMで初期コードが走る。ROM内の不変コードが信頼の起点になる。
- UEFIは SEC→PEI→DXE→BDS と環境を組み立て、PEIでメモリ初期化、DXEでドライバ群を構築し、BDSがブートローダを選ぶ。
ExitBootServices()を境にBoot Servicesが切れ、OSが主導権を握る。 - Secure Bootは各段の署名を PK/KEK/DB/DBX の鍵階層で検証して不正を止め、Measured BootはハッシュをTPMのPCRへextendして記録し、attestationやシール鍵で改竄を検出する。両者は補完関係にある。
ブート後の世界は、デバイスを安全にOSへ繋ぐDMAとIOMMUの原理や、ハイパーバイザが介在するハードウェア仮想化支援へと続きます。電源投入直後の「何も使えない」状態から信頼を一段ずつ積み上げていく設計思想こそ、現代プラットフォームのセキュリティの土台です。
CPU/メモリ/ディスク Article
ブートシーケンスとファームウェア ─ リセットからOSハンドオフまでを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ブート
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 6
導入後に効く点
UEFIはSEC→PEI→DXE→BDS→TSLと段階的に環境を整える。PEIでメモリを初期化し、DXEで多数のドライバを読み込んでサービスを構築し、BDSがブート対象を選んでブートローダ(例 GRUB/Windows Boot Manager)へ制御を渡す。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 6
判断チェックリスト
- 自社の用途が「ブート / UEFI」に近いか確認する。
- 強みである「CPUはリセット解除後、固定のリセットベクタ(x86-64では物理アドレス0xFFFFFFF0)からフェッチを開始する。そこはROM/SPIフラッシュに張られており、まだDRAMもキャッシュも使えないため初期コードはレジスタやキャッシュをRAM代わりに使うCAR(Cache-as-RAM)で動く。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。