当記事ではLinuxの起動の流れについてまとめています。取り扱う内容の関係上、Linux以外のOSにも関わる話が含まれます。
はじめに
LPI-Japanが管理する資格「LinuCレベル1 Version 10.0」受験のために勉強する過程でLinuxの起動の流れについて調べました。当記事では調べた内容をまとめています。
BIOSの起動
PCの電源を入れると最初に起動するのが「Basic Input/Output System」(BIOS)というプログラムです。Award Software InternationalやAmerican Megatrends Incorporatedといった企業のものが有名らしいですが、マザーボードのメーカー(?)などが独自のBIOSを作っていることもあるそうです。
BIOSはマザーボードに直付けされている「BIOSチップ」などと呼ばれるストレージ部品のなかにインストールされています。メーカーからBIOSのアップデートプログラムが配布されることがありますので、それを適用することなどはできますがBIOSを削除したり再インストールしたりというのは一般的なPCユーザーの機材ではできないようです。少し調べたかぎりでは、半田ごてでマザーボードから取り外したうえで、専用の機材でBIOSを入れて、それから再びはんだ付けするということで電子工学的な技術と設備が求められるっぽいです。
BIOSの種類
BIOSには古くから存在する規格に基づいて実装される旧型BIOSと、2005年に登場した「Unified Extensible Firmware Interface」(UEFI)という規格に基づいて実装される新型BIOSの2種類があります。両者の呼び分けとしては「Legacy BIOS」「UEFI BIOS」とする場合と「BIOS」「UEFI」と呼び分ける場合があります。
日本ではLegacy BIOSとUEFI BIOSを別物として扱うケースが多いように思われますが、いくつかの資料や英語圏の記事などを読んだかぎりでは、あくまでもBIOSの世代の違い・種類の違い・規格の違いと捉えるのが適当であると考えます。「Java 8」と「Java 9」を別の言語と見なさないように、Legacy BIOSとUEFI BIOSも同じBIOSであると考えるのが妥当でしょう。
Legacy BIOSとUEFI BIOSの違いは色々ありますが、それについては今後の解説のなかで必要に応じて都度触れていきます。基本的にはUEFI BIOSのほうが優れていると考えていただいて結構です。
BIOSの役割
BIOSの役割・機能は大きく3つあります。
1つ目は、コンピューターに接続されている各種デバイスの初期化です。ただし、ここで確実に初期化できるのはキーボードやマウスといった基本的なデバイスだけで、プリンターやWebカメラといった特殊なデバイスは原則としてOS起動後にOSがデバイスドライバーを介して初期化する必要があります。これはBIOSチップという限られたストレージ内に、さまざまなデバイス用の制御プログラムを詰め込めない事情が関係しているようです。
例外として、UEFI BIOSの場合はUEFI BIOS用のデバイスドライバーというものがあるらしいので、それが使える状態ならば特殊なデバイスにも対応できる可能性があります。ちなみに、デバイスドライバーというのはOSがハードウェアを制御するためのプログラムの総称です。デバイスドライバーといえばOS用のものしかないと思っていたので、まさかBIOS用(厳密にはUEFI BIOS用ですが)のデバイスドライバーがあるとは驚きでした。
2つ目は、OSがハードウェアを制御するときの橋渡し・インターフェースとしての活用です。キーボードやマウスの操作による影響をOSやOS上で動作するアプリに伝達する、あるいはその反対のことをするとき、OSはBIOSにその処理を依頼することができます。これを「BIOS interrupt call」(BIOS割り込みルーチン)と言います。
ただ、BIOSを介したハードウェア制御は動作速度が遅いという欠点があるうえ、繰り返しなりますが、BIOSチップという限られた容量のなかに年々増加の一途を辿るさまざまなデバイス用の制御プログラムを詰め込むのは現実的ではないといった理由などから、近年ではOSがデバイスドライバーを介して直接ハードウェアを制御するのが一般的になっているようです。
つまるところ、OSが起動してデバイスドライバーを使ってハードウェアを制御できるまでの間に必要なハードウェアだけ初期化できれば良いということなのでしょう。
3つ目は、「Boot device」(ブートデバイス、あるいはブートメディアとも)の探索と「Bootstrap lodear」(ブートローダー)の起動です。
ブートデバイスとはコンピューターを立ち上げたときに最初に動かしたいプログラムが入っているストレージです。ほとんどのコンピューターの場合、最初に動かしたいプログラムはOSであるため、ブートデバイスとは「起動したいOSが入っているストレージ」と言っても過言ではないでしょう。
例えば、私のPCには256GBのSSDと128GBのSSDが1つずつ接続されており、256GBのSSDのほうにWindows 10 Homeが入っています。よって、私のPCにとってのブートデバイスはこの256GBのSSDということになります。あるいは、私のAndroidスマートフォンは128GBの内部ストレージと64GBのSDカードで構成されています。Androidがインストールされているのは内部ストレージのほうであるため、私のスマートフォンにとってのブートデバイスはスマートフォン内部のストレージということになります。
ブートデバイスは複数指定することができ、その場合は起動の優先順を設定する必要があります。この設定はBIOSの設定画面から行う必要があります。
BIOSがブートデバイスを見つけると、ブートデバイスにインストールされているブートローダーを探して起動します。
ブートローダー
ブートローダーは起動するOSの探索と起動を行うプログラムです。BIOSからOSを直接起動することは技術的に可能らしいですが、その場合はBIOSにさまざまなOSに対応したOS起動用プログラムを組み込む必要があります。そうなると必要以上にBIOSが複雑になるなどの理由から、OSの起動はブートローダーという専用のプログラムに任せる仕組みが採用されるようになったようです。
ところで、前述のとおりブートローダーはOSを起動させるプログラムを指す総称です。ここで左記定義を鑑みますと、BIOSもOSの起動に関わっているといえば関わっていますのでBIOSもブートローダーの一種と見なすことがあります。その場合はBIOSを「1次ブートローダー」、ブートローダーを「2次ブートローダー」と呼び分けます。ただ、日本語圏・英語圏ともにそのような呼び分けをするケースというのは多くないっぽいので、原則「ブートローダー」といえば「2次ブートローダー」を指すと考えて問題ありません。
ブートローダーにはいくつかの種類があります。Windowsシリーズでは古くは「NT OS Loader」、現在は「Windows Boot Manager」というものが使われているようです。macOSシリーズでは「BootX」というものがかつては標準搭載されていたようですが、現在は別のものに切り替わったみたいです。名称は分かりませんでした。Linuxでは「GNU GRUB」が一般的に使われます。厳密には「GRUB Legacy」と「GRUB 2」の2種類があり、現在はGRUB 2が広く使われています。
ブートローダーの挙動
ブートローダーはHDDやSSDにインストールされるプログラムです。
BIOSは予め設定されているブートデバイスの起動順に従ってブートデバイスを探していき、そのなかにあるブートローダーを呼びだします。厳密には「ストレージの先頭にあるアドレスを読んで実行する」のですが、ブートローダーを呼びだしていると考えて大きく差し支えないでしょう。
BIOSによってブートローダーが実行されると、ブートローダーは自身の設定に従ってOSの探索と起動を行います。ブートローダーはさまざまな団体・企業がそれぞれに独自のものを開発しており、細かい仕様こそ異なりますがおおまかな挙動は同じはずです。
パーティショニング
まず、ブートローダーは自身がインストールされているストレージがどのように「Disk partitioning」(パーティショニング)されているかを判別します。パーティショニングとは1つのストレージを複数の「Partition」(パーティション)という区切りに分ける機能、およびパーティションを管理する機能のことです。
パーティション
パーティションは、前述のとおり、1つのストレージ内を区切る仕切りです。パーティション1で何らかの障害が起きるとパーティション1に保存されているデータ全てに影響を及ぼす恐れがありますが、パーティション2には影響を与えません。それはパーティションという区切りがあるおかげです。また、パーティションという仕組みがあることで1つのストレージに複数のOSをインストールし、起動時にどのOSを起動するか選ぶことができるようになっています。
このように便利なパーティションですが、分けるときに一定のデッドスペースが生じてしまうようです。そのため、パーティションをあまりに細かく分けすぎるとストレージの容量を十分に活かすことができなくなる可能性があります。また、後述するパーティショニングの規格によって、1つのストレージ内に作成できるパーティションの数にも制約があるため、必ずしも無限に分割できるわけでもありません。
パーティショニングの種類
パーティショニングには「MBR」(Master boot record)と「GPT」(GUID Partition Table)という2つの規格があります。
MBRは1983年に登場した古い規格です。取り扱うことができるストレージの容量は2TBまでという制約があり、1つのストレージ内に4つまでパーティションを作ることができます。OSの処理によって、1つのパーティションのなかに複数のパーティションがあるかのように振舞わせることもでき、その場合は1つのストレージ内に4つまでしか作れないという制約を無視できますが、あくまでも「振る舞っている」だけであり正式なパーティションの数は4つまでです。
前述の正式なパーティションを「Primary partition」(基本パーティション、プライマリパーティションなど)と言い、疑似的なパーティションを「Logical partition」(論理パーティション)と言います。また、4つまで作れる基本パーティションの1つを論理パーティション用に充てる必要があるわけですが、この基本パーティションは「Extended partition」(拡張パーティション)と呼ばれます。
色々と制約が多いMBRに対して、GPTはUEFI BIOSの前身となる規格である「Intel Boot Initiative」や「Extensible Firmware Interface」策定の一環で考案された新しいパーティショニングの規格です。
取り扱うことができる1つのストレージの容量は8ZB(800万TB)へと大幅に増えたほか、パーティションの生成数制限も規格上は無くなり無限に作ることもできるようになりました。ただ、OSごとに取り扱うことができるパーティションの上限数は決まっているようで、例えばWindowsの場合は1つのストレージあたり128個までという制限があります。基本的にはGPTのほうが優秀なわけです。
パーティショニングとBIOSの関係
MBRとGPTは対応しているBIOSにも違いがあります。Legacy BIOSはMBRに対応しており、UEFI BIOSはGPTに対応しています。
ただ、後方互換性の観点からUEFI BIOSにはLegacy BIOSのように振る舞わせることができる「Compatibility Support Module」(CSM)という機能があり、左記機能を利用した場合はMBRを起動することも可能になっています。ただ、UEFIという規格の生みの親といえるIntelとしてはCSMを廃止してMBRとの互換性を無くしたいみたいです。
ブートローダーがOSを探すまでの流れ
ブートローダーは自身が管理するパーティションの数を把握すると、それらパーティションのなかでOSの起動に関するプログラムが入っているパーティションを探します。OS起動用プログラムを入れることができるのは基本パーティションだけで、拡張パーティションには入れることができません。言わずもがな、論理パーティションはそもそもOSが起動していないと論理パーティションと見なされませんのでこちらにも入れることはできません。
ブートローダーの設定にもよりますが、OS起動用プログラムが1つだけしかない場合はそのOSを自動的に起動させます。複数のOSが見つかった場合は、起動するOSを選ぶメニュー画面を表示することでユーザーが起動するOSを選べるように案内します。このように1つのストレージに複数のOSが入っている状態を「Multi booting」(マルチブート)などと言います。
init
ここまでやって、ようやくLinuxが起動するわけですがまだログイン画面は表示されません。
Linux上で動くプログラムは「プロセス」という単位で管理されるのですが、それらプロセスのなかで最初に起動し、プロセス全体を統括制御するプロセスを「init」と言います。initは自身の設定に従って各種プロセスを順番に起動していき、それら全ての起動処理が完了したら、ようやくログイン画面を出してくれます。
initの役目は起動時の初期処理のみならず、各種プロセスの管理も担います。大抵のプロセス――もといプログラムには、そのプログラムを制御するために用意された専用のコマンドや設定ファイルがあるのですが、それらを使わずinitの権限・機能を使ってプログラムを実行したり停止させたりすることができます。細かい操作については各プログラムが用意するAPIを使うことになります。
また、initは電源周りの制御も担っています。Linuxにはさまざまな電源操作コマンドが用意されているのですが、それらは全てinitを呼びだすかたちを採っています。例えば、有名な電源操作コマンドに shutdown
がありますが、これも内部の処理的にはinitを使って電源操作しているプログラムになります。
initの種類
initは最初に起動するプロセスの名前であり、最初に起動してLinuxの初期化や電源周りの管理などを担うプログラムを指す言葉でもあります。そんなinitにはいくつかの種類があります。
最初期に使われていたのは、Linuxの元になったOSであるUnixのバージョンの1つである「Unix System V」に搭載されていたものでした。このinitには特に名前が付けられていなかったため、現在では他のinitと区別するために「SysV init」などと表記されることがあります。
しかしながら、当記事執筆時点ではSysV initを採用したLinuxディストリビューションというのは主流ではなく、2010年3月30日に登場した「systemd」という改良版に置き換えられているケースが散見されます。
SysV initとsystemdは機能・性能に違いがある他、initを制御するためのコマンドの構文にも違いがありますので、これからLinuxを学ぼうとしている人はSysV init時代に書かれた書籍や記事を参考にしないように注意してください。また、他にもいくつかinitがありますのでinitについて勉強したり、操作するときは一応注意ください。
おわりに
以上がLinux起動までのざっくりとした流れになります。結構省いているところが多いため、気になった点などありましたら各自で調べてみてください。