2022年8月、ホームページを全面リニューアルしました! 情報を分かりやすくお伝えできるサイト作りを目指してまいります。

ディスクの構造とOSの起動!

OSの起動プロセスは、BIOSのロードから始まって、kernelのロード及びデバイスドライバーのロードまでを考えるとHDD上のデータ配置と密接に関係する。したがって、ディスクの構造も含め考えてみたい。


1.ディスクパーティション
PC/AT互換機の元々の仕様では、1つのハードディスクには、最大4つの基本パーティションを作ることが出来、さらに、基本パーティションの1つを拡張パーティションとして、その中を論理パーティションとしていくつでも区切ることが出来る。つまり、5つ以上パーティションが必要な場合は、必然的に拡張パーティションを利用することになる。例えば、Windowsを考えてみると、基本パーティションはCドライブのシステム領域で、アクティブにするブートパーディション(ブートセクター)もCドライブとなるので、基本パーティションを一つ作り、その他は拡張パーティションにして論理パーティションで複数に区切った方が効率的だ。
これらの基本・拡張パーティション情報は、ハードディスクの先頭セクターへ記録される。このセクターのことをMBR(Master Boot Record)と呼び、CD-ROMやFloppyDiskには無い構造である。
このMBRは1セクター(512バイト)の領域を有しており、MBRの後は62セクターの空きがあり、その後に基本パーティションが始まっている。
基本パーティションの先頭には、ブートセクター(1セクター分)が必ず配置される。さらに、拡張パーティションは、その中を論理パーティションに区切った、その先頭にEPBR(Extended Partition Boot Record)と言う論理パーティションの情報が記録されてる領域が作られる(図1参照)。

図1

2.MBRはディスクの管理人
MBRの構造は、どうなってるのだろうか?実際に、Debina GNU/Linuxが入っているホストで検証してみる。

1)プログラム領域(446バイト)
ブートに関するプログラムが記録されている。インストールされているOSによって異なったブートプログラムが書き込まれている。

2)パーティションテーブル(64バイト)
ここには、基本・拡張パーティションに関する情報が記録されていて4つのエントリ構成になっている。
■パーティションの位置
■パーティションの種類
■アクティブフラグ(このパーティションからブートするかの判断フラグ)

3)ブートシグネチャ(2バイト)
これは、このMBRが正しい情報かの判断するための情報が書き込まれている。通常 0xAA55 になっていて、これ以外の値だと、BIOSはこのMBRを無効と判断する。

実際に、ハードディスクのMBRをファイルに保存してのぞいてみることにする。以下は、Debian GNU/LinuxのMBRをファイルへ保存して、そのファイルを16進ダンプしたものである。

wirehork:~# df -m
Filesystem 1M-blocks Used Available Use% Mounted on
/dev/hdc1 13782 1727 11356 14% /
tmpfs 126 0 126 0% /lib/init/rw
udev 10 1 10 1% /dev
tmpfs 126 0 126 0% /dev/shm

wirehork:~# fdisk -l -u /dev/hdc

Disk /dev/hdc: 15.3 GB, 15377080320 bytes
255 heads, 63 sectors/track, 1869 cylinders, total 30033360 sectors
Units = sectors of 1 * 512 = 512 bytes

Device Boot Start End Blocks Id System
/dev/hdc1 * 63 28676024 14337981 83 Linux
/dev/hdc2 28676025 30025484 674730 5 Extended
/dev/hdc5 28676088 30025484 674698+ 82 Linux swap / Solaris

wirehork:~# cd /tmp/

wirehork:/tmp# dd if=/dev/hdc bs=512 count=1 > mbr.dat
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000214844 seconds, 2.4 MB/s

wirehork:/tmp# hexdump -C mbr.dat
00000000 eb 48 90 6c 62 61 4c 49 4c 4f 01 00 15 04 5a 00  |詒.lbaLILO….Z.|
00000010 00 00 00 00 89 aa af 45 24 46 b0 00 00 25 46 b0  |…..・E$F握.%F淫
00000020 00 00 23 46 b0 00 00 01 70 65 27 46 b0 00 00 28  |..#F握..pe’F握.(|
00000030 46 b0 00 00 de 45 b0 00 00 df 45 b0 00 00 03 02  |F握.淌握.濺握…|
00000040 ff 00 00 20 01 00 00 00 00 02 fa 90 90 f6 c2 80   |??. ……??.??.|
00000050 75 02 b2 80 ea 59 7c 00 00 31 c0 8e d8 8e d0 bc  |u.荻袮|..1成悽仄|

省略

00000160 7c be 85 7d e8 40 00 eb 0e be 8a 7d e8 38 00 eb  ||小}萓.覡小}荼.譛
00000170 06 be 94 7d e8 30 00 be 99 7d e8 2a 00 eb fe 47  |.小}莪.小}茯.譫G|
00000180 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 44  |RUB .Geom.Hard D|
00000190 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 00  |isk.Read. Error.|
000001a0 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00  |皿.堪柚・.u??…|
000001b0 00 00 00 00 00 00 00 00 90 90 90 90 90 80 80 01  |…………….|
000001c0 01 00 83 fe ff ff 3f 00 00 00 7a 8f b5 01 00 fe    |…????…z.貴.??
000001d0 ff ff 05 fe ff ff b9 8f b5 01 54 97 14 00 00 00    |??.????.貴T…..|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |…………….|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa  |…………..U・

上のデータで、初めの446バイトまで(0x0000~0x01BD迄)がプログラム領域で、ここを見るとこのLinuxシステムのブートローダーはGRUBが使われていることがわかる。しかし、初めの方でLILOと書き込まれているのは、更新前のブートローダーがLILOを使っていて、その残骸のようだ。

