BPBの復習

結局、この辺に戻ってくるらしい。

例えば、最新の環境でUSBメモリの読み書きを行おうとしても、

FAT32がデファクトスタンダードであるので、全く無視する訳にもいかない。

とは言え、ほとんどが、後方互換の為に残されている物であって、

現在のOS事情においては、参考程度の情報かもしれない。

BPB (BIOS Parameter Block)

FAT12の時代からある、予約領域の先頭セクタに配置されるデータ構造。

ボリュームに関する諸情報が格納されている。

ブートローダーを含む場合は、

VBR (Volume Boot Record) や PBR (Partition Boot Record) などとも呼ばれる。

BS_から始まる名前は、ブートセクタの要素。

BPB_から始まる名前は、BPBの要素。

 

FAT12/16/32共通

名前 オフセット サイズ 内容
BS_JmpBoot 0 3

ブートストラップコードへのジャンプ命令(x86命令)。

0xEB, 0x??, 0x90 (ショートジャンプ+NOP)
0xE9, 0x??, 0x?? (ニアジャンプ)

一般的には、前者。

BS_OEMName 3 8

OEM名識別⼦。

任意の値で良いが、互換性を重視する場合、

"MSWIN4.1"や"MSDOS5.0"が使われる。

BPB_BytsPerSec 11 2

セクタあたりのバイト数。

512、1024、2048、4096のいずれか。

ストレージのセクタサイズと同一になる。

互換性を重視する場合、512が、最も安全性が高い。

BPB_SecPerClus 13 1

クラスタあたりのセクタ数。

0より大きい、2の累乗でなければならない。

要するに、8bit中、いずれかのbitが1となる。

互換性を重視する場合、

セクタサイズは、32Kバイト以下が望ましい。

BPB_RsvdSecCnt 14 2

予約セクタ数 (FAT1領域の直前までのセクタ数)

0以外、任意の値を設定可能であるが、

互換性を重視する場合、

FAT12/16では、1が望ましく、

FAT32では、主に32とする事が多い。

BPB_NumFATs 16 1

FATの数。

互換性を重視する場合、常に2が望ましい。

BPB_RootEntCnt 17 2

FAT12/16における、

ルートディレクトリエントリの最大数。

32倍して、2セクタ分の倍数となる必要がある。

互換性を重視する場合、

FAT16では、512とする事が望ましい。

FAT32では、常に0。

BPB_TotSec16 19 2

全セクタ数(古い16ビットフィールド)。

FAT12/16では、セクタ数が0xFFFF以下の場合有効。

0x10000以上の場合は、0。

FAT32では、常に0。

BPB_Media 21 1

固定ドライブの場合、0xF8が標準。

リムーバブルメディアの場合、0x0Fが多い。

これと同じ値をFAT[0]の下位8bitに置く。

BPB_FATSz16 22 2

一つのFATが占めるセクタ数。

FAT12/16でのみ有効。

FAT32では、常に0。

BPB_SecPerTrk 24 2

トラックあたりのセクタ数。

現在では、ほとんど意味がない。

BPB_NumHeads 26 2

ヘッド数。

現在では、ほとんど意味がない。

BPB_HiddSec 28 4

隠しセクタ数。

パーティション分割されていない場合、常に0。

現在では、ほとんど意味がない。

BPB_TotSec32 32 4

全セクタ数(新しい32ビットフィールド)。

FAT12/16では、セクタ数が0x10000以上の場合有効。

0xFFFF以下の場合は、0。

FAT32では、常に有効。

 

FAT12/16 (オフセット36以降)

名前 オフセット サイズ 内容
BS_DrvNum 36 1

ドライブ番号。

INT13hで使用。

フロッピーディスクでは、0x00、

固定ディスクでは、0x80。

BS_Reserved 37 1

予約。

WindowsNTで使用されているらしい?

通常は、0x00を設定。

BS_BootSig 38 1

拡張ブートシグネチャ。

続く2つのフィールドが有効な場合、

0x29を設定する。

BS_VolID 39 4

ボリュームシリアル番号。

不正なメディア交換を検出する為のヒント。

大抵は現在時刻から生成される。
BS_VolLab 43 11

ボリュームラベル。

ルートディレクトリのボリュームラベルに一致する。

