※ この記事はまだ勉強中のため、いろいろ間違いがあるかもしれません。
xv6のbootmain.cなどのブートローダは、まだセグメントやページテーブルが有効な状態としては利用されない。 実際にOSを動かすとなれば、ページテーブルが必須となるが、これはどのようにして設定しているのだろうか。
X86番のxv6では、bootmainからentryに飛ぶ直前に、エントリを設定してセグメントを有効にしている。 ここでは、0x0010_0000番地にロードされたデータが、全て0x8010_0000として読み込まれるようにセグメントを設定することで、entryから先は0x8010_0000にアクセスすることで、プログラムにアクセスできるようになっている。
ここで、kernel.ldを見てみよう。
SECTIONS { /* Link the kernel at this address: "." means the current address */ /* Must be equal to KERNLINK */ . = 0x80100000; .text : AT(0x100000) { *(.text .stub .text.* .gnu.linkonce.t.*) }
見て分かるとおり、プログラムがロードされるのは0x8010_0000だが、実行されるのは0x0010_0000からフェッチされることを想定している。 セグメントが有効になった場合に、0x0010_0000からフェッチが開始される訳だ。
bootmain.cでは、ディスクイメージからカーネルをメモリにロードした後、entryを見つけて、そこからプログラムを開始するようにしている。
void bootmain(void) { struct elfhdr *elf; struct proghdr *ph, *eph; void (*entry)(void); uchar* pa; elf = (struct elfhdr*)0x10000; // scratch space // Read 1st page off disk readseg((uchar*)elf, 4096, 0); // Is this an ELF executable? if(elf->magic != ELF_MAGIC) return; // let bootasm.S handle error // Load each program segment (ignores ph flags). ph = (struct proghdr*)((uchar*)elf + elf->phoff); eph = ph + elf->phnum; for(; ph < eph; ph++){ pa = (uchar*)ph->paddr; readseg(pa, ph->filesz, ph->off); if(ph->memsz > ph->filesz) stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz); } // Call the entry point from the ELF header. // Does not return! // ここがプログラムの開始だ。 entry = (void(*)(void))(elf->entry); entry(); }
そして、entryはentry.Sに記述されている。
# Entering xv6 on boot processor, with paging off. .globl entry entry: # Turn on page size extension for 4Mbyte pages movl %cr4, %eax orl $(CR4_PSE), %eax movl %eax, %cr4 # Set page directory movl $(V2P_WO(entrypgdir)), %eax movl %eax, %cr3 # Turn on paging. movl %cr0, %eax orl $(CR0_PG|CR0_WP), %eax movl %eax, %cr0 # Set up the stack pointer. movl $(stack + KSTACKSIZE), %esp # Jump to main(), and switch to executing at # high addresses. The indirect call is needed because # the assembler produces a PC-relative instruction # for a direct jump. mov $main, %eax jmp *%eax
ここで、ページテーブルを有効にして、やっとmainに飛ぶ訳だ。 さて、今度は、これをMIPSに移植していこう。