FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MITのxv6を読もう - 第1章 entryはどのような構造? -

そもそも、僕はx86のページテーブルの構造が分かってねえや(笑)。

まずはいろいろ調べてみよう。

softwaretechnique.jp

仮想メモリ方式の分類

Intelx86では、セグメント方式とページング方式を同時に利用することができるのか。xv6ではページングの方式を利用している。

  • セグメント: セグメントのサイズ、開始位置を自由に選択可能 → より複雑なハードウェアが必要になる?
  • ページング: ページのサイズは固定、開始位置はあるオフセットに固定 → ハードウェアが簡単になる?

難しいから、commentaryにやってみよう。以下が、xv6が最初に実行するentryだ。

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