※ この記事はまだ勉強中のため、いろいろ間違いがあるかもしれません。
さて、xv6のmainに足を踏み入れると、以下のようなコードが記述されている。
extern char end[]; // first address after kernel loaded from ELF file // Bootstrap processor starts running C code here. // Allocate a real stack and switch to it, first // doing some setup required for memory allocator to work. int main(void) { kinit1(end, P2V(4*1024*1024)); // phys page allocator kvmalloc(); // kernel page table mpinit(); // collect info about this machine cprintf("\ncpu%d: starting xv6\n\n", cpu->id); picinit(); // interrupt controller consoleinit(); // I/O devices & their interrupts uartinit(); // serial port pinit(); // process table tvinit(); // trap vectors binit(); // buffer cache fileinit(); // file table iinit(); // inode cache ideinit(); // disk timerinit(); // uniprocessor timer, we don't support multicore for MIPS. kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() userinit(); // first user process // Finish setting up this processor in mpmain. mpmain(); }
kinit1とkinit2の中身を見てみよう。kalloc.c に配置されている。
// Initialization happens in two phases. // 1. main() calls kinit1() while still using entrypgdir to place just // the pages mapped by entrypgdir on free list. // 2. main() calls kinit2() with the rest of the physical pages // after installing a full page table that maps them on all cores. void kinit1(void *vstart, void *vend) { initlock(&kmem.lock, "kmem"); kmem.use_lock = 0; freerange(vstart, vend); } void kinit2(void *vstart, void *vend) { freerange(vstart, vend); kmem.use_lock = 1; } void freerange(void *vstart, void *vend) { char *p; p = (char*)PGROUNDUP((uint)vstart); for(; p + PGSIZE <= (char*)vend; p += PGSIZE) kfree(p); }
kinit1はxv6のプログラム領域の最後から、4MBまでの領域を初期化し、フリーアドレススペースに挿入するようになっている。 フリーアドレススペースに挿入する仕組み自体は、kfree(p)によって実現されている。
kinit1(end, P2V(4*1024*1024)); // phys page allocator ... void kfree(char *v) { struct run *r; if((uint)v % PGSIZE || v < end || v2p(v) >= PHYSTOP) panic("kfree"); // Fill with junk to catch dangling refs. memset(v, 1, PGSIZE); if(kmem.use_lock) acquire(&kmem.lock); r = (struct run*)v; r->next = kmem.freelist; kmem.freelist = r; if(kmem.use_lock) release(&kmem.lock); }
endはプログラム領域の最後として、kernel.ldに定義されている。
... PROVIDE(edata = .); .bss : { *(.bss) } PROVIDE(end = .); /DISCARD/ : { *(.eh_frame .note.GNU-stack) }
このプログラムはアドレス0から4MBの領域をユーザ領域として使うようだが、実際にはendまではプログラムが含まれているので、 endから4MBまでの領域を初期化するようになっている。 ところが、MIPSでコンパイルしたコードを実行すると、MIPSのkernelは4MBを越えてしまい、初期化する領域が無くなってしまった。 これにより、カーネルがパニックを起こす。
kfree(char *v) { struct run *r; if((uint)v % PGSIZE || v < end || v2p(v) >= PHYSTOP) panic("kfree");
開放する領域がendよりも小さい場所だと、パニックするような仕組みになっているのだ。 これを回避するために、今回の移植では、メモリとして確保する領域を8MBに増やした。
index 0166c0f..834a817 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ extern char end[]; // first address after kernel loaded from ELF file int main(void) { - kinit1(end, P2V(4*1024*1024)); // phys page allocator + kinit1(end, P2V(8*1024*1024)); // phys page allocator kvmalloc(); // kernel page table mpinit(); // collect info about this machine cprintf("\ncpu%d: starting xv6\n\n", cpu->id); @@ -32,7 +32,7 @@ main(void) iinit(); // inode cache ideinit(); // disk timerinit(); // uniprocessor timer, we don't support multicore for MIPS. - kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers() + kinit2(P2V(8*1024*1024), P2V(PHYSTOP)); // must come after startothers() userinit(); // first user process
これを実行することで、無事にメモリ初期化の領域は通過するようになったが、別の部分で止まってしまった。 そしてかなりシミュレーションに時間がかかる。この辺りも改善していこう。
swimmer_mips --imgfile ~/xv6-mips/xv6.img --max 1000000000 Swimmer-RISCV Version 20150910 Revision d8cf377 developed by Masayuki Kimura <masayuki.kimura.1986@gmail.com> <Info: NewMemory Region 1fc00000 is defined.> <Info: NewMemory Region 0050d000 is defined.> <Info: NewMemory Region 0050e000 is defined.> <Info: NewMemory Region 0050f000 is defined.> <Info: NewMemory Region 00510000 is defined.> <Info: NewMemory Region 00511000 is defined.> <Info: NewMemory Region 00512000 is defined.> <Info: NewMemory Region 00513000 is defined.> <Info: NewMemory Region 00514000 is defined.> <Info: NewMemory Region 00515000 is defined.> <Error: CSR Address 018 is invalid.> <Error: CSR Address 028 is invalid.> xv6... <Info: NewMemory Region 00000000 is defined.> cpu0: panic: inituvm: more than a page