Slide 1

Slide 1 text

Linuxのブートプロセス initramfs編 Mar. 15th, 2025 Satoru Takeuchi X: satoru_takeuchi 1

Slide 2

Slide 2 text

はなすこと ● マシンの電源投入からinitramfsを使った場合にinitが起動するまでの流れ ○ 使わない場合は前回の動画「 Linuxのブートプロセス」を参照 ○ Secure Bootは省略(後日別動画で説明するかも ) ● 前回との差分を中心に紹介後、改めてinitramfs込のブートの流れを説明 ● 環境 ○ CPUアーキテクチャ: x86_64 ○ ファームウェア: UEFI BIOS ○ ブートローダ: GRUB ○ ディスクが1台あり、GRUBとLinuxをインストールしている ■ ディスクのドライバはカーネルモジュールとして持つ ■ カーネルモジュールは rootfsに存在する 2

Slide 3

Slide 3 text

カーネル機能の提供方法についてのジレンマ ● カーネル機能は本体に組み込むか外付けのカーネルモジュールとして提供可能 ● カーネル本体のサイズはなるべく小さくしたい ○ メモリ使用量が減らせる ○ カーネルのロードが速くなる →起動が速くなる ● なるべく多くのカーネル機能を使いたい ○ とくにユーザのハードウェア環境がわからない&なるべく多くの環境で動かせるようにしたいディストリビュータに当て はまる ● カーネルが提供する機能を多くして、ほとんどをカーネルモジュールで提供すればいいとこどり できる 3

Slide 4

Slide 4 text

課題と解決方法 ● rootfsをmountするまではカーネル本体に組み込まれた機能のみ使用可能 1. カーネルモジュールはディスクのファイルシステム上に存在する 2. モジュールをロードするには rootfs上のmountが必要 3. それにはrootfsがあるディスクのドライバ、 rootfsのファイルシステムドライバなどが必要 4. これらの機能をモジュールとして提供しているとドライバが読めない ■ 📝 boot中に”VFS: Unable to mount root fs”というログが出る場合、この問題に遭遇してい るの可能性が高い ● そこでinitramfsですよ ○ ブート時に必要なカーネルモジュールを含む仮の rootfs用をcpioで固めて圧縮したファイル ○ 展開後の仮のrootfsもinitramfsと呼ぶ 4

Slide 5

Slide 5 text

initramfsがない場合との違い ● GRUBはvmlinuzファイルとinitramfsをメモリ上にロード ● initramfsを仮のrootfsとしてmount&その上の仮のinitを実行 ● 仮のinitがディスクから真のrootfsを読み出しrootfsを切り替え 5

Slide 6

Slide 6 text

GRUBがvmlinuzファイルとinitramfsをメモリ上にロード ● vmlinuzに加えてinitramfsは通常ブートパーティション(“/boot/”)に存在 ● ロードの流れ 1. 設定に基づきシステムに存在するカーネルの一覧を取得し、カーネルと initramfsをブートパラメタで 指定する(“root”,”initrd”パラメタ) 2. vmlinuzファイルとinitramfsをメモリ上にロード 6 物理アドレス空間 カーネル展開 コード カーネル圧縮 イメージ disk GRUB (1) vmlinuzとinitramfsを指定 (2) ロード initramfs

Slide 7

Slide 7 text

initramfsを仮のrootfsとしてmount&その上のinitを実行 1. カーネルはinitramfsファイルを展開してメモリ上にtmpfsのデータ構造を作る 2. tmpfsを仮のrootfsとしてmount a. この後はカーネルモジュールを読めるのでロード可能 3. tmpfs上のinitを実行 7 物理アドレス空間 カーネル (1) initramfsを展開して tmpfsのデータ構造を作成 仮のrootfs (tmpfs) initramfs (2)(3) tmpfsを仮のrootfsと してmount&init実行

Slide 8

Slide 8 text

仮のinitがディスクから真のrootfsを読み出しrootfsを切り替え 1. “root”ブートパラメタで指定した真のrootfsをディスクから読み出しmount a. カーネルモジュールをロードできるのでディスクドライバ、ファイルシステムドライバはカーネルモ ジュールとして提供されていても OK 2. rootfsを仮のものから真のものに切り替え 3. 真のrootfs上のinitをメモリマップして実行 8 物理アドレス空間 disk カーネル (1) 真のrootfsを読み出しmount (2)(3) rootfsを切り替え&真のinitを実行 仮のrootfs (tmpfs) 真のrootfs

Slide 9

Slide 9 text

initramfsを考慮したブート処理の流れ 1. 人間がマシンの電源を入れる 2. マシン上のUEFI BIOSが起動 3. UEFI BIOSがハードウェアを初期化 4. UEFI BIOSがGRUBをロードして実行 5. GRUBがvmlinuzファイルとinitramfsをメモリ上にロード 6. GRUBがカーネル展開コードを実行 7. 展開コードがカーネルをロードして実行 8. カーネルがシステムを初期化 9. initramfsを仮のrootfsとしてmountして仮のinitを動かす 10. rootfsを仮のものから真のものに切り替える 9

Slide 10

Slide 10 text

マシン上のUEFI BIOSが起動 ● マシンは電源を入れると特定アドレス(0xFFFFFFF0)上に存在するUEFI BIOSプロ グラムを動かすようになっている ● UEFI BIOSはマシンの不揮発性メモリ上に存在しており、システム起動時に物理ア ドレス空間の上述のアドレスにマップされている ○ 📝 つまり物理アドレスが物理メモリ以外のデータを指すことがある ○ 📝 UEFI BIOS以外にも物理アドレス空間にマップされるデータは他にもあるが、本動画では以下 のようなイメージを持っていればいい 10 物理アドレス空間 0 0xFFFFFFF0 不揮発性メモリ上の UEFI BIOS 物理メモリ 物理メモリ