ボリュームラベルが無い場合は、"NO NAME "。
BS_FilSysType 54 8

大抵の場合、

"FAT12   ", "FAT16   ","FAT     "

のうちいずれかの文字列。

この文字列は情報提供のみを目的としており、

FATタイプを決定するものではない。

BS_BootCode 62 448

ブートストラップコード。

未使用時はゼロで埋める。

BS_Sign 510 2

ブートシグネチャ。

0xAA55をリトルエンディアンで設定するので、

オフセット510 = 0x55

オフセット511 = 0xAA

となる。

--- 512 --- セクタサイズが512を超える場合は、0x00で埋める。

 

FAT32 (オフセット36以降)

名前 オフセット サイズ 内容
BPB_FATSz32 36 4

1つのFATが専有するセクタ数。

BPB_ExtFlags 40 2

ビット3~0:

  0から始まるアクティブなFAT。

  ビット7が1のとき有効。
ビット6~4:

  予約。
ビット7:

  0は全てのFATがミラーリングされることを示す。

  1はビット3~0で示される1個のFATだけがアクティブであることを示す。
ビット15~8:

  予約。

BPB_FSVer 42 2

FAT32ボリュームのバージョン。

上位バイトがメジャーバージョン番号、

下位バイトがマイナーバージョン番号。

BPB_RootClus 44 4

ルートディレクトリの先頭クラスタ番号。

大抵は先頭クラスタである 2 が設定される。

BPB_FSInfo 48 2

予約領域中でFSINFO構造体の置かれるセクタ番号。

大抵はブートセクタの次である 1 が設定される。

BPB_BkBootSec 50 2

0以外の場合、予約領域中でブートセクタのバックアップが配置されるセクタを示す。

大抵はブートセクタの6セクタ先である 6 が設定される。

BPB_Reserved 52 12

予約。

0x00で埋める。

BS_DrvNum 64 1

ドライブ番号。

INT13hで使用。

フロッピーディスクでは、0x00、

固定ディスクでは、0x80。

BS_Reserved 65 1

予約。

WindowsNTで使用されているらしい?

通常は、0x00を設定。

BS_BootSig 66 1

拡張ブートシグネチャ。

続く2つのフィールドが有効な場合、

0x29を設定する。

BS_VolID 67 4

ボリュームシリアル番号。

不正なメディア交換を検出する為のヒント。

大抵は現在時刻から生成される。
BS_VolLab 71 11

ボリュームラベル。

ルートディレクトリのボリュームラベルに一致する。

ボリュームラベルが無い場合は、"NO NAME "。
BS_FilSysType 82 8

常に"FAT32   "。

この文字列は情報提供のみを目的としており、

FATタイプを決定するものではない。

BS_BootCode 90 420

ブートストラップコード。

未使用時はゼロで埋める。

BS_Sign 510 2

ブートシグネチャ。

0xAA55をリトルエンディアンで設定するので、

オフセット510 = 0x55

オフセット511 = 0xAA

となる。

--- 512 --- セクタサイズが512を超える場合は、0x00で埋める。

 

なんと言うか...

PC黎明期からの歴史を感じつつも、今となっては、かなり無理を感じる...

当時は、メモリもストレージも、まだまだ容量が小さくて、

1Byteでも無駄に出来ない... そんな雰囲気があったもんなぁ...

それが、今の時代、容量を気にせず、利便性を追求できるので、

過去の資産を考慮しなければ、もう少し、すっきりした構造に出来そうだけど、

x86含め、互換性重視だと、どうしても、継ぎ足し継ぎ足し構造になっちゃうね。

QEMUの(ほぼ)最新版を入れてみる

何は、ともあれ、QEMUを用意してみる。

以前は、確か、0.x.xだったバージョンが、10になっている。

最新は、11らしいけど、新しすぎるのも怖いので、

ひとまず、10の最新版にしておこう。

以前は、Windows環境だったと思うけれど、今回は、Linux環境で。

Windows環境は、あれこれ弄ってしまうと、訳が分からなくなるので、

仮想環境上に用意したLinuxの上で、気兼ねなく、実験しましょう。

何かの拍子に、おかしくなっても、惜しくはない。

色々と足りない...

Linuxは、Ubuntu 22.04 を VMware 上で利用している。

バージョン的に、少し古くなっているので、色々と足りないらしい。

