2014年9月21日日曜日

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

まだまだ3日目だ。

今度は、OS本体起動時に、ビデオモードを設定してみる。

tinyos.s

.text
.code16 
 movb $0x00, %ah
 movb $0x13, %al
 int $0x10
fin: 
 hlt
 jmp fin
正しく実行できれば、真っ暗な画面が表示されるはず。
だが、試してみると動かない。

原因としては、次ののどちらか。
jmp 0xC200 で 0xC200にジャンプしていない。
FDからOS本体のイメージを正しく読んでいない。

前日に、jmp 0xC200 で実行したところ、正しく動作せず、
jmp *0xC200 にしたら、見掛け上は動いているようだったので
安心していたが、このコードでは、
0xC200に書いてあるアドレスにジャンプする命令だったようだ。

ソースとリンカスクリプトを再チェック、ビルド方法の確認をしてみたが、今のところお手上げ。
仕様がないので、qemu上のコードをGDBでデバッグすることにした。

Makefile に デバッグ用のターゲットを追加する。

Makefile

debug:
 qemu-system-i386 -m 32 -localtime -vga std -fda ${image_file} \
  -gdb tcp::10000 \
  -S
GDBは、起動時に実行するスクリプトファイルを指定できる。
今後の開発で、多分、実行したいコマンドが増えると思うので、作成しておく。

gdb.scr

target remote localhost:10000
make debug で qemuを起動した後に、gdbを-xオプションでスクリプトファイルを指定して起動する。
$ gdb -x gdb.scr
ブレークポイントを0x7c00に設定する。
(gdb) b *0x7c00
Breakpoint 5 at 0x7c00
ブレークポイントまで実行する。
(gdb) c
Continuing.

Breakpoint 5, 0x00007c00 in ?? ()
止まった。 ジャンプする直前で止めたいので、lstファイルを確認すると、該当箇所は0x00acなので、 0x7cacにブレークポイントを設定し、continueする。
  80                            // シリンダ
  81 00a3 80C501                add     $1, %ch
  82 00a6 3A2E0A00              cmp     MAX_CYLINDER, %ch
  83 00aa 72B9                  jb      readloop        # シリンダは 0 〜 MAX_CYLINDER - 1
  84 00ac E90000                jmp     0xC200          # 0x8000 + 0x4200 = 0xC200  ← ◆ここ
(gdb) b *0x7cac
Breakpoint 2 at 0x7cac
(gdb) c
Continuing.

Breakpoint 2, 0x00007cac in ?? ()
レジスタ値を確認する。
(gdb) i all-registers 
eax            0x840 2112
ecx            0x101 257
edx            0x0 0
ebx            0x0 0
esp            0x7c00 0x7c00
ebp            0x0 0x0
esi            0x0 0
edi            0x0 0
eip            0x7cac 0x7cac
eflags         0x202 [ IF ]
cs             0x0 0
ss             0x0 0
ds             0x0 0
es             0x840 2112 ← ◆これ
fs             0x0 0
gs             0x0 0
あれ?ESレジスタが1回分しか0x20が加算されておらず、0x840になっている。 停止させたアドレスが間違っているのかと思って、continueしたけど
(gdb) c
Continuing.
このまま止まらなかった。 イメージ読み込みがうまく動いていないのか。
ソースをチェックすることにしよう...

参考