2014年9月21日日曜日

[OS作成]30日でできる!OS自作入門 3日目 (4)

いよいよOS本体を起動する処理の作成だ。

IPLとOS本体を含むイメージファイルを作成するには、筆者作成のedimg.exeを使うと簡単であるが、ここ  や ここ  を参考にすると、UbuntuやDebianのmtoolsパッケージに含まれるmformatコマンドを使ってFDイメージを作成しているので、同様の手順で作成することにした。

mformatコマンドを使うとイメージファイルを次のコマンドで作成できる。
$ mformat -f 1440 -B ブートセクタファイル -C -i イメージファイル名 ::
ipl.binはブートセクタのファイルをBオプションで指定できる。
なお、man mformatを見ても、iオプションの説明は無かった。
OS本体をイメージファイルにコピーするには、
$ mcopy OS本体 -i イメージファイル名 ::
とする。

それぞれのコマンドの後ろにtarget directoryとして :: としているが、イメージファイルの場合は、これを指定するようだ。

Makefileは以下のようになった。

Makefile

image_file=tinyos.img

ipl.bin: ipl.s lnk.ls
    gcc -nostdlib -o $@ -Tlnk.ls ipl.s
    gcc -Tlnk.ls -c -g -Wa,-a,-ad ipl.s > ipl.lst

tinyos.sys: tinyos.s lnk.ls
    gcc -nostdlib -o $@ -Tlnk.ls tinyos.s
    gcc -Tlnk.ls -c -g -Wa,-a,-ad tinyos.s > tinyos.lst

image_file: ipl.bin tinyos.sys
    mformat -f 1440 -B ipl.bin -C -i ${image_file} ::
    mcopy tinyos.sys -i ${image_file} ::

img:
    make image_file

run:
    qemu-system-i386 -m 32 -localtime -vga std -fda ${image_file}

書籍通りに、まずは簡単なコードで確認する。

tinyos.s

fin:   
    hlt
    jmp fin

make img でイメージを作成してみる。

なお、tinyos.sのリスティングファイル(アセンブル結果)は以下の通り。

tinyos.lst

   1                  fin:   
   2 0000 F4               hlt
   3 0001 EBFD             jmp fin

書籍の通りに、0x2600にファイル情報がある。
00002600: 5449 4e59 4f53 2020 5359 5320 1800 e9b5  TINYOS  SYS ....
00002610: 3445 3445 0000 e9b5 3445 0200 0300 0000  4E4E....4E......
0x4200からOS本体のコードがある。
00004200: f4eb fd00 0000 0000 0000 0000 0000 0000  ................
イメージを0x8000から読み込ませているので、
イメージの0x4200からのコードを実行するには、
0x8000 + 0x4200 = 0xC200 になる。

ipl.s を修正して、FDの読み込み処理後に
    jmp    0xC200        # 0x8000 + 0x4200 = 0xC200
を追加した。

IPL用のリンカスクリプトとは別に、OS本体用のリンカスクリプトも必要だ。

tinyos_lnk.ls

OUTPUT_FORMAT("binary");

SECTIONS {
     . = 0xC200;
}
Makefileを、これに合わせて修正する。
image_file=tinyos.img

ipl.bin: ipl.s lnk.ls
 gcc -nostdlib -o $@ -Tipl_lnk.ls ipl.s
 gcc -Tipl_lnk.ls -c -g -Wa,-a,-ad ipl.s > ipl.lst

tinyos.sys: tinyos.s lnk.ls
 gcc -nostdlib -o $@ -Ttinyos_lnk.ls tinyos.s
 gcc -Ttinyos_lnk.ls -c -g -Wa,-a,-ad tinyos.s > tinyos.lst

image_file: ipl.bin tinyos.sys
 mformat -f 1440 -B ipl.bin -C -i ${image_file} ::
 mcopy tinyos.sys -i ${image_file} ::

img:
 make image_file

run:
 qemu-system-i386 -m 32 -localtime -vga std -fda ${image_file}

だんだん汚なくなってきた。そのうち綺麗に書き直そう。

make imgしてイメージを作成後、qemuで試してみる。
が、正しく動かない。load errorと出てしまう。
JMPがすっとばされているのか?
リスティングファイルを確認する。

ipl.lst

  83 00ac E90000                jmp     0xC200          # 0x8000 + 0x4200 = 0xC200
どこにもC200が無い。これでは駄目だ。

いろいろ調べて、試行錯誤してみると、

ipl.s

    jmp    *0xC200        # 0x8000 + 0x4200 = 0xC200

ipl.lst

  83 00ac FF2600C2              jmp     *0xC200         # 0x8000 + 0x4200 = 0xC200
うーむ。*0xC200と書くのが正しいのか。
(実は、最初は指定アドレスは即値なので$0xC200と書いて怒られた。)
きちんとGASのリファレンスを読んだほうが良さそうだな。

これで試してみると、一応見かけ上は動いているみたい。
今日はここまで。

9/21 追記
この後、ビデオモードを変更する処理を書いてみたが、どうも上のコードでは、0xC200へjmpしていないようだ。
0xC200へJMPさせるには、どう書けば良いのか?うーむ。

参考