Linuxのブートシーケンスの基礎まとめ

ファームウェアBIOS or UEFI*1)が

  • マザーボードのROMからメモリにロードされて実行開始し、ハードウェアをスキャン(POST - Power-On Self Test というハードウェアの自己診断を)する
  • [BIOSの場合] プライマリHDDのMBR(先頭のセクタ(512バイト))を見る
  • [UEFIの場合] プライマリHDDのGPTヘッダ(LBA1 or 最終セクタ)を見る

https://upload.wikimedia.org/wikipedia/ja/c/cc/GUID_Partition_Table.png

GPTとMBRはどのように違うのか? - かーねる・う゛いえむにっき

BIOS/UEFI/MBR/GPT

  • MBRでは232≒2.2TBまでのディスクしか扱えない
  • GPTでは264≒8.5ZBまでのディスクを扱うことができる

  • BIOSIntel CPUのリアルモード(16bitモード)でないと起動できないため、1MBまでのメモリしか利用できない

  • UEFIはプロセッサ非依存のため、32bitプロセッサなら32bit命令が、64bitプロセッサなら64bit命令が使えるため、潤沢なメモリを利用できる
  • BIOSはGPTに対応していないため、GPTに対応したUEFIを使う

  • MBRパーティションテーブルには四つのパーティション構成情報が書き込める (四つ以上は、四つ目を拡張パーティションテーブルとして対応)

  • MBRの最後の2バイトは0xaa55というMBR signatureが書き込まれている
$ sudo hexdump -s 500 -n 12 /dev/sda
00001f4 0000 0000 0000 0000 0000 aa55          
0000200
  • 一方、GPTは128までパーティションが管理でき、物理や論理といった煩雑な管理は必要ない

  • BIOSのようにGPTを認識しないファームウェアにはMBRを見せることができる

  • 末尾にもGPTヘッダがあり冗長構成となっている

2TB以上のディスクは

  • MBRでは扱うことができない and fdiskコマンドでは扱うことができない
  • GPTを使う必要がある and ( parted or gdisk コマンドを使う必要がある )

  • 追加した2TB以上のディスクにパーティションラベルを付ける

# parted /dev/sdd
(parted) mklabel gpt

ブートローダ(GRUB or LILO)が

GRUB2

GNU GRUB - Wikipedia

initrd/initramfs

  • initrdはブロックデバイスgzip圧縮したもの
  • initramfsはファイルシステムをcpioでアーカイブしたものをgzip圧縮したもの
  • initrdにカーネルモジュールを追加しようとするとマウントが必要(etc.)
     → 扱いにくいのでObsolete
     → 現在では一般的にinitramfsを使う
  • initrdに含まれるファイルにアクセスするためにループバックマウントされる

initrd/initramfsの必要性

vmlinuz/vmlinux/bzImage/zImage

  • bootパーティションには、vmlinuzと呼ばれる、カーネルイメージを含むファイルが置かれている
  • vmlinuzは、カーネルイメージ(vmlinux)をgzip圧縮したものと、圧縮されたカーネルイメージを伸張し展開するコードをそれ自身に伴った形式ものである
  • このファイル形式をbzImageという
  • なお、zImageでは512KB以下のイメージしか扱えない

uImage

  • U-Boot用のカーネルイメージのファイル形式
  • U-Bootは、主に組み込み用途で使われるブートローダで、ネットワークブート(PXEクライアント)の機能を持つなど、高機能版のブートローダGRUBでネットワークブートをする場合は、おそらくNIC側のPXEクライアント機能を使う必要がある)

System.map

  • System.mapは、vmlinuxに対するnmコマンドの実行結果であり、カーネルに関するメモリアドレスと型、シンボルの対応テーブルを表す
  • nmは、実行形式のファイルやライブラリなどからシンボルテーブルを取得するためのコマンド
  • ブートに必要なデータではなく、Kernel PanicやOopsが発生した際のデバッグに使われる(実行時のメモリアドレスからシンボルを特定する)

kexec

  • カーネルを入れ替えるためにリブートする際、これらのブートシーケンスを行わず、ブートローダカーネルに制御を移した段階から始めることができるため、リブート時間を短くすることができる

カーネル

  • ハードウェアリソースに対応する初期設定やデバイスドライバの初期設定を行う
  • idleプロセス(PID=0)を起動する
  • initrd/initramfsを展開して、初期ルートファイルシステムをramfsとしてマウントする
  • [initrdの場合] /linuxrcを、一時的なinitプロセス(PID=1)として起動する
  • [initramfsの場合] /initを、一時的なinitプロセス(PID=1)として起動する
  • 初期ルートファイルシステムに置かれているカーネルモジュールをロードして、様々なファイルシステムでフォーマットされているパーティションを認識する
  • 初期ルートファイルシステムから、読み込み専用でマウントしたルートファイルシステムへマウントポイントを移す
  • [initrdの場合] 一時的なinitプロセスの終了後に、/sbin/initを実行して、initプロセス(PID=0)を起動する
  • [initramfsの場合] /initが、exec /sbin/initを実行して、initプロセス(PID=0)を起動する(execは現在のプロセスを別のプロセスで置き換える)

Systemd

  • /sbin/initは、現在systemdに置き換えが進んでおり、単に/sbin/initがsystemdへのシンボリックリンクになっているLinuxディストリビューションも存在する
  • systemdは、サービスの起動を並列に実行することによる起動処理の高速化、cronやxinetd(リソース効率化のため通信を検出した際にそのポートに対応するプロセスを起動するスーパーデーモン)に対応する機能の集約、cgroupによるリソース制御を用いたプロセスの優先度管理、などを行う

initプロセスが

  • /etc/inittabに書かれている通りrunlevelを設定し、該当する/etc/rc.d/rcXを実行する
  • スクリプトを実行する際は、forkによってinitプロセスがそのスクリプトを実行するプロセスの親プロセスとなる
  • 読み込み専用でマウントされたルートファイルシステムに対してfsckを実行*2し、実行後に読み書き可能で再マウントする
  • initプロセスが、/etc/fstabに書かれている通り各パーティションをマウントする

fstab - ArchWiki

runlevel

  • runlevelの定義はOSに依存するが、0:停止、1:シングルユーザ、2:マルチユーザ(ネットワーク無、Xディスプレイ無)、3:マルチユーザ(ネットワーク有、Xディスプレイ無)、5:マルチユーザ(ネットワーク有、Xディスプレイ有)、6:リブート、のパターンが多い
  • Sで始まるファイルは起動用スクリプト(S=Start)であり、Kで始まるファイルは停止用スクリプト(K=Kill)になる

*1:Unified Extensible Firmware Interface

*2:grubの設定ファイルでkernel(linux)コマンドに対して読み込み専用のモード(ro)が指定されているのはfsckを実行するため