xv6のbootloader
xv6_translate/chapter1.md at master · msyksphinz/xv6_translate · GitHub
original UNIX v6
- ROMに保存されているブートストラップローダプログラムが、ルートディスクのブロック番号0にあるブートストラッププログラムをメモリのアドレス0に読み込んで実行する。
- ブートストラッププログラムはルートディスクのファイルシステムから /unix や /rkunixといったカーネルプログラム本体をメモリのアドレス0に読み込んで実行する。
- カーネルがシステムの初期化を行う
電源ON〜kernelをディスクにロード、PCを設定するところまで (1, 2)
わかりやすい
kernel動作開始からinit前まで(3: 主に仮想メモリの初期化)
kernel.ld (リンカスクリプト)
ENTRY(_start)
ENTRY(start)とは、プログラムの実行をstartというシンボルの位置から開始するという意味です。startは.text : { start = . ; ...によって、機械語命令を格納する.textセクションの先頭に設定されます。
_startの位置からしばらく続くBYTE()やLONG()の列によって、所定の機械語命令を直接.textセクションに書き込んでいます。この命令をC風に書くと、だいたい次のようになります。
GNU linker scriptでhello world - Qiita
entry.S
1032 # By convention, the _start symbol specifies the ELF entry point. 1033 # Since we haven’t set up virtual memory yet, our entry point is 1034 # the physical address of ’entry’. 1035 .globl _start // コンパイル時には仮想アドレスとして定義されるが、entryはページングが動作していない状態でスタートするので、物理アドレスに変換している? // ここはちょっとトリッキーだ。entryの場所を仮想アドレスの場所(0x8000_0000以上)に設定するのではなく、無理矢理0x0000_0000の付近に設定している。 // これにより、最初はページングハードウェアがONになっていなくても、entryを読み込んで実行が開始される。 1036 _start = V2P_WO(entry) 1037 1038 # Entering xv6 on boot processor, with paging off. 1039 .globl entry 1040 entry: // ページング機構をONにするプログラムだと思う。それ以上は調べていない。 1041 # Turn on page size extension for 4Mbyte pages 1042 movl %cr4, %eax 1043 orl $(CR4_PSE), %eax 1044 movl %eax, %cr4 ============================================================================ // entrypgdirの詳細は以下 1311 pde_t entrypgdir[NPDENTRIES] = { 1312 // Map VA’s [0, 4MB) to PA’s [0, 4MB) 1313 [0] = (0) | PTE_P | PTE_W | PTE_PS, // 0x0-0x400000 --> 0x00000に変換 1314 // Map VA’s [KERNBASE, KERNBASE+4MB) to PA’s [0, 4MB) 1315 [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, // 0x8000_0000-0x8040_0000 を 0x0000000に変換 1316 }; ============================================================================ 1045 # Set page directory 1046 movl $(V2P_WO(entrypgdir)), %eax // cr3に設定することにより、ページング変換はこの場所から変換を開始するようになる。 1047 movl %eax, %cr3 // ページングを有効にする。それ以上は調べていない。 1048 # Turn on paging. 1049 movl %cr0, %eax 1050 orl $(CR0_PG|CR0_WP), %eax 1051 movl %eax, %cr0 1052 // スタックを有効にする 1053 # Set up the stack pointer. 1054 movl $(stack + KSTACKSIZE), %esp 1055 1056 # Jump to main(), and switch to executing at 1057 # high addresses. The indirect call is needed because 1058 # the assembler produces a PC−relative instruction 1059 # for a direct jump. // mainは0x8000_0000以上の場所になる。従って、ここからはページングハードウェアを利用して仮想アドレス変換が始まる。 // ここから先は、ページングハードウェアによって、変換されるが、mainは0x8010_0000に存在しているつもりが、0x0000_0000に変換される。 1060 mov $main, %eax 1061 jmp *%eax 1062 1063 .comm stack, KSTACKSIZE
MITのxv6を読もう - 第1章 entryはどのような構造? - - FPGA開発日記
main.c
// Boot page table used in entry.S and entryother.S. // Page directories (and page tables), must start on a page boundary, // hence the "__aligned__" attribute. // Use PTE_PS in page directory entry to enable 4Mbyte pages. __attribute__((__aligned__(PGSIZE))) pde_t entrypgdir[NPDENTRIES] = { // Map VA's [0, 4MB) to PA's [0, 4MB) [0] = (0) | PTE_P | PTE_W | PTE_PS, // Map VA's [KERNBASE, KERNBASE+4MB) to PA's [0, 4MB) [KERNBASE>>PDXSHIFT] = (0) | PTE_P | PTE_W | PTE_PS, };
entry用のページテーブルはmain.cに定義されている。 (main.cのその部分だけ以下に載せておきます。ただmain.c全体でも115行しかありません。)