※ この記事はまだ勉強中のため、いろいろ間違いがあるかもしれません。
さて、前回まででページの初期化が出来るようになったのだが、途中で落ちてしまう。 ユーザプロセス用の初期化ルーチンで落ちているようだった。具体的には、以下のvm.c内のinituvm()内でパニックを起こしてしまう。何だろう?
void inituvm(pde_t *pgdir, char asid, char *init, uint sz) { char *mem; if(sz >= PGSIZE) panic("inituvm: more than a page"); ...
inituvm()はproc.cから呼ばれている。
//PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = setupkvm()) == 0) panic("userinit: out of memory?"); inituvm(p->pgdir, p->asid, _binary_initcode_start, (int)_binary_initcode_size); ... }
binary_initcode_start, binary_initcode_size とは何だろう? 自分で翻訳していた。
大まかに見れば、setupkvmとuserinitは図1-2に示すようなアドレス空間を生成する。 最初のプロセスのメモリの初期内容は、initcode.Sからコピーされる。これはカーネル のビルドプロセスの一部であり、リンカがこのバイナリをカーネルに埋め込み、2つの 特別なシンボルを定義する。これが_binary_initcode_startと_binary_initcode_size である。これらはバイナリの場所とサイズを示している。userinitはinituvmを呼び出 すことによりこのバイナリを新しいプロセスのメモリ空間にコピーする。inituvmは物 理メモリのページを割り当て、そのメモリ空間を仮想アドレスの0番にマッピングする 。そしてバイナリをページの領域にコピーするのである(1903行目)。
そして、このbinary_initcode_startとbinary_initcode_sizeはどうやって定義しているんだろう。調べていると、以下のサイトを発見した。
ああ、binaryを指定することにより、start/stop/sizeの定数が生成されるのか。実際に生成しているのは、Makefileだ。
initcode: initcode.S $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o $(OBJCOPY) -S -O binary initcode.out initcode ...
実際にmakeしてみると、initcodeのサイズがやたらと大きいし、_binary_initcode_sizeも大きい!
00400018 g *ABS* 00000000 _binary_initcode_size
あれま!調査していると、initcodeをリンクするときに、いろんなデバッグ情報が付いていて、バイナリサイズが大きくなっていることが分かった。
mipsel-linux-elf-objdump -D -x initcode.out ... Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000038 00000000 00000000 00000094 2**2 CONTENTS, ALLOC, LOAD, CODE 1 .MIPS.abiflags 00000018 00400000 00400000 000000d0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE 2 .reginfo 00000018 00400018 00400018 000000e8 2**2 CONTENTS, READONLY, LINK_ONCE_SAME_SIZE 3 .debug_aranges 00000020 00000000 00000000 00000100 2**3 CONTENTS, READONLY, DEBUGGING 4 .debug_info 00000048 00000000 00000000 00000120 2**0 CONTENTS, READONLY, DEBUGGING 5 .debug_abbrev 00000014 00000000 00000000 00000168 2**0 CONTENTS, READONLY, DEBUGGING 6 .debug_line 00000040 00000000 00000000 0000017c 2**0 CONTENTS, READONLY, DEBUGGING 7 .gnu.attributes 00000010 00000000 00000000 000001bc 2**0 ...
0x00400000とか使ってるし!そりゃ、バイナリサイズも大きくなるよね。 仕方が無いので、ストリップしよう。このセクションは、おそらく使わない。
initcode: initcode.S $(CC) $(CFLAGS) -nostdinc -I. -c initcode.S $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o initcode.out initcode.o $(STRIP) --remove-section=.MIPS.abiflags --remove-section=.reginfo initcode.out $(OBJCOPY) -S -O binary initcode.out initcode $(OBJDUMP) -S initcode.o > initcode.asm
MIPS.abiflagsとreginfoセクションを切り取った。これで、サイズが小さくなる。
という訳で、これにて実行すると、cpu0がスタートするところまで行った。やったー!
$ make iss_debug_run swimmer_mips --imgfile xv6.img --max 80000000 --mem_flat=false --binfile kernel --only_info_load --reg_abi soft --script init.lua \ --trace_hier --trace_out flow.log \ --debug --out debug.log --debug_gvar --debug_func <Error: CSR Address 018 is invalid.> <Error: CSR Address 028 is invalid.> xv6... cpu0: starting <Error: CSR Address 018 is invalid.>
とは言え、完全デバッグモードだとここまで到達するのに10分くらいはかかる。高速デバッグモードだと2分くらいだが、もうちょっとデバッガビリティを上げる必要があるな。