Slide 11

Slide 11 text

UEFI BIOSがハードウェアを初期化 ● CPUの動作確認、初期化 ○ ブート直後は機能制限されていて、 UEFI BIOSが制限を外すというイメージ ● メモリの動作確認、初期化 ○ これをする前は物理メモリにアクセスできない! ● ディスクなどのその他ハードウェアを初期化 ● どこの領域にどんなデータがマップされているかを記録 ○ 📝 後でカーネルが使う 11

Slide 12

Slide 12 text

UEFI BIOSがGRUBをロードして実行 1. GPT形式のパーティションテーブルでフォーマットされたディスクを探す 2. ESP(EFI System Partition)というGUIDを持つパーティションを見つける a. 📝 このパーティションは FAT32ファイルシステムでフォーマットされている 3. ESPから「UEFIアプリケーション」と呼ばれる実行ファイルを見つける a. 📝 UEFIアプリケーションを実行するのは LinuxではなくUEFI BIOS 4. UEFI BIOSはUEFIアプリケーションであるGRUBをロード&実行 a. 通常はGRUBがデフォルトで動作するように設定されている 12 UEFI BIOS 物理アドレス空間 disk (1)(2)(3)GRUBを見つける GRUB (4) GRUBをロード&実行

Slide 13

Slide 13 text

GRUBがvmlinuzファイルをロード(前提知識) ● ESPはLinux動作時に通常(“/boot/efi/”)にマウントされている ○ GRUB EFIアプリケーションのファイル名は通常 ”/boot/efi/EFI/BOOT/BOOTX86.EFI” ● vmlinuzとinitramfsは通常ブートパーティション(“/boot/”)に存在する ○ 📝 GRUBはLinuxの一部のファイルシステム (e.g. ext4, XFS)を読み出せる ■ “/boot”はGRUBが読み出せるファイルシステムでなければならない ● カーネル圧縮イメージのフォーマット(bzImage形式と呼ばれる): 13 setup header カーネル展開コード カーネル圧縮イメージ カーネル展開コードやカーネルの ロード先メモリアドレス、エントリポイ ントを保持

Slide 14

Slide 14 text

GRUBがvmlinuzファイルとinitramfsをメモリ上にロード ● vmlinuzとinitramfsは通常ブートパーティション(“/boot/”)に存在 ● 処理の流れ 1. 設定に基づきシステムに存在するカーネルの一覧を取得し、カーネルと initramfsをブートパラメタで 指定する(“root”,”initrd”パラメタ) 2. vmlinuzファイルとinitramfsをメモリ上にロード 14 物理アドレス空間 カーネル展開 コード カーネル圧縮 イメージ disk GRUB (1) vmlinuzとinitramfsを読み出し (2) ロード * スペースの都合でsetup headerは省略 initramfs

Slide 15

Slide 15 text

GRUBがカーネルの展開コードを実行 ● カーネル展開コードのエントリポイントにジャンプして実行開始 15 物理アドレス空間 カーネル展開 コード カーネル圧縮 イメージ disk GRUB ジャンプ initramfs

Slide 16

Slide 16 text

展開コードがカーネルをメモリマップして実行 1. カーネル展開コードがカーネル圧縮イメージを読み出す 2. 圧縮イメージをメモリ上に展開してメモリ上にマップ 3. カーネルのエントリポイントにジャンプ 16 物理アドレス空間 カーネル展開 コード カーネル圧縮 イメージ disk カーネル (1) 読み出し (2) 展開&マップ (3) エントリポイントにジャンプ initramfs

Slide 17

Slide 17 text

カーネルがシステムを初期化 ● ハードウェアやカーネルそのものの初期設定 ○ 📝 UEFI BIOSはマシンの起動に必要な最低限の初期化しかしないが、カーネルによるハードウェ アの初期設定はシステムが稼働し続けるために必要な設定をするという違いがある ● まだrootfsをmountしていないのでカーネルモジュールは読み出せない 17 物理アドレス空間 カーネル initramfs disk

Slide 18

Slide 18 text

initramfsを仮のrootfsとしてmountして仮のinitを動かす 1. カーネルはinitramfsファイルを展開してメモリ上にtmpfsのデータ構造を作る 2. tmpfsを仮のrootfsとしてmount a. この後はカーネルモジュールを読めるのでロード可能 3. tmpfs上のinitを実行 18 物理アドレス空間 カーネル (1) initramfsを展開して tmpfsのデータ構造を作成 仮のrootfs (tmpfs) initramfs (2)(3) tmpfsを仮のrootfsと してmount&initを実行 disk

Slide 19

Slide 19 text

rootfsを仮のものから真のものに切り替える 1. “root”ブートパラメタで指定した真のrootfsをディスクから読み出しmount a. カーネルモジュールをロードできるのでディスクドライバ、ファイルシステムドライバはカーネルモ ジュールとして提供されていても OK 2. 真のrootfs上のinitをメモリマップして実行 19 物理アドレス空間 disk カーネル (1) 真のrootfsを読み出しmount (2) 真のinitプログラムをメモリマップ &実行 仮のrootfs (tmpfs) 真のrootfs

Slide 20

Slide 20 text

おわりに ● initramfsがあるとカーネル本体のサイズを小さく保ったまま多くの機能を提供でき る ● 📝 他にも暗号化ディスク上にrootfsがあるような場合にもinitramfsを使う ● 処理のステップ数が多い! ○ 技術的に難しいわけではなく単なる覚えゲーなので、何度か見れば多分理解できます 20