6.828: Operating System Engineering (9)

ええと以下の命令について

[f000:efe9]    0xfefe9: mov    $0x8f,%eax
0x0000efe9 in ?? ()
(gdb) si
[f000:efef]    0xfefef: out    %al,$0x70
0x0000efef in ?? ()
(gdb) si
[f000:eff1]    0xfeff1: in     $0x71,%al
0x0000eff1 in ?? ()
(gdb)

色々確認していたのですが、Non Maskable Interrupt によれば

void NMI_enable(void)
 {
    outb(0x70, inb(0x70)&0x7F);
 }
 
 void NMI_disable(void)
 {
    outb(0x70, inb(0x70)|0x80);
 }

みたいな usage が例示されてました。
上記は disable にしようとしているのが分かりますが、何故に下 4 bits を立ててるのかが不明。先の NMI なスレッドでも 0x80 で disable にして 0x00 で enable にするような事は微妙てきな記述があったりするんですが、何故に 0x8f なのかは謎のママ。
とりあえずアツくなってるので一旦スルーします。

戻る

直前エントリな命令列を見てると cr0 の PE なフラグを立てて longjmp っぽいソレを実行してますね。BIOS の初期化な部分の中でプロテクトモードに移行したのかな。A20 を云々ってのはそーゆーことなのかどうかは不明ですが、んな訳ゃないでしょ的ソリューションですね。
そのままもう少し続けてみます。

The target architecture is assumed to be i386
=> 0xffee1:     mov    $0x10,%eax
0x000ffee1 in ?? ()
(gdb) si
=> 0xffee6:     mov    %eax,%ds
0x000ffee6 in ?? ()
(gdb) si
=> 0xffee8:     mov    %eax,%es
0x000ffee8 in ?? ()
(gdb) si
=> 0xffeea:     mov    %eax,%ss
0x000ffeea in ?? ()
(gdb) si
=> 0xffeec:     mov    %eax,%fs
0x000ffeec in ?? ()
(gdb) si
=> 0xffeee:     mov    %eax,%gs
0x000ffeee in ?? ()
(gdb) si
=> 0xffef0:     mov    %ecx,%eax
0x000ffef0 in ?? ()
(gdb) si
=> 0xffef2:     ret    
0x000ffef2 in ?? ()
(gdb) si
=> 0xf194b:     push   %ebp
0x000f194b in ?? ()

なんとなくどこかで見たようなセグメントレジスタへの代入なのですがいきなり ret しとるな。しかも適当に si 続けてたらいつの間にか BIOS ROM なアドレスから脱出していたのでびっくり。最初からリトライしてみます。
すると 0xed965 を call してますね。

=> 0xf1957:     mov    %dl,%al
0x000f1957 in ?? ()
(gdb) si
=> 0xf1959:     out    %al,$0xd
0x000f1959 in ?? ()
(gdb) si
=> 0xf195b:     out    %al,$0xda
0x000f195b in ?? ()
(gdb) si
=> 0xf195d:     mov    $0xc0,%al
0x000f195d in ?? ()
(gdb) si
=> 0xf195f:     out    %al,$0xd6
0x000f195f in ?? ()
(gdb) si
=> 0xf1961:     mov    %dl,%al
0x000f1961 in ?? ()
(gdb) si
=> 0xf1963:     out    %al,$0xd4
0x000f1963 in ?? ()
(gdb) si
=> 0xf1965:     push   $0xf5420
0x000f1965 in ?? ()
(gdb) si
=> 0xf196a:     push   $0xf4f90
0x000f196a in ?? ()
(gdb) si
=> 0xf196f:     call   0xed965
0x000f196f in ?? ()

なんかふつーに手続きを call しちゃってるカンジです。

=> 0xed965:     lea    0x8(%esp),%ecx
0x000ed965 in ?? ()
(gdb) si
=> 0xed969:     mov    0x4(%esp),%edx
0x000ed969 in ?? ()
(gdb) si
=> 0xed96d:     mov    $0xf7288,%eax
0x000ed96d in ?? ()
(gdb) si
=> 0xed972:     call   0xed1e0
0x000ed972 in ?? ()
(gdb) si
=> 0xed1e0:     push   %ebp
0x000ed1e0 in ?? ()

これは一体どーゆーことなのだろうか。ここもスルーしちゃってメセジ出力するまでひたすら si してみようかな。てか途中で直前コマンドと同じなら空で Enter タタけば良かったことを思いだしたorz

眠くなってきたので止める

次はどうも 0x7c00 に breakpoint 張って云々とあるな。si の途中だがセット。

(gdb) b *0x7c00
Breakpoint 1 at 0x7c00
(gdb) 

で、continue

(gdb) c
Continuing.
The target architecture is assumed to be i8086
[   0:7c00] => 0x7c00:  cli    

Breakpoint 1, 0x00007c00 in ?? ()
(gdb)

どうやって breakpoint を、って一瞬思ったんですが、こうやるのか。で、メモリの中身確認しながら以下の質問に答えられるようになれ、とあるのかな。

  • At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?
  • What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?
  • Where is the first instruction of the kernel?
  • How does the boot loader decide how many sectors it must read in order to fetch the entire kernel from disk? Where does it find this information?

ちょっとここから先はエントリを改めます。