何よりも、Pythonは、最新版を手動でインストールする事になった。

システム的に、デフォルトの Python は、弄らない方が良いとの事で、

/usr/local/〜 にインストールする事で、上手く共存?出来るらしい。

とにかく、やってみる

とりあえず、必要そうなパッケージをブチ込む。

sudo apt install build-essential libbz2-dev libdb-dev libreadline-dev libffi-dev libgdbm-dev liblzma-dev libncursesw5-dev libsqlite3-dev libssl-dev zlib1g-dev uuid-dev tk-dev

さくっとPythonを入れる。

$ wget https://www.python.org/ftp/python/3.14.5/Python-3.14.5.tar.xz
$ tar xJf Python-3.14.5.tar.xz
$ cd Python-3.14.5/ 
Python-3.14.5$ ./configure
Python-3.14.5$ make
Python-3.14.5$ sudo make install
Python-3.14.5$ wthich python3
/usr/local/bin/python3

OK!!

続けて、QEMUに必要そうなパッケージのインストール

$ sudo apt install libglib2.0-dev flex bison

本命のインストール

$ wget https://download.qemu.org/qemu-10.2.3.tar.xzwget https://download.qemu.org/qemu-10.2.3.tar.xz
 :
 :
2026-06-05 16:56:18 (23.0 MB/s) - ‘qemu-10.2.3.tar.xz’ へ保存完了 [141095748/141095748]
$ tar xvJf qemu-10.2.3.tar.xz
 :
 :
qemu-10.2.3/subprojects/libc-0.2-rs.wrap
qemu-10.2.3/subprojects/keycodemapdb.wrap
qemu-10.2.3/qemu.nsi
$ cd qemu-10.2.3/
qemu-10.2.3$ ./configure
qemu-10.2.3$ make
qemu-10.2.3$ sudo make install
qemu-10.2.3$ which qemu-system-x86_64
/usr/local/bin/qemu-system-x86_64
qemu-10.2.3$ qemu-system-x86_64 -version
QEMU emulator version 10.2.3
Copyright (c) 2003-2025 Fabrice Bellard and the QEMU Project developers

うむ。

インストールは、出来たようだ。

ひとまず、QEMUを用意しよう...

以前は、CD-ROMからのブートを試みて、

ブータブルCDを作成するため、EL TORITO を調べたりしたようだが、

今回は、USBメモリからのブートとしたいのでさらっとスルーする。

ただ、JIS X 0606 (ISO 9660) については、別途、まとめる事とする。

これは、今後、JIS規格の範囲を把握する為の資料としたい。

QEMUでUSBメモリからのブートを試すには?

レガシーBIOSの場合は、HDDと同様、MBRを配置するだけで良いのか?

勿論、MBRだけでは、動かないだろうけど...

UEFIの場合は、FAT前提の上で、規定のファイル名の内容がロードされるらしい。

とりあえず、QEMU上では、HDDイメージとして試して、

それを、USBメモリに、ブータブルイメージとして書き込めば良いのかな?

ひとまず、QEMUの最新版を用意して試してみましょう。

最近の環境を確認してみる

前回、とは言え、もう十年以上も前になるのか...

CDイメージからブートしようと、何やら、頑張っていたみたいだけれど、

そこから、CD-ROMの規格やら、ディレクトリ構造やら、脱線しまくった模様。

当時、既に、フロッピーディスクは、姿を消しつつあった訳だけど、

今となっては、CD-ROMも、同じ道を辿りつつある。

色々と環境も変わっているので、一旦、見直した方が良いだろう。

当時を思い出してみる...

当時の反省点として、まず、ブログだけでは情報不足という点。

まぁ、メモ書き程度のつもりで書き残していたと思うけれど、

当時の成果物と合わせて追わないと、全く意味不明な感じだ。

当時の成果物も、何処かに埋もれてしまって、探し出すのが大変だ。

資料のまとめ方も考える必要があるな。

とにかく、HariboteOS を参考にしていたので、QEMUを使って、

レガシーBIOS と MBR/PBR の組み合わせだったような気がする。

開発環境も、多分、Windowsだったと思うが、7辺りだったか?

QEMUのバージョンも、0.x.x...

最近の環境は、どうなってる?

あれから、随分と年月が経ったが、今では、すっかりAI一色。

