ブートセクタ(IPL)を書く上で必要になりそうな情報 †
DOS互換にするならブートセクタにBPBも書きます †
一番古い形式のFAT12/FAT16用BPB †
- 最初の11バイト:
- AT/98の場合:
- +0x00 - +0x02 : jmp命令用の空き
- +0x03 - +0x0a : 名前(たいていはファイルシステムの名前か、もしくはOSの名前が入る。ATでBIOSを使ってこの部分を読みこむと、たいていごみデータに置換される。)
- TOWNSの形式1の場合:
- +0x00 - +0x03 : ブート可能であることを示すシグネチャ「IPL4」
- +0x04 - +0x0a : jmp命令用の空き(あまりには名前を書いてもよい)
- TOWNSの形式2の場合:
- +0x00 - +0x02 : jmp命令用の空き
- +0x03 - +0x06 : ブート可能であることを示すシグネチャ「IPL4」
- +0x07 - +0x0a : 名前
- +0x0b - +0x0c : セクタサイズ(一般的には512か1024)
- +0x0d : クラスタサイズ(1クラスタが何セクタで構成されているか)
- +0x0e - +0x0f : FATがどこから格納されているか(このBPBセクタからの相対セクタ番号で)
- +0x10 : FATがいくつあるか(一般的には2)
- +0x11 - +0x12 : ルートディレクトリの長さ(32バイト単位)
- +0x13 - +0x14 : このドライブ(FDの場合はディスク、HDDの場合はパーティション)の総サイズ(セクタ数で)
- ここは2バイトまでしか書けないので、1セクタ512バイトの場合は32MBを超えられないことになってしまう。そこで2バイトで書けない場合は、ここを0x0000にして、+0x20 - +0x23に総サイズを書く。
- +0x15 : メディアのタイプ(一般に1440KB-FDの場合は0xf0を、HDDの場合は0xf8を書いておけば問題はなさそう)
- +0x16 - +0x17 : FATの長さ(1つ分の長さをセクタ数で)
- +0x18 - +0x19 : 1トラックにいくつのセクタがあるか(一般に1440KB-FDの場合は18)
- +0x1a - +0x1b : ヘッドの数はいくつか(一般に1440KB-FDの場合は2)
- +0x1c - +0x1d : このBPBセクタはデバイスの先頭から数えてどこにあるか(HDDのパーティション開始位置を表すために用いられる、セクタ単位、一般に1440KB-FDの場合は0)
- 全体的なフォーマット:
- +0x0e - +0x0fの値で示される部分から、次の順序で並ぶ。
| 名前 | 長さ(バイト数) | 備考 | | 第一FAT | (+0x16 - 0x17)x(+0x0b - +0x0c) | | | 第二FAT | (+0x16 - 0x17)x(+0x0b - +0x0c) | 内容は第一FATと同じ(バックアップ) | | ルートディレクトリ | (+0x11 - +0x12)x 32 | | | ファイル領域 | 下記 | |
- ファイル領域のバイト数は(+0x13 - +0x14)x(+0x0b - +0x0c)から上記3つの長さを引き、さらに(+0x0e - +0x0f)x(+0x0b - +0x0c)を引く
- FAT12/FAT16の区別は?
- まずファイル領域の総クラスタ数を算出。これは上記の方法でファイル領域のバイト数を出して、それをクラスタサイズで割れば求められる。このクラスタサイズが12bitで表現できれば(おそらく総クラスタ数が0xff5未満なら)、FAT12になる。そうでなければFAT16になる。
現在の形式のFAT12/FAT16用BPB †
- +0x1e - +0x1f : HDDの大容量化にあわせて+0x1c - 0x1dの内容を4バイトに拡張、したがってここには上位16bitが入る
- +0x20 - +0x23 : +0x13 - +0x14の内容を4バイトで書いたもの
- +0x24 : 物理ドライブ番号(とりあえず0にしておくといいらしい)
- +0x25 : 予約(とりあえず0にしておくといいらしい)
- +0x26 : 拡張ブート識別コード(とりあえず0x29を書くらしい)
- +0x27 - +0x2a : 0xffffffffを書いておくといいらしい(ボリュームシリアル番号)
- +0x2b - +0x35 : ディスクの名前、もしくはパーティションの名前、ボリュームラベルのコピー
- +0x36 - +0x3d : "FAT12"(46 41 54 31 32 20 20 20)か、"FAT16"(46 41 54 31 36 20 20 20)が入る
さらに拡張されたSF16用BPB †
- FAT16の記述に対してさらに+0x4fまで規定されている。詳細はSF16を参照。
FAT32用BPB †
AT互換機の場合 †
- FDDの場合:
- ブートセクタの内容が0x0000:0x7c00に転送されます。そしてBIOSからJMP 0x0000:0x7c00されます。もしBPBを置くならここからプログラムを書くのは難しいので、とりあえずBPBの後ろにコードを置くことにして、ここではそこにJMPさせましょう。
- まだ確信はありませんが、この時のレジスタ状況はこんな感じのようです。
- DS=ES=SS=0, SP=0x7c00, FLAGS.IF=1(割り込み許可)
- ということでNASMやNASKを使ってブートセクタを書くなら、バイナリーモードでORG 0x7c00で書き始めればいいみたいです。もちろん他のアドレスに転送するつもりならこの限りではありませんが。0x00000〜0x005ffはIA-16やBIOSが使っているようなので、訳が分かるまではここを避けて使うといいでしょう。
- このレジスタ初期値とかロード位置とかって、もしかして8bit時代のなごりなのかな。8bitの頃は0x8000からがROMだったりしたから、0x7c00っていうのもいかにもそれっぽい感じが・・・。セグメントレジスタが全部等しいので、64KB以内でなんとかなるならセグメントを無視してプログラミングすることもできますね。
- ブートセクタの最後の2バイトはシグネチャーです。0x55 0xaaをおいてください。これがないと有効なブートセクタではないとBIOSに判定され、呼び出してもらえません。
- HDDの場合:
- 上記に加えて、SIにも値がセットされます。DS:SIからの16バイトはMBR中にあるパーティション情報のうち、実際に今回起動に使われたものをコピーして指し示しているようです。
TOWNSの場合 †
- 形式1:
- セクタの最初の4バイトはシグネチャーになっております。ブート可能なディスクなら必ず'IPL4'と書くこと。
- 0xb0000〜0xb03ffにロードされる(512バイトセクタのときは、0xb0000〜0xb01ffかな?・・・と思いきやどうも次のセクタも読んでくれているようです)。
- システムからはCALL 0xb000:0x0004で呼ばれる。
- ブートに失敗した場合、RETFするのが作法。その場合、システムは次のデバイスの起動を試みる。
- もしBPBを置くならここからプログラムを書くのは難しいので、とりあえずBPBの後ろにコードを置くことにして、ここではそこにJMPさせましょう。
- 形式2: (これって初代TOWNSとかでも使えるのかな?)
- セクタの0x03からの4バイトはシグネチャーになっております。ブート可能なディスクなら必ず'IPL4'と書くこと。
- 0xb0000〜0xb03ffにロードされる(512バイトセクタのときは、0xb0000〜0xb01ffかな?・・・と思いきやどうも次のセクタも読んでくれているようです)。
- システムからはCALL 0xb000:0x0000で呼ばれる。
- ブートに失敗した場合、RETFするのが作法。その場合、システムは次のデバイスの起動を試みる。
- もしBPBを置くならここからプログラムを書くのは難しいので、とりあえずBPBの後ろにコードを置くことにして、ここではそこにJMPさせましょう。というか、BPBを置かなくてもシグネチャーとぶつかるので、結局JMPですね。
- IPLからCALLされた段階では、まだBIOSが使えない(泣)。ということで、システムROMルーチンを直叩きしてやることになる。TOWNSでは、BIOSはDOSが設定しているらしい。
- ディスク読み込みファンクション
- AH = 0x05
- AL = device no. (0x20:FD0)
- CX = cylinder
- DH = head
- DL = sector no.
- BX = sectors
- DS:DI = buf-addr
- CALL 0xfffb:0x0014
- CF = 0なら正常終了
- 文字表示ファンクション (シフトJISが使える)
- ES = 0xc000
- BH = 0x02
- DS:SI = struct { char y, x, len, string... } の構造体へのポインタ
- CALL 0xfffb:0x001e
- TOWNSではATとは異なり、どのデバイスからのブートであるかの情報も得られる(ATの場合だと、ブートしたデバイスがBIOSから#0デバイスにみえるという、情けない仕組みになっている)。これはIPL突入時のBL, BHの値で判別できる。
- BLの下位4bit:デバイスのタイプ:1=HDD、2=FDD、8=CD-ROM
- BHの下位3bit:デバイス番号:0〜7らしい
98の場合 †
- どうやらシグネチャーはありません。だからデータディスクでも無害なIPLを書いておいて、ブートしないようにしてください。
- ブートセクタの内容が0x1fc0:0x0000に転送されます。そしてBIOSからJMP 0x1fc0:0x0000されます。もしBPBを置くならここからプログラムを書くのは難しいので、とりあえずBPBの後ろにコードを置くことにして、ここではそこにJMPさせましょう。
- 512バイトセクタのときは、0x1fe0:0x0000なのかな?
- この項未完成
AT/TOWNS/98対応IPLを作る場合 †
- TOWNSでは形式2を使って、そんでもって1440KBフォーマットにして、あとはCSの初期値をチェックすれば機種判別はできそうですね。
- もちろんATとTOWNSのシグネチャーを書きます。
- TOWNSの形式1を使った、つわものアルゴリズムもこの世には存在しますが(MEG-OSのIPLや、OSASKのI.Tak.さん作のIPL)。
- (まだできていないけどそろそろできるはずの)KHBIOSを使うという手もあります。
こめんと欄 †
- ATの上記情報はKが解析した内容をまとめただけです。もしかしたら解析対象がたまたまそうだっただけという可能性はあります。もしうちのシステムは違うぜ、みたいなことがありましたら、このこめんと欄で教えてください。 -- K 2003-06-29 (日) 13:55:16
- TOWNSのブートシグニチャは0x03に置いてもちゃんと認識されます。この場合はcall 0xb000:0x0000されます (TOWNSエミュレータうんづの互換ROMソースを読んで初めて知った)。ATや98とハイブリッド起動するためなんでしょうかね。Windows9Xに破壊されますが。 -- I.Tak.? 2003-07-01 (火) 09:34:41
- なんと!やるなーうんず! -- K 2003-07-01 (火) 10:16:44
- 実機でダンプをとったら, セクタサイズに関係なく1KB読み込まれていました。>TOWNS -- I.Tak.? 2003-10-31 (金) 16:31:41
- 興味深い・・・。1440KBに最初に対応したのってHG/HRらしいのですが、こいつでも2セクタ読んでくれているのかな? -- K 2003-10-31 (金) 17:51:50
書き込む際は必ず「承認」をチェックしてください!
|