6.828: Operating System Engineering (62)

以下のどこかでオチている模様。

    // Turn on paging.
    cr0 = rcr0();
    cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;
    cr0 &= ~(CR0_TS|CR0_EM);
    lcr0(cr0);

いつまでも printf デバッグとゆーのもアレだし、レジスタダンプによれば

EIP=f01028a7 EFL=00000086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0

とのことなのでデバッガで場所は分かるはず。というかどう考えても lcr0 な命令で、なのだろうとは思いますが。

デバッガで確認

ちなみにダンプによれば cr0 レジスタの値は 80050033 でこれは

CR0_PE|CR0_MP|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PG

になります。ちなみに

    cr0 = rcr0();
||
した時点での cr0 の状態は 0x11 になってて
>||
    cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;
    cr0 &= ~(CR0_TS|CR0_EM);

で、0x80050033 になるのか。

あら?

オチる直前に p/x $cr0 したら以下なナニ。あと info registers の出力に control register が出てこない。

(gdb) p/x $cr0
$8 = Value can't be converted to integer.
(gdb) info registers
eax            0x0      0
ecx            0x3d5    981
edx            0x3d5    981
ebx            0x80050033       -2147155917
esp            0xf0113f80       0xf0113f80
ebp            0xf0113fd8       0xf0113fd8
esi            0x9f     159
edi            0xf0146bf4       -267097100
eip            0xf01028b4       0xf01028b4 <i386_vm_init+5791>
eflags         0x86     [ PF SF ]
cs             0x8      8
ss             0x10     16
ds             0x10     16
es             0x10     16
fs             0x10     16
gs             0x10     16
(gdb) 

と思ったら随分前に

(gdb) p $cr0
$6 = void
(gdb) 

な問題は検出してたりするけどスルーされている模様。

gdb

見てるのですが、cr0 への格納はできてるのかどうか。

gdb) n
=> 0xf0102899 <i386_vm_init+5764>:      mov    %cr0,%ebx
174             __asm __volatile("movl %%cr0,%0" : "=r" (val));
(gdb) n
=> 0xf010289c <i386_vm_init+5767>:      or     $0x8005002f,%ebx
260             cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;
(gdb) n
=> 0xf01028a2 <i386_vm_init+5773>:      movl   $0xf01047a3,(%esp)
262             cprintf("(i386_vm_init) (3.5)\n");
(gdb) n
=> 0xf01028ae <i386_vm_init+5785>:      and    $0xfffffff3,%ebx
167             __asm __volatile("movl %0,%%cr0" : : "r" (val));
(gdb) n
=> 0xf01028b4 <i386_vm_init+5791>:      movl   $0xf01047b9,(%esp)
267             cprintf("(i386_vm_init) (4)\n");
(gdb) 

なんつーか出力されてる命令が、cr0 に出力してる箇所あたりから整合してないんだよな。これ系の不具合ってどう対処すべきなんだろ。本当に始末に困る。
しかし上記のソレは printf デバッグの痕跡ががっつり確認できて情無いッスね。
ちなみに上記の状態から n したらレジスタダンプが出て止まらなくなります。QEMU も暴走してるカンジに見えますね。ダンプが以下。

EAX=00000000 EBX=80050033 ECX=000003d5 EDX=000003d5
ESI=0000009f EDI=f0146bf4 EBP=f0113fd8 ESP=f0113f80
EIP=f01028b4 EFL=00000086 [--S--P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 10000000 ffffffff 10cf9300 DPL=0 DS   [-WA]
CS =0008 10000000 ffffffff 10cf9a00 DPL=0 CS32 [-R-]
SS =0010 10000000 ffffffff 10cf9300 DPL=0 DS   [-WA]
DS =0010 10000000 ffffffff 10cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00114000 00000017
IDT=     00000000 000003ff
CR0=80050033 CR2=00113f80 CR3=00115000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
Triple fault.  Halting for inspection via QEMU monitor.

ん、Triple fault って何でしょ。wikipedia に以下な記述が。

In QEMU, a triple fault produces a dump of the virtual machine in the console, with the instruction pointer set to the instruction that triggered the first exception.

eip は 0xf01028b4 とありますな。

なんとなく

ページングを有効にしたらオチる、ってことはその準備に何らかの手抜かりがあるのだろうな、ということで別途夜に確認してみます。