【Linux】ブートプロセスに関する学習記録

2024年1月5日

- 本記事にはアフィリエイト広告が含まれます -

こんにちは、キクです。

本記事は、僕が自己学習で学んだことをブログでアウトプットするシリーズになります。
今回は『Linuxにおけるブートプロセス』について調べたことを書いていこうと思います。

それでは、よろしくお願いします。

注意事項

本記事は自己学習としてのアウトプットが目的となります。

そのため、本記事には誤った情報が含まれる可能性もありますが、ご了承ください。

本題:ブートプロセスについて

今回はLinuxが起動するまでの流れ「ブートプロセス」について学習しました。

本質的には同じことが書いてあると思うのですが、調べれば調べるほどサイトによって若干書いてあることが違っていて混乱しました。
本記事には一旦腑に落ちた内容として整理したものを書いておきます。

起動の流れ

  1. 電源投入
  2. BIOS/UEFIが動作開始
  3. 各種デバイスの認識/初期化
  4. 起動デバイスのMBR領域からブートストラップローダを読み込み、サーバのメモリ上に書き込み
  5. CPUが起動し、メモリ上のブートストラップローダを実行
  6. ブートストラップローダにより起動デバイスの更に別の場所に格納された「ブートローダ(GRUB2など)」をメモリに読み込んで実行
  7. ブートローダが起動デバイスに保存されている「カーネル本体」と「初期RAMディスクファイル」をメモリに読み込む
  8. ブートローダがカーネルを実行
  9. カーネルは初期RAMディスクを一時的なルートファイルシステムとしてマウント(=ループバックマウント)
  10. カーネルは初期RAMディスク上のinitプログラムを実行
  11. エラーチェックを実施してルートファイルシステムをマウント
  12. カーネルはルートファイルシステム上のinitプログラムを実行
    initは「/etc/inittab」ファイルを参照して、そこに書かれた処理を順次実施していく
    参考:組込みLinuxを起動するまでの基礎知識
    Systemdではやや処理内容が異なることに留意
    参考:「Systemd」を理解する ーシステム起動編ー
  13. ログイン画面表示

関連調査

ここからはLinuxのブートプロセス関連で調べたキーワードや処理について記載していきます。

関連キーワード

BIOS(Basic Input Output System)

電源投入後、最初に起動するプログラム
マザーボードに内蔵チップとして組み込まれており、カーネル認識前でも動作可能

必要に応じて新しいバージョンに書き換えることができる

BIOSによってシステム起動に必要な「起動デバイス(HDD / CD-ROM / USBなど)」が認識され、必要な「ブートローダ(=起動プログラム)」が読み込まれる

BIOSのバージョンが古いと、最新のアダプタ類を正しく認識できず、本来利用可能なアダプタが正常に利用できない(構成エラーが発生する)ことがある
このような場合には、BIOSを最新のバージョンにアップデートするなどの対応が必要

BIOSには予め「ブートデバイス情報」が設定されており、起動時にはその情報を元に認識しにいく

BIOSでは、以下のような処理が実施される

  1. メモリのチェック
  2. ハードウェア設定の読み込み
  3. 起動デバイスのチェック
  4. 起動デバイスのMBR領域に格納されてブートストラップローダを実行

POST(Power On Self Test)

BIOSによるデバイスの初期化プロセスのこと

MBR(Master Boot Record)

HDDなどの「起動デバイス」の先頭セクタのこと

BIOSはMBRをメモリ上にロードし、MBR領域にあるプログラム( = ブートストラップローダ)に制御を移す

全体サイズは512バイトで、以下のような内訳となっている

MBRの内訳

446バイト:ブートストラップローダ格納領域

64バイト :パーティションテーブル

2バイト  :ブートシグネチャ(MBRの有効性を示す決まった値)

ブートストラップローダ

起動デバイス(内蔵ハードディスクやCD/DVDメディアなど)のMBR領域に書き込まれた446バイトのプログラムコード
起動デバイスの別の場所にあるブートローダ(GRUBなど)をメモリに読み込む

ブートローダ

起動デバイスに保存されている「カーネル本体」と「初期RAMディスクファイル」をメモリに読み込む

このとき、ブートローダは設定ファイル「/boot/grub2/grub2.cfg」を読み込んで起動メニューを表示する
この表示メニューからメモリに読み込んで起動するカーネルと初期RAMディスクのペアを選択することができる

なお、各読み込み対象は基本的に以下のパスに格納されている

各読み込み対象の格納先

カーネル本体   :/boot/vmlinuz-カーネルバージョン

初期RAMディスク:/boot/initramfs-カーネルバージョン.img