そんな流れの中、自作OSなんて流行らないと思いきや、

HariboteOSの後に、MikanOSなども現れたらしく、

自作OSの火が、完全に消えた訳でもないようで、その点は、嬉しい限り。

PCの性能も、マルチコアが当り前、メモリはG単位、ストレージはT単位。

BIOSもUEFIに置き換わりつつあり、MBR/PBRもGPTに移行中。

Windowsも絶対的な存在ではなくなりつつあり、

Linuxが、その代替候補としても、かなり使えるレベルに成熟している。

ぶっちゃけ、現在では、ブラウザさえ使えれば、スマホでも、大概の事は出来る。

PCは、パーソナルユースとしては、高性能になり過ぎたかもしれない。

数万円の Android タブレットでさえ、Win95時代のPCを遥かに凌駕する性能だ。

そうなると...

もしかしたら、PC用のOSにこだわる必要はないのかもしれない。

なるほど、ハードウェアをある程度抽象化して、仮想マシンなどを用意するのも、

純粋にOSの主要部分だけを勉強したいのであれば、良い方法かもしれない。

本来、X86アーキテクチャ や PC BIOS に精通する事と、

OSその物を作る事とは、切り離せない訳でもない。

ただ、手元のPCを使って試してみたいと考えると、そうなるだけの話であって、

例えば、ラズパイのようなマイコン相手だと、また話が変わってくる。

結局、自分は、これまで、OSの手前の話で躓きまくって、

核心部分には、全く届いていなかったという事が、良く分かった気がする。

とは言え...

今までやってきた事も、無駄ではなかったと思うし、それはそれで、まとめたい。

それとは、別に、今後は、特定のアーキテクチャにこだわる事なく、

なるべく抽象的に捉えられるように気を付けて、先に進む事にしよう。

手っ取り早く...

さくっと始めたいのであれば...

やはり、寄り道せずに、既存のブータブルメディアを作成出来るソフトを使う。

そうすれば、BIOSやらローダーやらを気にせずに、OSの開発を始められる。

ただ、その過程で、上手く動かなかったりした場合、

ある程度、何をしているのか理解していた方が、解決も早いだろう。

少なくとも、この段階で、BIOSの詳細やローダーの処理を追う必要はない。

でも、結局...

BIOSについては、この後、小さなプログラム...

例えば、画面に文字列を表示する

などを作成する際に、力を借りる事になるはずだ。

BIOSに、どのような機能が用意されているか分かってくれば、

必然的に、ローダーが、どのような処理を行っていたかも分かってくるだろう。

簡素なローダーであれば、BIOSの機能のみで完結する場合もあるが、

ほとんどの場合、何かしらのファイルシステム... 例えば FAT32 など、

付随的に必要となる内容が、いくつか出てくる可能性が高い。

しかし、これらも、OS本体の作成を進めていけば、必要となる内容である。

結局のところ、多少順番が前後するくらいの話で、

必要となる知識に関しては、必ず、どこかで向き合う事となる。

要するに...

先に進みたい人は、どんどん先に進めば良いし、

分からないままだと気持ち悪い人は、立ち止まって、深堀りするのも良い。

最終的には、同じ道に合流する事になる。

少なくとも、学んだ事が、無駄になる事はない。

それよりも、大事な事は、自分のやる気を維持する事だと思う。

OSという巨人を相手に、心が折れそうになる場面が、何度もあるだろう。

だから、なるべく、自分が楽しいと思えるやり方で進めるべきだと思う。

仕事としてOSに取り組んでいる人は、別として、

趣味や興味で取り組んでいる人は、義務や強制ではないので、

あまり難しく考えず、自分なりのやり方で良いはず。

きっと、そこには、正しい進め方なんて物はなくて、

強いて言えば、続ける事だろうか?

これは、これまでの自分を振り返っての反省点である。

頭の中で色々と考えているつもりになって、結局、何もしていない事が多い。

それならば、小さなプログラムを書くなり、調べ物をするなり、

駄文でも良いので、自分の考えをまとめてみたり、何かしら行動すべき。

一日一日の成果は、大した事がなくとも、積み重ねに勝る物はない。

歳を重ねると、その大事さが、だんだん分かってくるようになります。

何故、ローダーが必要なのか?

ローダーって何?

