起動するまでの長い道のり IPL篇(1) ディスクイメージ作成の巻

 PC/ATマシンで動くOSを作る場合、PC/ATでのOS起動規格に則ってブートセクタ等を用意しなければならない。

マシンはどうやってOSを起動するか

 まっさらなマシンにWindowsとかLinuxとかのインストールCDを入れて起動すると、CDがガリガリ読み込まれてインストール画面が出る。だが、まっさらなマシンに他のソフトのCDを入れて起動すると「No operating system」とかメッセージが出てそのまま止まってしまう。たとえインストールCDのファイルを別のCDに全部コピーしても、その不正コピーCDではインストール画面が立ち上がらない。上記のことはフロッピーディスクにも当てはまる。起動できるディスクと起動できないディスクがあるのだ。

 起動できるディスクには、ブートセクタ(IPL)と呼ばれる領域がディスクの先頭にある。マシン(BIOS)は、接続されているFDDやHDDにブートセクタを持つディスクが入っているか確かめ、見つかればメモリに読み込んで実行する。ドライブを検索する順序は大抵フロッピー→ハードディスク→CDになっていて、普段はハードディスクにあるOSが起動される。(BIOSの設定によって順序を変えられたりもする)

IPLを作るには

 IPLは、FDなどを普通にフォーマットしてファイルをコピーしても作れない。ファイルという概念は、実はファイルシステムという仕組みの上に実現されている。身近にある「本」で例えれば、ファイルは目次と見出しを付けられた章のようなものだ。

 BIOSは、起動できるかどうか判断するのに本の中身(ファイル)を見ない。表紙だけを見る。エクスプローラ等では、普通、本(ディスク)の表紙までは操作できない。表紙に何かを書き込む場合には特別なツールや作業が必要となる。

 IPLを作るためには恐怖のアセンブラを使う必要がある。さらに、ファイルシステムを考慮しないで「表紙」に書き込むためのdd(GNU binutilsに付属)というツールを使う。

IPLを作る

 さて実際にIPLを作ってみる。IPLを作る手順は以下の通り。カッコ内は使用するツールだ。

  1. アセンブラのコードを書く。(エディタ)
  2. アセンブルする。(as)
  3. バイナリ形式に変換する(objcopy)
  4. ディスクに書き出す。(dd)
  5. 実行する。(qemu)

 以上の手順でいわゆる「起動ディスク」が出来上がる。今回はqemuでその起動ディスクから起動してみることにする。(なので、実際のディスクを使わずにディスクイメージファイルを作る。フロッピーを買いに走ったりしなくて良い)

 以下、順を追って説明する。

コードを書く

 いよいよコーディングらしいことをする。エディタでアセンブラのソースファイルを書くのだ。とりあえず以下のような内容を書き、ipl.sというファイル名で保存する。(別の名前でも良いが、日本語だけは止めておいた方が良いと思う)
 それぞれのコードの意味は後日明らかになると思うので今はとにかくこれをこのまま書こう。
 なお、アセンブラにはgas(GNU as)を使う。nasmが良いとかいうわがままな人は自分で頑張ろう。

# ipl.s

# generate real mode code
.code16

    jmp begin
    nop

# BPB
name:           .ascii  "Name    "
sector_size:    .word   0x0200
cluster_size:   .byte   0x01
fat_pos:        .word   0x0001
fat_cnt:        .byte   0x02
root_size:      .word   0x00e0
sector_cnt:     .word   0x0b40
media_type:     .byte   0xf0
fat_size:       .word   0x0009
sector_cnt_pt:  .word   0x0012
head_cnt:       .word   0x0002
bpb_pos:        .long   0x0000
sector_cnt_l:   .long   0x00000b40
drive_no:       .byte   0x00
reserved:       .byte   0x00
ext_boot_code:  .byte   0x29
volume_serial:  .long   0xffffffff
disk_name:      .ascii  "DISK       "
fat_name:       .ascii  "FAT12   "

    # boot begin
begin:
    # infinite loop
    jmp begin

# boot signature.
. = 510
.short 0xaa55
アセンブルする

 Cygwinシェルを起動して、ipl.sのあるディレクトリに移動し、asでアセンブルする。(Cygwinをまだインストールしていない人は、しよう)

$ as -o ipl.o ipl.s

 するとipl.oというファイルができる。

バイナリ形式に変換する

 諸般の事情により、アセンブルしたオブジェクトファイル(ipl.o)はまだ実行可能形式ではない。複数のオブジェクトファイルをまとめたりする場合のための情報が混じっている。これを純粋な実行コードだけの形式にしなければならない。そのためにobjcopyという変換ツールを使う。

$ objcopy -S -O binary ipl.o ipl.bin

 これでipl.binというファイルができる。(因みにbinとはbinaryの略だ)

ディスクに書き出す

 上記のipl.binが実際に実行されるコードになるのだが、これをエクスプローラ等でフロッピーにコピーしても起動時に実行されない。先述のようにディスクの「表紙」に書かなければならない。ddというツールを用いれば表紙に書き込める。

$ dd if=/dev/zero of=fd.img count=2880
$ dd if=ipl.bin of=fd.img conv=notrunc

 1行目が空のディスクイメージ作成のためのコマンドで、2行目がIPLをディスクイメージ先頭に書き込むコマンドだ。これでfd.imgというフロッピーのディスクイメージができる。

実行する

 fd.imgをqemu上の仮想マシンに挿入して実行する。(まだqemuをダウンロードしていない場合は、しよう)

 IPLを作成した同じディレクトリにqemuディレクトリがあると見なして説明する。もし別の場所にqemuがある場合は、qemuのパスの部分を読み替えて欲しい。

$ ./qemu/qemu.exe -L ./qemu -m 128 -fda fd.img

 これでメモリ128Mのマシンの1番目のFDD(fda)にディスク(fd.img)を挿入して起動するというコマンドになる。
 起動してきたqemuのウィンドウに「FATAL: Not a bootable disk」というエラーメッセージが出なければ成功だ。
 ちなみに、qemuのウィンドウ内でマウスをクリックしたりするとカーソルが消滅して操作できなくなったりする。その場合は、qemuのウィンドウタイトルに書かれている通りCTRLキーとALTキーを同時押しすると再びカーソルが出てきて操作可能になる。