※ この記事はまだ勉強中のため、いろいろ間違いがあるかもしれません。
さて、前回まででページの初期化が出来るようになったのだが、途中で落ちてしまう。 ユーザプロセス用の初期化ルーチンで落ちているようだった。具体的には、以下の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分くらいだが、もうちょっとデバッガビリティを上げる必要があるな。