6.828: Operating System Engineering (71)
mem.pdf の以下の課題に着手。
Exercises
1. Set a breakpoint at swtch. Single step with gdb’s stepi through the ret to forkret, then use gdb’s finish to proceed to trapret, then stepi until you get to initcode at virtual address zero.
2. Look at real operating systems to see how they size memory.
とりあえず 1 から
make qemu-gdb して swtch で break すれば良いのかな。とは言え、何を確認すれば良いのやら。以下かなぁ。
- swtch 手続きを経由してまず forkret 手続きに jmp していること
- forkret が終了したら trapret 手続きに jmp していること
- trapret から iret したら initcode の start に制御が移っていること
- initcode から init が exec されていること
なのかどうなのか。
まず一つめ
(gdb) n => 0x103dcf <swtch+19>: pop %ebp swtch () at swtch.S:27 27 popl %ebp (gdb) n => 0x103dd0 <swtch+20>: ret swtch () at swtch.S:28 28 ret (gdb) n => 0x1030b0 <forkret>: push %ebp forkret () at proc.c:353 353 { (gdb)
を、forkret に制御が移りました。次は、って cpu を二つ認識してるのでトレイス微妙。cpu 一つで云々なオプションは何だ。こうすりゃ良いのかな。
$ CPUS=1 make qemu-gdb
で再度実行してるのですが、forkret から戻ったら swtch に制御が飛ぶなぁ。n じゃなくて si で進めないと駄目なのかな。
リトライ
forkret からひたすら si で進めてたら trapret に制御が移ったことが確認できました。
(gdb) si => 0x1030c2 <forkret+18>: leave forkret () at proc.c:358 358 } (gdb) si => 0x1030c3 <forkret+19>: ret 0x001030c3 in forkret () at proc.c:358 358 } (gdb) si => 0x104cf0 <trapret>: popa trapret () at trapasm.S:31 31 popal (gdb)
ここも我慢して si で進めてみます。で、iret のあたりが以下。
(gdb) si => 0x104cf7 <trapret+7>: add $0x8,%esp 36 addl $0x8, %esp # trapno and errcode (gdb) si => 0x104cfa <trapret+10>: iret 37 iret (gdb) si => 0x0: push $0x24 0x00000000 in ?? () (gdb)
ふむ。0x0 番地に飛びましたね。で、何故か alltraps 手続きに制御が移っております。
(gdb) si => 0x5: push $0x1c 0x00000005 in ?? () (gdb) si => 0xa: push $0x0 0x0000000a in ?? () (gdb) si => 0xc: mov $0x9,%eax 0x0000000c in ?? () (gdb) si => 0x11: int $0x40 0x00000011 in ?? () (gdb) si => 0x1053b4 <vector64+2>: push $0x40 320 pushl $64 (gdb) si => 0x1053b6 <vector64+4>: jmp 0x104cd0 <alltraps> 321 jmp alltraps (gdb) si => 0x104cd0 <alltraps>: push %ds 9 pushl %ds (gdb) si => 0x104cd1 <alltraps+1>: push %es 10 pushl %es (gdb) si => 0x104cd2 <alltraps+2>: push %fs 11 pushl %fs (gdb) si => 0x104cd4 <alltraps+4>: push %gs 12 pushl %gs (gdb)
64 は 0x40 ですな。なんとなく exec してるような気もしますが、、
今、alltraps から trap 呼び出したあたり。で、短気を起こして next すると swtch に制御が移りますな。
とりあえず 0x0 番地に jmp したのが見れたのでヨシ、ってことにしてもらっても良いかなぁ。しかもよく考えたら exec した先はプロセスなオブジェクトとして別なはずなので、トレイスは無理なのかどうか。
そのに
ズルしました。dmesg に出てくる
Memory: 4043492k/5242880k available
みたいなナニで arch/i386 配下を find|grep したら以下。
$ find|xargs grep 'Memory:' ./mm/init.c: printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", $
上記出力な命令があるのは mem_init という手続きな模様。これ、main.c で呼び出されてるのかな。ただ、なんとなく mem_init で size してるのではなくて start_kernel 手続きの
setup_arch(&command_line, &memory_start, &memory_end);
でセットされてるように見えます。ただし、arch/i386/mm/init.c の mem_init 手続きでは出力部分が以下の記述になってますので、
printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10));
こん中でもごもごヤッてると言えばそうなのかも。
ざくっと確認したところでは setup_arch で (あるいはそれ以降でも?) 始点と終点をキメておいて mem_init の中で予約済みなページだったりを分別してそうなカンジです。
ここはもう少しじっくり見てみたい。