ブートローダが起動するとカウントダウンが開始され、その間にカーネルを選択することができる
何も選択しなかった場合にはデフォルトのカーネルが起動する

ブートセクタ / PBR(Partition Boot Record)

各基本パーティションの先頭セクタのことを指す

パーティションテーブル

MBR内の領域のひとつ
複数のパーティションに関する情報が保存されている

IPL(Initial Program Loader)

OSを起動させるためのブートローダの「残りの機能」を呼び出すための機能を持つ

この「残りの機能」は、ブートローダの2ndステージと呼ばれることもある

MBR/PBRは512バイトと非常に小さな領域で、ここに格納されているIPLはさらに小さなサイズである
この小さなプログラムに、OSを起動するためのブートローダの全内容を含めるのは困難である

そのため、IPLにはブートローダの「一部のプログラムコード」のみを持たせ、PBRの後続セクタに格納されている「残りの機能」を読み込むことで後続処理を続ける形となっている

IPLから呼び出されたブートローダの「残りの機能」によって後続のOSファイルを読み込み、最終的にOSが起動する流れとなる

初期RAMディスク

カーネルが起動した後は、まずは起動ディスクにアクセスして各種ファイルシステムをマウントする必要がある
このとき、起動ディスクにアクセスするためにデバイスドライバが必要となる

しかし、カーネル起動直後は必要なデバイスドライバを読み込んでいないため、上記ディレクトリにアクセスすることができない

ポイント

カーネルモジュール一式は/lib/modules/カーネルバージョン配下に格納されている

なお、起動ディスク用のデバイスドライバも上記ディレクトリにある

[確認例]
# ll /lib/modules/5.15.59-v8.2.el9
total 2544
lrwxrwxrwx.  1 root root     33 Aug 30  2022 build -> /usr/src/kernels/5.15.59-v8.2.el9
drwxr-xr-x. 11 root root   4096 Aug 30  2022 kernel
-rw-r--r--.  1 root root 605053 Aug 30  2022 modules.alias
-rw-r--r--.  1 root root 630151 Aug 30  2022 modules.alias.bin
-rw-r--r--.  1 root root  15356 Aug 30  2022 modules.builtin
-rw-r--r--.  1 root root      0 Aug 30  2022 modules.builtin.alias.bin
-rw-r--r--.  1 root root  16993 Aug 30  2022 modules.builtin.bin
-rw-r--r--.  1 root root  87664 Aug 30  2022 modules.builtin.modinfo
-rw-r--r--.  1 root root 226347 Aug 30  2022 modules.dep
-rw-r--r--.  1 root root 304347 Aug 30  2022 modules.dep.bin
-rw-r--r--.  1 root root    384 Aug 30  2022 modules.devname
-rw-r--r--.  1 root root  67795 Aug 30  2022 modules.order
-rw-r--r--.  1 root root    883 Aug 30  2022 modules.softdep
-rw-r--r--.  1 root root 279619 Aug 30  2022 modules.symbols
-rw-r--r--.  1 root root 339084 Aug 30  2022 modules.symbols.bin
lrwxrwxrwx.  1 root root      5 Aug 30  2022 source -> build

この問題を解決するのが初期RAMディスクである
初期RAMディスクの実態は、デバイスドライバをはじめとする「カーネル起動直後に使用するファイル群」をまとめたアーカイブファイルである

また、初期RAMディスクはブートローダによって既にメモリ上に読み込まれているため、カーネルは初期RAMディスクを利用してデバイスドライバを読み込むことが可能となっている

初期RAMディスクの中身は以下のコマンドで確認することができる

# lsinitrd /boot/initramfs-カーネルバージョン.img

paxコマンドを利用することで初期RAMディスクをtmpディレクトリなどに解凍して、直接中身を確認することもできる

初期RAMディスクの中には、必ず「init」という名前の実行ファイルがある
このファイルを実行することで、ルートファイルシステムのマウントに必要なカーネルモジュールをロードしたりする

また、最終的に読み込む「ルートファイルシステム」上にも「init」プログラムが存在する
このinitプログラムはどのプロセスよりも先に実行されるため、常に「PID:1」となる
いわゆる初期化プロセスである

前者のinitプログラムが実行されることでルートファイルシステムがマウントされる
その後、ブートプロセスが進行していく中で後者のinitプログラムが実行される

RAMディスク

メモリ上にファイルシステムを作成する機能

ループバックマウント

初期RAMディスクのような「ファイル」をファイルシステムとしてマウントする機能

カーネル

Linuxの根幹となるシステム

以下のような役割を担う

