概要
- 電源ボタンを押してからLinuxカーネルが動き出すまでの一連の流れを解説
- CPUのリセットからBIOS/UEFI、ブートローダ、セットアッププログラムの役割
- 32ビット保護モードから64ビットロングモードへの移行手順
- カーネルの展開とアドレス修正、kASLRによるランダム化
- 低レベルの仕組みと用語の簡単な説明付き
電源投入からカーネルの最初の命令まで
-
電源ボタン を押すと、CPUは自動的にリセットされ、 real mode (8086時代のモード)で起動
-
メモリアドレス はセグメントとオフセットで構成され、hex(16進数)表記が多用される
-
リセットベクタ(0xFFFFFFF0) にジャンプし、ごく短いジャンプ命令で マザーボードのファームウェア (BIOSまたはUEFI)へ制御を渡す
- レジスタ はCPU内の高速な記憶スロット、CSはコードセグメント、IPは命令ポインタ
-
BIOS はPOST(電源投入時自己診断)を実行し、ブート順に従いデバイスを調査
- ブート可能なデバイスを見つけると、最初の512バイトセクタ(0x55, 0xAAで終了)を0x7C00にコピーし、そこへジャンプ
- セクタは小さいため、次の大きなプログラムを読み込むだけの役目が多い
-
UEFI はファイルシステムを直接理解し、より大きなブートプログラムを読み込むことが可能
- より多くの情報をOSに渡す
ブートローダとセットアッププログラム
- ブートローダ (例:GRUB)はOSをメモリに配置する案内役
- 設定を読み込み、メニュー表示やLinuxカーネルのロードを実行
- カーネルファイルには小さな setupプログラム (real mode用)と圧縮済みカーネル本体が含まれる
- setup headerにカーネル配置場所やコマンドライン、initrdの位置などの情報を格納
- setupプログラム は作業空間の初期化を担当
-
セグメントレジスタ(CS, DS, SS)を整え、 direction flag をクリアし、スタックを作成
-
BSS領域 (グローバル変数の初期化用)をゼロクリア
-
earlyprintk が指定されていればシリアルポートを初期化
-
ファームウェアから利用可能なRAM領域情報(e820)を取得
-
最初のC関数mainを呼び出し、real modeからの脱出準備
-
割り込み はCPUの「割り込み」機能で、maskable(一時的に無効化可能)とnon-maskable(NMI、常に割り込む)が存在
-
32ビット保護モードから64ビットロングモードへの移行
-
protected mode は1980年代の制限を超える32ビット世界
- GDT (グローバルディスクリプタテーブル)でセグメント定義
- Linuxは flat model (全空間を単純に扱う)を採用
- IDT (割り込みディスクリプタテーブル)は割り込み時のジャンプ先管理
-
移行手順
-
割り込みを無効化し、 A20ライン を開放(1MB超アドレスのための歴史的対応)
-
FPU (浮動小数点演算ユニット)をリセット
-
必要最小限のGDTとIDTをロード
-
CR0 のPEビットをセットし、far jumpで保護モードへ
-
データ・スタックセグメントを再設定し、32ビット保護モードに移行
-
制御レジスタ (CR0, CR3, CR4)はモード切替やページテーブルのアドレス管理に使用
-
-
64ビットロングモード (Linuxが本当に動作するモード)に移行するには
- ページング (仮想アドレス→物理アドレス変換)が必須
- PAE (CR4で有効化)と LME (EFERレジスタで有効化)をセット
- 低メモリを2MB単位でカバーする最小限のページテーブルを構築し、CR3にセット
- LMEを有効化し、64ビットコードへfar returnでジャンプ
-
モード切替時は割り込みや状態管理を慎重に扱い、異常状態を防止
カーネル展開、アドレス修正、kASLR
-
64ビットスタブ が自身の実行位置を確認し、必要なら安全な場所へ移動
-
BSS領域 をクリアし、最小限のIDT(ページフォールト、NMI用)をセット
- ページフォールト発生時は、その場でマッピング追加
-
カーネルやブートパラメータ、コマンドラインバッファのためにアイデンティティマッピングを用意
-
extract_kernel 関数がカーネル展開を担当
- 一時ヒープを確保し、圧縮アルゴリズム(gzip, xz, zstd, lzo等)でカーネルを解凍
- ELFヘッダ を読み、必要なアドレスに各セクションを配置
- 配置先がビルド時と異なる場合は リロケーション 処理でアドレス修正
- 展開完了後、カーネルのエントリーポイントにジャンプし、ブートパラメータを渡す
- 最初に呼ばれる関数は start_kernel で、本格的な初期化が始まる
-
kASLR (Kernel Address Space Layout Randomization)は、カーネルの物理・仮想ベースアドレスをランダム化し、セキュリティ向上を図る技術
- 攻撃者にカーネル位置を特定させにくくする工夫
この流れで、電源投入からLinuxカーネルの本格的な起動までの詳細なプロセスを把握可能。低レベルの仕組みや用語も理解しやすい構成。