↓データの抜粋

000001b0                           80 01    |…………….|
000001c0 01 00 83 fe ff ff 3f 00 00 00 7a 8f b5 01 00 fe    |…????…z.貴.??
000001d0 ff ff 05 fe ff ff b9 8f b5 01 54 97 14 00 00 00    |??.????.貴T…..|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |…………….|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa  |…………..U・

上のデータで、先頭が0x80なので、この場合はアクティブパーティションになっている。次にパーティションテーブルのエントリー1の開始位置がリトルインディアン(数値データを1バイト単位で区切ったとき、会の桁から読み書きする方式)読みで0x000101(01 01 00)は、シリンダ0、セクター1、ヘッド1、つまり第2トラックとなる。

80 01 01 00 83 fe ff ff   3f 00 00 00 7a 8f b5 01  →   エントリー1
00 fe ff  ff 05 fe ff ff   b9 8f b5 01 54 97 14 00  →   エントリー2
                                    55 aa  →   ブートシグネチャ

元々、MBRはシリンダ0、セクター1、ヘッド0の1セクターのみの領域であるため、残りのシリンダ0、ヘッド0の領域(セクター2~セクター63迄)は何も使われてない空き領域となる。何だかもったいない気もするが、PC/AT互換機の仕様では、第1パーティションは第2トラックから始まらなければいけない仕様になっているようだ。さらに、パーティションタイプは、上記のエントリー1に0x83が書き込まれているので、第1パーティションはLinux Native(ext3)、エントリー2に0x05が書き込まれているので、第2パーティションは拡張パーティションを表している。
また、同じく上記のエントリーに対して、LBAアドレッシングでのパーティション開始位置とパーティションの総セクター数を見てみると、第1パーティションの開始位置は0x0000003F(63)、総セクター数は0x01B58F7A(28675962)、第2パーティション開始位置は0x01B58FB9(28676025)、総セクター数は0x00149754(1349460)となっている。
最後に、0xAA55でブートシグネチャで、このMBRは正しいものである、と言っている。
上記のMBR情報では、基本パーティション(MAX4つ)だけしか記録されない。と言うのも、拡張パーティション内の論理パーティション(いくつでも作れる)情報はMBRではわからない。そこで、論理パーティション情報を知るために、EPBR(Extended Partition Boot Record)と言う拡張パーティション内の先頭1セクターの情報を見てみよう。構造的には、MBRと全く同様である。

wirehork:/tmp# dd if=/dev/hdc2 bs=512 count=1 > ebr.dat
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.0189323 seconds, 27.0 kB/s

wirehork:/tmp# hexdump -C ebr.dat
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |…………….|
*
000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe  |……………??
000001c0 ff ff 82 fe ff ff 3f 00 00 00 15 97 14 00 00 00    |??.????………|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |…………….|
*
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa  |…………..U・
00000200

↓データ抜粋

                                 00 fe    |……………??
000001c0 ff ff 82 fe ff ff 3f 00 00 00 15 97 14 00 00 00    |??.????………|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |…………….|
*
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa  |…………..U・

00 fe ff ff 82 fe ff ff 3f 00 00 00 15 97 14 00   →  エントリ1
                                 55 aa   →  ブートシグネチャ

上のデータで第1論理パーティションタイプが0x82が書き込まれているので、LinuxSwap・Solarisを表している。さらに、パーティション開始位置は0x0000003F(拡張パーティションの先頭から63)で、総セクター数は0x00149715(1349397)となる。そして、最後にブートシグネチャがあって、このEPBRは正しいものである、と言っている。


3.BIOSのお仕事
図2は、BIOSの仕事の流れである。PC/AT互換機では、電源を入れてから、まず初めに起動させるプログラムが有る。それは、BIOS(Basic Input/Output System)である。BIOSは、PCの中にあらかじめ用意されている。BIOSは必要最小限の小さなプログラムだ。当たり前だが、BIOSでは自分がどのようなOSでどんなファイルシステムであるかまではわらないが、デバイスへの物理的なアクセスは出来るので、セクター番号を指定して、有るセクターのデータをメモリへロードすることは可能である。つまり、デバイスというデバイス全てに対して、BIOSのプログラムだけでセクターリードが可能だ。
では、早速、BIOSの仕事を見てみよう。まず、BIOS自体をメインメモリへロードする。ロードしたBIOSが実行される。BIOSが実行されたら、CPU周りのメモリ、IO等の自己診断テストを行う(例えば、メモリではあるデータを全ての番地へ書き込み・読み込みを繰り返す)。
次に、ハードディスク・FDD・ストレージ・グラフィックボード・キーボード等のデバイスの初期化を行う。例えば、起動デバイスにハードディスクが設定されている場合などは、ハードディスクの先頭セクター(MBR)をリードして、510 バイト目のブートシグネチャをチェックしに行く。前項で説明したように、ブートシグネチャが正しい値(0xAA55)だった場合、先頭セクターに書き込まれている起動プログラムをキックする。また、そうでなければ、次に設定された起動ドライブをリードしに行く。さらに、全てのドライブでリードが行えないとすると、エラーとなりPCはHALT(停止)状態になる(図2参照)。

図2

ハードディスクからの起動の場合、MBRのプログラム領域に書き込まれているプログラムは、ブートストラップと言いLinuxで言うとGRUBのようなプログラムを言う。通常ブートストラップは、ドライブのアクティブなパーティションの先頭番地からロードするようになっている。パーティションの先頭にはIPL(Initial Program Loader)が設置してあり、OSのコアシステムをロードする。つまり、Linuxで言うとカーネルがロードされるわけである。
以上

コメント