LoginSignup
9
5

【Linux】OSブートの仕組み

Last updated at Posted at 2023-07-05

たまにカーネル周り触っててわからなくなるのでまとめておく。
前提として超基本的なところ

コンピュータの五大装置

入力:コンピュータに命令を与える。キーボード,マウス
記憶:コンピュータ内の情報を格納し、記憶しておくメモリ、※補助記憶装置⇒HDD,SSD
演算:CPU内にあり、算術演算(四則演算)や論理演算(andやor)などの計算を行う装置
制御:CPU内にあり、記憶装置から読み込んだプログラムを解釈し、コンピュータ全体の動作を制御。
出力:コンピュータの処理結果を出力する。(モニター、スピーカー、プリンタ)
 ※装置間のデータや制御はマザーボードで繋がっている

image.png
(https://academy.gmocloud.com/know/20150413/929 より)

CPU

(中央処理装置:Central Processing Unit)の略。
演算装置:レジスタにあるデータを0/1で計算。ALU(ArithmeticLogicUnit=算術論理演算装置)など。
レジスタ:すばやく演算するためにメモリからデータを保持。CPUはここのデータしか処理できない
制御装置:メモリからレジスタへのデータのやり取りなど、全体の動きをコントロール
クロック:1秒間隔で信号を出し、作業タイミングを合わせる指揮者。2GHz⇒1秒で20億回処理
 ⇒発熱などにより性能に限度があるため、コアを増やすことで向上できる。(2コア,4コア等)

スペック例はこんな感じ
Intel Xeon Platinum 8352V 2.1GHz 1P36C CPU x 2CPUs
⇒ 1CPU(プロセッサ/ソケット) に 36コア搭載されていて、それが2つ付いてる。
※ハイパースレッドが有効化だと36コア72スレッドとなるので、論理プロセッサは144となる。

コアやスレッドに関しては以下サイトがわかりやすい。
https://chimolog.co/bto-cpu-core-thread/

メモリ

RAM:データを読み書きするための作業机。Random Access Memory
 ⇒SRAM:フリップフロップ回路。電源ONであればデータは消えない。CPUとメインメモリの間でキャッシュメモリとして使用され、高速でデータをやり取りできる。
 ⇒DRAM:コンデンサ。時間の経過と共にデータが消えるため、上書き=リフレッシュが必要。メインメモリで使用される。

メモリに関しては以下の記事がとてもわかりやすいです。
https://qiita.com/kunihirotanaka/items/70d43d48757aea79de2d

ディスク

大きくは従来型のHDD(hard disk drive)SSD(solid state drive)に分かれる。
SSDはUSBメモリと同じくNAND型フラッシュメモリを用いたストレージで、仕組上は従来のHDDではなくメモリに近い、いわばメモリの不揮発版といえる。

HDD

HDDは、その性能とインターフェース規格の違いからSATASASに分類され、ともに大きさの違いから3.5インチ、2.5インチという2つの規格がある。
SASは"シリアルSCSI"とも言われ、SATAと比べて高速・高信頼の設計で、主に企業の重要なシステムで使用されるHDD。その分高価。
⇒高速というメリットは、SSDの普及によりなくなりつつある

SSD

接続インターフェースで規格を分けると、NVMe、SATA/SASに分かれる。
アクセス速度が高速なSSDの能力を生かせるのはNVMeの方だが、対応する機器が少ない上に高価である。

RAID

RAIDカードを搭載することで、サーバでは一般的に使用されるRAID機能を使用できる。

RAID0 ⇒ ストライピング。1つのデータを2台のHDDに分散して読み書き。1台壊れると使えなくなる。速度重視。
RAID1 ⇒ ミラーリング。2台のディスクにそれぞれ同じデータを同時に書き込む。安全性重視。
RAID5 ⇒ "パリティ"と呼ばれる冗長コードを全ディスクに分散して保存。同時に2台以上が壊れると回復不可能になる。
RAID6 ⇒ RAID5にもう1つ独立したパリティを追加し信頼性を向上。同時に2台のディスク装置が故障してもデータ修復が可能

なお、OS(Linux)上からHW周りの情報を確認する方法は以下にあります(宣伝)

OSブートシーケンス

ここから本題。

1.電源を入れる

ポチっと

2.マザーボード上のBIOS/UEFI起動

現在はUEFIが主流。マザーボードの内臓チップに組み込まれている小さなプログラム

3.BIOS/UEFIによるハードウェアの認識・初期化

POST(Power On Self Test)でCPUやメモリ,接続されている各種拡張カード等をチェック/初期化する。
ブートデバイス(HDD、CDROM、USB)等を認識する。

4.ブートローダー起動

BIOS/UEFIが認識されたブートデバイス(HDD等)に記録されているブートローダー(起動プログラム)を読み込む。

BIOS:
マザーボード上のNVRAMに格納されたFW。電源を投入すると設定されたデバイスの優先順位に従って、ディスクの先頭ブロックにあるMBR内のブートローダーを検索して最初に検知したデバイスブートローダーを起動する。MBRは下記のような構造になっている。
①ブートローダ (446B)
②パーティションテーブル (64B)
③Boot Signature (2B)

UEFI:
NVRAMのブートエントリーに設定された優先順位に従って、GPTで管理しているUEFIシステムパーティション(ESP)に格納されているブートローダーを起動する。EFIシステムパーティションはFAT(またはVFAT)でフォーマットされ、/boot/efiディレクトリにマウントされる。

LinuxではGRUBまたは後継のGRUB2というブートローダーが採用されている。

5.カーネルとinitramfsを読み込む

ブートローダー(GRUB Legacy/GRUB2)がカーネル(vmlinuz)とinitramfsをメモリにロードし、カーネルを起動する。

■GRUB Legacy

・Stage1
=ブートローダがブート可能なストレージデバイスから読み込む最小限のコードセット。

・Stage1.5
=ディスク上のファイルシステムを解釈し、Stage2をロードする。ディスク上ではMBRと最初のパーティションの間に存在する。

・Stage2
=GRUBの本体。メモリにロードされたカーネルイメージを読み取り、初期RAMディスク(initramfs)をロードする拡張セット

Stage2のプログラムが設定ファイル/boot/grub/menu.lstを読み、その記述に従ってカーネルとinitramfsをメモリにロードする。
①セクタ番号1にあるStage1ではMBRの0x44~0x47領域に記載されているStage1.5かStage2のブロック番号を読み取る
②stage1.5の場合はstage2をファイルシステムとして読み込む。
/boot/grub/stage2はmenu.lstを読み込む
/boot/grub/menu.lstの記述内容に従って、カーネルとinitramfsをメモリに読み込む

/boot/grub/menu.lst
boot=/dev/sda    #ブートデバイスの定義。GRUBのインストール先
default=0        #デフォルトで起動するエントリ番号。デフォルトは1番目のエントリ
timeout=5        #メニューを表示する時間。デフォルトは5秒
hiddenmenu       #起動時に選択メニューを表示しない
splashimage=(hd0,0)/grub/splash.xpm.gz    #メニューの表示画面の画像
title CentOS (2.6.32-358.el6.i686)        #メニューに表示されるエントリ名。1番目のエントリ
root (hd0,0)     #ルートファイルシステムの指定。GRUBでは、/dev/sda1を(hd0,0)、/dev/sdaを(hd0,1)と表示
kernel /vmlinuz-2.6.32-358.el6.i686 ro root=UUID=15a29eb8-6f0c-4e3b ~ quiet    #起動するカーネルイメージファイルと起動オプションの指定
initrd /initramfs-2.6.32-358.el6.i686.img    #初期RAMディスクファイルの指定

■GRUB2

GRUB LegacyであったStage1~2がない代わりにboot.imgcore.img、動的にロードされる複数のモジュールで構成される。
以下はBIOSの場合
①セクタ番号1にあるboot.imgを読み込む
②セクタ番号2~64のcore.imggrub.cfgをもとに少数のモジュールを動的リンクする
③その後GRUBを起動し、カーネルとinitramfsをロードする

UEFIの場合はEFIパーティション内の FAT32 ファイルシステム上にあるshim.efiというブートローダを呼び出す。

■GRUB2-設定ファイル

設定ファイルは以下。
/boot/grub/grub.cfg:設定ファイル(BIOS)
/boot/efi/EFi/centos/grub.cfg:設定ファイル(UEFI)
/usr/lib/grub/i386-pc:モジュールの置かれたディレクトリ
/etc/grub.d:設定ファイル grub.cfg の生成時に実行するスクリプトが置かれたディレクトリ

/boot/grub/grub.cfg(抜粋。BIOS起動の場合)
set root='hd0,msdos1'          #ブートするカーネルと initrd の置かれルパ=ディションとディスクを ‘ディスク,パーティション’ で指定
linux /bootvmlinuz-3.9.5 root=/dev/sda1 ro    #カーネルと引数を指定。ランレベルを追加すると指定したランレベルで立ち上げる。GRUB1ではkernelで始まり、GRUB2ではlinuxで始まる
initrd /boot/initramfs-3.9.5.img    #initramfs を指定。GRUB1ではパーティションは0始まり、GRUB2では 1で始まる

ディスクとデバイス名との対応は/boot/grub/device.mapに格納されている。

/boot/efi/EFi/centos/grub.cfg(抜粋。UEFI起動の場合)
set root='hd0,gpt2'
linuxefi /vmlinuz-3.10.0-1160.el7.x86_64 root=UUID=6a4853a1-61c8-486c-8177-966ad3cb2cba ro
initrdefi /initramfs-3.10.0-1160.el7.x86_64.img

※上記で設定は確認できるが、GRUB2の設定ファイルは直接編集NG。設定を変更したい場合は/etc/default/grubを修正し、grub-mkconfigコマンドにて反映する必要がある。

/etc/default/grub
GRUB_TIMEOUT=5    #デフォルトのOSを起動するまでの秒数
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"    #メニューエントリに表示するコマンド
GRUB_DEFAULT=saved    #デフォルトで起動するOSの番号またはメニュータイトル。savedは前回起動したもの
GRUB_DISABLE_SUBMENU=true    #全てのOSをフラットメニューで並べる
GRUB_TERMINAL_OUTPUT="console"    #コンソール出力する
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet"    #カーネルに渡すブートオプション
GRUB_DISABLE_RECOVERY="true"    #メニューにリカバリモードを表示する

反映コマンド

grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg

GRUB_CMDLINE_LINUXの変更が適用されているかは、以下コマンドで確認可能

cat /proc/cmdline

上記設定により表示されたブートメニューより、ユーザがどれか1つのOSを選択すると、ブートローダはそのOSのカーネルの実体バイナリvmlinuz-*と RAMディスクinitramfs-*.imgをメモリ上にロードし、カーネル本体の先頭アドレスにジャンプした後、自身の初期化シーケンスを実行する。

6.カーネルが初期RAMディスク(initramfs)を読み込む

・カーネルが自身の初期化処理を終えると、cpioでアーカイブされgzipで圧縮されたinitramfsをメモリ上に展開し、一時的なルートファイルシステムとしてマウントする。

※initramfsは、ルートディレクトリをcpioという形式でアーカイブし、gzipで圧縮したもので、/bin /lib /dev などのディレクトリがあり、それぞれのディレクトリには必要最低限のコマンドやデバイスファイルなどが含まれている。小さなLinuxシステムであるともいえる。
実際に/bootにあるinitramfsの中身は以下コマンドで確認できる。

zcat initramfs-xxx.img | cpio -idv

また、レスキューブートからのdracutコマンドでinitramfsを自前で作成することも可能。

※例
mount --bind /proc /mnt/sysimage/proc
mount --bind /dev /mnt/sysimage/dev
mount --bind /sys /mnt/sysimage/sys
chroot /mnt/sysimage/
cp /boot/initramfs-4.19.14-300.fc29.x86_64.img /boot/initramfs-4.19.14-300.fc29.x86_64.img.bak
dracut -f /boot/initramfs-4.19.14-300.fc29.x86_64.img 4.19.14-300.fc29.x86_64

lsinitrd imageFILEコマンドで中身の確認もできる。

7.initプロセス実行

・initramfsをマウントしたカーネルは、initramfs内のinitからシンボリックリンクされたsystemdを起動し、以下の流れで処理を行う。

initramfs の /initコマンドが実行される。
①/bin/mknod コマンドにより必要なデバイスファイルを作成
②/bin/mkdir コマンドにより/tmp、/proc、/sys、/devなど必要なディレクトリを作成
③/bin/mount コマンドにより擬似ファイルシステムをマウント
④/bin/mount コマンドによりディスク内のルートファイルシステムを/sysrootにマウント
⑤/sbin/switch_root コマンドによりinitramfsからディスク内のルートファイルシステムに切り替え

※SysV initの場合: initramfs内のinitを起動し、ディスク内のルートファイルシステムをマウントする

8./sbin/initを実行し、起動シーケンスを開始

・カーネルは切り替えたディスク内のルートファイルシステムの/sbin/initを実行し、シンボリック先の/lib/systemd/sytemdを再実行して各ユニット設定ファイルを参照し起動シーケンスを開始する。
Initは実行される最初のプロセスであり、PIDは常に1となる。

※SysV initではディスク内のルートファイルシステムの/sbin/initを実行し、/etc/inittabを参照して起動シーケンスを開始する

※ブートシーケンス内でsystemdは2回起動されることになる。
initramfs内のsystemdはプロセス空間を制御し、必要なファイルシステムをマウントするために必要である一方、ディスク内のsystemdはシステムを完全に起動し、サービスを管理するために必要。

カーネル起動中のメッセージはdmesgコマンドで確認できる。

9.ターゲットにしたがってサービスを起動する

systemdでは、Unitという考え方が採用されており、OS の起動シーケンスの起点となるdefault.targetに記述されている依存関係を満たすように、各種ユニットを立ちあげる。(udev によりハードウェアを扱えるようにしたり、各種デーモンなど他のプロセスを実行する)

はじめに/etc/systemd/system/default.targetを読みに行くことで指定されたターゲットで処理される。
また以下コマンドで、default.target を起点としてそこから要求される形でどのようなユニットが起動されたかを確認できる。

systemctl list-dependencies

※SysV initではランレベルとなる。

10.ログインプロンプト/ログイン画面からログインする

ここでようやくいつものログイン画面へ

インストールって?

前述④のブートデバイスが外部インストールメディアか、ネットワーク経由でのPXEかとなる。
簡単な流れは以下の通り。

1.OSインストーラーをメモリにロードする。
2.インストーラを起動し、インストールするHDD/SSDを指定する。
3.指定したHDD/SSDをファイルシステムにフォーマット(xfs,ext4など)
4.ブートセクタの作成及びOS機能を提供するプログラムやライブラリファイルをファイルシステムにインストール(配置)

インストール後はマシンを起動すると前述④のブートデバイスが配置したHDD/SSDのブートセクタからブートローダをメモリに展開し、以降の流れは同じ。

PXEブートって?

PXE (Preboot eXection Environment) はネットワークブートのプロトコル。クライアントがネットワーク上のサーバーからNetwork Bootstrap Program (NBP)をダウンロードし、NBPがカーネルとinitramfsをダウンロードして起動する。
以下の流れ。NBPファイルはメモリ上にロードされ、ディスクには保存されない。

クライアントの PXE 対応 NIC からサーバーへ DHCP リクエスト
サーバーから IP アドレスと NBP ファイル名を取得
クライアントからサーバーへ NBP ファイルを TFTP リクエスト
サーバーから prelinux.0 をダウンロード
NBP ファイル (prelinux.0) を起動して TFTP リクエスト
サーバーから vmlinnuz と initramfs をダウンロード

以上。

参照

LPICレベル2 赤本
https://www.ether-zone.com/learning-lpic-2-3/#toc2
https://qiita.com/taichitk/items/b3b69705be0e270e9f6e
https://www.tomoyan.net/linux/dracut

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5