これも、要領の良い人... 勘の良い人と言うべきか?

ピンと来る人は、すんなり納得出来てしまうのかもしれないが、

自分の場合、いきなり、この疑問で躓いてしまった。

ぶっちゃけ、ローダー?何それ?状態で、

まずは、ローダーとは...、から理解する必要があるのか、と思い込んでしまった。

ローダーとは、文字通り、OSをロードする物なのだが、

電源を入れれば、勝手にOSが起動する物じゃないの?という理解レベルでは、

なかなか、その必要性に気が付けなかった。

まずは、コンピューターの仕組みを知らねばならない

その必要性に気付くには、やはり、最低限の仕組みから入る事になる。

コンピューターの五大要素として、制御・演算・記憶・入力・出力があるが、

制御と演算については、主にCPUが、その役割にあたる。

CPUが中心となって、その他の装置を制御する事になるのだが、

CPUは、記憶、すなわち、メモリからプログラムを読み出しながら動作する。

いわゆる、ノイマン型(ストアードプログラム方式)と呼ばれる仕組みである。

CPU単体では、処理能力はあっても、やるべき仕事を知らないという訳である。

CPUは、基本的に、起動直後、メモリの決まった場所から読み出しを開始する。

つまり、その場所に、前もって、プラグラムを用意しておく必要がある。

必然的に、その領域は、不揮発性のROM領域となる。

揮発性のRAM領域では、電源を切ると、内容がクリアされてしまうからである。

小規模な構成であれば、そのROMに直接プログラムを書き込む方法もある。

だが、より大きな構成になってくると、それでは不便になってくる。

そこで、プログラムを外部装置(例えば、ハードディスクやUSBメモリ)に用意し、

そこからRAM領域へ読み込む事を考える。

そうすると、対象となる外部装置を制御するプログラムが必要になる。

つまり、それらが、BIOSであり、読み込みのための最低限の環境を提供する。

外部装置からプログラムを読み込み、そのプログラムに制御を移すまでは、

ROM領域に用意された固定プログラムで処理を行う必要があるので、

最初のプログラムを読み込むまでは、決められた手順に沿う事になる。

具体的には、指定装置の決められた領域から決められたサイズ分を読み込み、

RAM領域の決められた場所に配置した後、そのプログラムに制御を移す。

最初のプログラムは、この条件下で用意する必要があり、

多くは、より大きいプログラムを読み込むための小さいプログラムである。

すなわち、これが、ローダーである。

思えば、遠回りをしたものだ...

復習がてら、つらつらと書き出してみたが、

自分は、この仕組みを理解し納得するまで、随分と遠回りをした気がする。

が、今となっては、必要な遠回りだったようにも思う。

冒頭でも書いた通り、自分は、そこまで勘の良い人間ではない。

凡人には、凡人のやり方があって、天才の真似事をしようとしても無理な話だ。

結局、一歩々々、地道に愚直に、積み重ねていくしかない。

とにかく、ローダーは、ローダーであって、OS本体とは別物。

それでも、OSを動かそうとすると必要になる物。

今は、その程度の理解で納得出来ているから、それで十分だと思っている。

 

 

 

 

 

 

 

BIOSだとか、ローダーだとか...

避けられない話なのだが、OSを作るぞ〜!!と意気込んで、

最初にぶつかるのが、BIOSだったり、ローダーだったりする。

右も左も分からない状態で、これらの用語にぶつかると、

これもOSの一部なのか?と思いがちであるが、

厳密には、OSを読み込むために用意されている仕組みであって、

OSその物を勉強したければ、深入りすべきではない... と思う。

けれども、そう言えるのも、随分と回り道をした結果であって、

自分は、分からないまま先に進むのが気持ち悪くて、

未だに、この入口の部分で、足止めを喰らっている。

きっと、要領の良い人は、素直にスルー出来るのだろうけれど、

自分は、そういう点では、とことん不器用なのだろう。

だから、OSを勉強したいと思う人には、勧めないけれど、

コンピューターの動作を隅々まで理解したいと思う人には、

自分が納得するまで、とことん調べてみれば良いと思う。

繰り返しになるけれど、BIOSやローダーだけでも、奥が深いです。

純粋にOS「だけ」を勉強したければ、ひとまず、スルーするのが正解だと思います。