ブートチェーンの内部(UEFI・ブートローダ・initramfs)
電源投入から init 起動まで、誰がどの順で制御を渡すのか。UEFI・Secure Boot・GRUB・カーネル展開・initramfs の各段を内部動作まで追い、起動トラブルを切り分けられる地力がつきます。
- 1.ブートはリセットベクタ→UEFI→ブートローダ→カーネル→initramfs→init と制御を順送りする多段リレーです。
- 2.Secure Boot は各段の署名を db/KEK/PK の鍵階層で検証し、改ざんされた次段の実行を拒否します。
- 3.initramfs は本物の root をマウントするための一時 root で、必要なドライバを積んでから pivot します。
ブートは「信頼の連鎖」を伴う多段リレー
電源投入直後のマシンには、まだ OS どころかメモリの初期化すらありません。そこから少しずつ大きなプログラムを読み込んでいく過程がブートですが、上級的に重要なのは 各段が「次の段」をロードし、制御を明け渡す という構造です。前段は次段にとって唯一の信頼の起点であり、Secure Boot 環境ではこの連鎖が暗号的に保証されます。
全体像をまず1本のタイムラインで押さえます。
電源 ON / リセット
→ CPU がリセットベクタから実行(ファームウェア本体)
→ UEFI: SEC → PEI → DXE → BDS の各フェーズ
(Secure Boot 有効時は各 EFI 実行体の署名を検証)
→ BDS が BootOrder/BootXXXX 変数を見て起動エントリを選択
→ ESP 上の \EFI\... のブートローダ (例 shimx64.efi → grubx64.efi)
→ GRUB が vmlinuz と initramfs を RAM へロード、boot params 構築
→ カーネル本体: 自己展開 → ページング有効化 → サブシステム初期化
→ initramfs を tmpfs に展開、/init を PID 1 として起動
→ 本物の root を見つけてマウント → switch_root で pivot
→ 本来の init (systemd 等) が PID 1 を引き継ぐ → サービス起動
基礎的な4段モデルは 起動(ブート)プロセス で扱いました。本稿はその各段の内部に踏み込みます。
UEFI の内部フェーズと変数ストア
レガシ BIOS が MBR 先頭512バイトを実行するのに対し、UEFI は ファイルシステムを理解する小さな OS に近い実装で、明確なフェーズ列を持ちます。
| フェーズ | 略 | 主な役割 |
|---|---|---|
| Security | SEC | リセット直後の最初期コード、信頼の根(Root of Trust)確立 |
| Pre-EFI Init | PEI | メインメモリ(DRAM)初期化、最小限のチップセット設定 |
| Driver Exec | DXE | デバイスドライバ群を起動しブートサービス/ランタイムサービスを構築 |
| Boot Dev Select | BDS | 起動デバイスとブートエントリを選び、ローダを実行 |
ブート対象は NVRAM 上の UEFI 変数 で管理されます。BootOrder が試行順を、Boot0001 などの BootXXXX 変数が各エントリ(どの ESP のどのパスの .efi を起動するか)を保持します。Linux では efibootmgr でこれらを読み書きできます。ブートローダが置かれる ESP(EFI System Partition) は FAT32 でフォーマットされた専用パーティションで、ファームウェアが読めるよう GPT 上に特定の種別 GUID で確保されます。
UEFI は基本的に GPT パーティションを前提とします。MBR の制約(2TB 上限、プライマリ4個)を超えるためで、GPT はディスク先頭に保護用 MBR を置きつつ、本体は LBA1 以降のヘッダとエントリ配列で構成されます。
Secure Boot:鍵階層による署名検証
Secure Boot は、UEFI が 次に実行する EFI 実行体の署名を検証 し、許可された鍵で署名されたものだけを起動する仕組みです。鍵は階層構造になっています。
| 鍵/DB | 役割 | 上位で守られる |
|---|---|---|
| PK(Platform Key) | プラットフォーム所有者の最上位鍵。KEK の更新を認可 | (最上位) |
| KEK(Key Exchange Key) | db/dbx を更新する権限を持つ鍵集合 | PK |
| db(許可DB) | 起動を許可する署名/ハッシュの一覧 | KEK |
| dbx(禁止DB) | 失効させた署名/ハッシュの一覧(脆弱版を排除) | KEK |
Linux 環境では多くの場合、Microsoft の鍵で署名された小さな第1段ローダ shim を db に通し、shim が独自の MOK(Machine Owner Key) を使って GRUB やカーネルを検証します。これにより、ディストリビュータは Microsoft の鍵階層を直接持たずに署名チェーンを延長できます。検証は段ごとに行われ、shim → grub → vmlinuz のいずれかが改ざんされると、その段で起動が拒否されます。
脆弱な旧 GRUB などを失効させる dbx 更新が配布されると、古いローダを使い続けるシステムは「正規だが失効済み」となり起動不能に陥ることがあります。Secure Boot 有効環境では、ローダとファームウェアの更新タイミングを揃える必要があります。
ブートローダ(GRUB)の役割
GRUB の本質的な仕事は、カーネル本体(vmlinuz)と initramfs を RAM に読み込み、ブートパラメータを整えてカーネルに制御を渡す ことです。UEFI 環境の GRUB は、ファームウェアの提供するブートサービス経由でファイルを読みます。実行イメージはおおむね次の流れです。
grub_main():
load grub.cfg # メニュー定義を読む
show menu / pick entry # エントリ選択(タイムアウトあり)
linux /vmlinuz root=UUID=... ro quiet # カーネルと cmdline 指定
initrd /initramfs.img # initramfs を RAM へ
boot # EFI ハンドオフでカーネルへジャンプ
ここで渡される root=、ro、init=、rd.* などのカーネルパラメータが、後段の動作を決定づけます。root=UUID=... はファイルシステムの UUID で本物の root を指定する方式で、デバイス名(/dev/sda1 等)が起動ごとに変わる問題を避けます。
カーネル展開とサブシステム初期化
GRUB から制御を受けたカーネルイメージ vmlinuz は、先頭に小さな セットアップ/展開コード を含む圧縮イメージです。順序は次のとおりです。
1. 自己展開: 圧縮された本体を所定アドレスへ伸長
2. アーキ依存の初期化: ページング有効化、CPU モード確定
3. start_kernel(): スケジューラ・メモリ管理・割り込みを初期化
4. ドライバ初期化、initramfs を tmpfs として展開
5. PID 1 として initramfs 内の /init を実行
この段で 仮想記憶が立ち上がる ため、以降のコードは物理アドレスではなく仮想アドレスで動きます。仮想記憶の原理は 仮想メモリ を参照してください。start_kernel() 完了後、カーネルは最初のユーザー空間プロセスとして PID 1 を起動しますが、通常それは本物の init ではなく initramfs の中の /init です。
initramfs:本物の root に到達するための一時 root
ここが上級者が混同しやすい要点です。なぜカーネルは直接本物の root をマウントしないのか。理由は 鶏と卵 にあります。本物の root が LVM・暗号化(LUKS)・RAID・NVMe・ネットワークストレージ上にある場合、それをマウントするには対応するドライバとユーザー空間ツールが必要です。しかしそれらは(多くの場合)まさにマウントしたい root の中にあります。
そこで、起動に必要な最小限のドライバとツールだけを詰めた initramfs(initial RAM filesystem) を GRUB が RAM に積み、カーネルがそれを tmpfs に展開して一時 root とします。/init の仕事はおおむね次のとおりです。
/init (initramfs 内, PID 1):
必要なカーネルモジュールを insmod
udev でデバイスを認識(/dev を populate)
LUKS なら cryptsetup で復号、LVM なら vgchange で活性化
root= が指す本物の FS をマウント → /sysroot
switch_root /sysroot /sbin/init # 一時 root を捨て pivot
switch_root は、新しい root へ移った上で initramfs の tmpfs を解放し、本物の root 上の init(systemd など)を新たな PID 1 として exec します。PID 1 が入れ替わる点が独特で、これによりメモリ上の使い捨て root から恒久的な root へ橋渡しされます。PID と最初のプロセスの位置づけは プロセスとスレッド も参考になります。
古い initrd は「RAM ディスク(ブロックデバイス)」で、専用 FS をマウントして使いました。現在主流の initramfs は cpio アーカイブを tmpfs に展開する方式で、サイズが可変・解放が容易です。GRUB の initrd 命令名は歴史的な名残で、実体は initramfs を指すことが多いです。
init システム:PID 1 がサービスを起動
本物の root 上の init(多くの環境で systemd)が PID 1 を引き継ぐと、ここからは依存関係に基づくサービス起動の世界です。systemd は unit(service・mount・target など)の依存グラフを解決し、独立なものは並列に起動します。古典的な SysVinit がランレベルごとにスクリプトを直列実行したのに対し、systemd は target(到達したい状態) と socket/path などの起動トリガ を使って並列化と遅延起動を行います。
ここまでのリレーを誰が誰に制御を渡すかで整理します。
| 段 | 実行主体 | 次段に渡すもの | 信頼の検証 |
|---|---|---|---|
| ファームウェア | UEFI | ESP 上のローダを実行 | Secure Boot: db で署名検証 |
| 第1段ローダ | shim | MOK で GRUB を検証し実行 | MOK / db |
| ブートローダ | GRUB | vmlinuz + initramfs + cmdline | shim 経由でカーネル署名検証 |
| カーネル | vmlinuz | PID 1 として /init を起動 | (モジュール署名は別途) |
| 一時 init | initramfs /init | 本物の root をマウントし pivot | — |
| 本来の init | systemd 等 | 依存解決して各サービス起動 | — |
画面が真っ黒で UEFI メニューにも入れないならファームウェア/POST 段、GRUB メニューが出るならローダまでは到達、Kernel panic - not syncing: VFS: Unable to mount root fs なら initramfs が root を見つけられていない段、ログインが出ないなら init/サービス段です。停止箇所を上の表に当てはめると、原因の層を素早く絞れます。
まとめ
- ブートは リセットベクタ → UEFI(SEC/PEI/DXE/BDS)→ ローダ → カーネル → initramfs → init と制御を順送りする多段リレー。
- Secure Boot は PK/KEK/db/dbx の鍵階層で各段の署名を検証し、改ざんされた次段の実行を拒否する。
- initramfs は 本物の root をマウントするための使い捨て一時 root で、必要なドライバを積んでから
switch_rootで pivot し、PID 1 を本来の init に明け渡す。
カーネルとユーザー空間の境界は カーネルモードとユーザーモード、本物の root に到達したあとの隔離技術は 名前空間と cgroups(コンテナの基盤) も合わせてどうぞ。
OS Article
ブートチェーンの内部(UEFI・ブートローダ・initramfs)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ブート
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
Secure Boot は各段の署名を db/KEK/PK の鍵階層で検証し、改ざんされた次段の実行を拒否します。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「ブート / UEFI」に近いか確認する。
- 強みである「ブートはリセットベクタ→UEFI→ブートローダ→カーネル→initramfs→init と制御を順送りする多段リレーです。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。