カーネルの主な役割

  • システムリソース(CPUやメモリなど)の管理
  • デバイスの制御
  • プロセスのスケジューリング
  • プロセス間の通信
  • 割り込み処理
  • ユーザ管理
  • 時刻管理
  • その他

カーネルは以下のような要素から構成される

  1. 核となる部分
  2. コンパイル時に静的にリンクされるカーネルモジュール
  3. 起動後に必要に応じて動的にメモリに読み込まれるローダブルカーネルモジュール(/lib/modules/version/kernel)

カーネルはブートローダからメモリに読み込まれると、自身の初期化シーケンスを実施する
その後、メモリにロードされている初期RAMディスクをマウントする
初期RAMディスクのマウント後、それを利用してルートファイルシステムをマウントする

カーネルのバージョン情報は「/proc/version」に格納されており、以下のようなコマンドで確認できる

[確認例1]
# cat /proc/version
Linux version 5.15.59-v8.2.el9 (mockbuild@88c6f946b38a4410a07280c4fbe2912c) (gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2), GNU ld version 2.35.2-24.el9) #1 SMP PREEMPT Tue Aug 30 01:59:02 UTC 2022

[確認例2]
# uname -a
Linux localhost.localdomain 5.15.59-v8.2.el9 #1 SMP PREEMPT Tue Aug 30 01:59:02 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux

カーネルの起動

以下のような処理が行われる

  1. ハードウェアの検出
  2. メモリの初期化
  3. システムクロックの設定
  4. IRQの設定
  5. ルートパーティションのマウント
  6. initプログラム(/sbin/init)の実行

処理内容はdmesgコマンドで確認可能

GRUBについて

ブートローダの一種で、ハードディスクなどからOSを起動するためのプログラム

多数のファイルシステムを認識可能
シェル機能も搭載している

■インストール方法

下記コマンドを実行すると、/dev/sdaのMBRにGRUB2がインストールされる

# grub2-install /dev/sda

■設定ファイル

以下2パターンある模様

  1. /boot/grub/grub.cfggrub-mkconfigコマンドにより自動生成されるもの手動での編集は避ける
  2. /etc/default/grub手動で設定したい場合にはこのファイルを編集する

編集の流れとしては、ファイル2を手動で編集した後、下記コマンドでファイル1の書き換えをするっぽい?

# grub2-mkconfig -o /boot/grub2/grub.cfg

参考:【Linux】ブートローダとは?とブートローダのインストール方法

関連処理

初期RAMディスク利用前の事前処理

以下のような処理が行われる

  1. メモリ上の初期RAMディスクファイルから一時的なファイルシステムを作成(機能名:RAMディスク)
  2. 上記ファイルシステムをマウント(処理名:ループバックマウント)
  3. 初期RAMディスクに含まれるファイル群を上記RAMディスク領域に展開して利用

初期RAMディスク上のinitプログラム実行について

「実際のルートファイルシステムのマウント準備」および「同ファイルシステムへのアクセスの準備」を行う

ルートファイルシステムが存在するデバイスにアクセスするためのドライバなどのモジュール郡を読み込んでくれる
必要なモジュールが読み込まれると、udevによってInitramfsに対して必要なデバイスが提供される

参考:Linuxのブートプロセス
参考:10 ブートプロセスの概要

ディスク装置にアクセスする仕組みの違い

■BIOS

ブートローダを読み込む際にブートデバイス(内蔵ディスクなど)にアクセスするが、この時にはデバイスドライバを必要としない
BIOSはマザーボードを製造するメーカーが作成するソフトウェアであるため、マザーボードに接続されたディスク装置にアクセスする機能が事前に用意されている

この機能を利用することで、デバイスドライバを必要とせずに自身の力でディスクにアクセスできる
ただし、機能としては限定的になる

■ブートローダ

カーネルや初期RAMディスクを読み込む際にディスク装置にアクセスするが、BIOS同様にデバイスドライバは不要
これはブートローダがBIOSの機能を呼び出してディスクにアクセスしているためである

■カーネル

先述の通り、BIOSの機能でのディスクへの接続は「機能が限定的」であったり、すべてのディスク装置に対してアクセスできるわけではない
そのような背景も踏まえて、カーネルではデバイスドライバを利用してディスクにアクセスする

参考情報

参考:【Linuxの基礎知識】起動の仕組みとカーネルについて!
参考:Linux道場入門編(LPI-JAPAN)
参考:ブートローダ
参考:【Linux】ブートローダーからカーネルまでの起動プロセス
参考:Initramfsのしくみ
参考:マスターブートレコード(MBR)_分かりそうで分からないシリーズ

-学習記録, Linux
-,