6.828: Operating System Engineering (57)

boot_map_segment の検討。pgdir の UTOP から末端までなのか分かりませんが、pgdir にマップを作成せよ、とのことなのかな。
ちなみに PTSIZE の定義は

// Page directory and page table constants.
#define NPDENTRIES	1024		// page directory entries per page directory
#define NPTENTRIES	1024		// page table entries per page table

#define PGSIZE		4096		// bytes mapped by a page
#define PGSHIFT		12		// log2(PGSIZE)

#define PTSIZE		(PGSIZE*NPTENTRIES) // bytes mapped by a page directory entr
#define PTSHIFT		22		// log2(PTSIZE)

みたいなカンジになってて、pgdir の一つの要素が指してる領域のサイズ、という理解で良いのかな。つーか、boot_map_segment って現時点ではどこからも呼び出されていないのか。

うーむ

今ひとつ何をすれば良いのかがよく分からんので check_boot_pgdir を読むことから始めます。ええと check_va2pa 手続きは va が居るページテーブルの先頭 pa が戻ってくるということを押さえつつ pmap.c の全体を確認してるのですが、i386_vm_init 手続きに以下な記述があるのを見つけてます。

    //////////////////////////////////////////////////////////////////////
    // Recursively insert PD in itself as a page table, to form
    // a virtual page table at virtual address VPT.
    // (For now, you don't have understand the greater purpose of the
    // following two lines.)

    // Permissions: kernel RW, user NONE
    pgdir[PDX(VPT)] = PADDR(pgdir)|PTE_W|PTE_P;

    // same for UVPT
    // Permissions: kernel R, user R 
    pgdir[PDX(UVPT)] = PADDR(pgdir)|PTE_U|PTE_P;

ええととりあえず上記で pgdir[PDX(VPT)] および pgdir[PDX(UVPT)] は non-zero ってことになるのか。あ、

    //////////////////////////////////////////////////////////////////////
    // Now we set up virtual memory 

以降の部分で boot_map_segment を使って

  • UPAGES
  • kernel stack
  • KERNBASE

あたりを map する、ということになるのか成程。
で、check_boot_pgdir 手続きなんですが、まず UPAGES あたりの確認をしてます。

    // check pages array
    n = ROUNDUP(npage*sizeof(struct Page), PGSIZE);
    for (i = 0; i < n; i += PGSIZE)
        assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);

ん、これってどーゆー意味だろ。check_va2pa は渡された va のページテーブル先頭 kva を戻す、ので 4096 おきに目印付けとけ、ってことなのかな。
なんとなく、いきなり boot_map_segment 書いてしまうより、こっちの試験のソレを確認してから実装検討した方が良さげですね。この部分のヒントは i386_vm_init 手続きにもコメントとして記載がありますね。

    // Map 'pages' read-only by the user at linear address UPAGES
    // Permissions:
    //    - the new image at UPAGES -- kernel R, user R
    //      (ie. perm = PTE_U | PTE_P)
    //    - pages itself -- kernel RW, user NONE

次のテスツは KERNBASE のマップの試験なのか。

    // check phys mem
    for (i = 0; i < npage * PGSIZE; i += PGSIZE)
        assert(check_va2pa(pgdir, KERNBASE + i) == i);

i386_vm_init なコメントが以下。

    // Map all of physical memory at KERNBASE. 
    // Ie.  the VA range [KERNBASE, 2^32) should map to
    //      the PA range [0, 2^32 - KERNBASE)
    // We might not have 2^32 - KERNBASE bytes of physical memory, but
    // we just set up the mapping anyway.
    // Permissions: kernel RW, user NONE

作れたページ分はマップしとけ、ってことなのかな。ここまでの時点で UPAGES と KERNBASE 分の page table は作成されてないといけないはず。pgdir_walk 使うのであれば page table の確保はどこかでヤッたな。
で、もひとつが kernel stack 云々。

    // check kernel stack
    for (i = 0; i < KSTKSIZE; i += PGSIZE)
        assert(check_va2pa(pgdir, KSTACKTOP - KSTKSIZE + i) == PADDR(bootstack) + i);
    assert(check_va2pa(pgdir, KSTACKTOP - PTSIZE) == ~0);

う、bootstack って何だ。pmap.c では定義されてない。探してみると kern/pmap.h で char * として定義されとるのかな。

extern char bootstacktop[], bootstack[];

i386_vm_init 手続きなコメントが以下。

    // Use the physical memory that 'bootstack' refers to as the kernel
    // stack.  The kernel stack grows down from virtual address KSTACKTOP.
    // We consider the entire range from [KSTACKTOP-PTSIZE, KSTACKTOP) 
    // to be the kernel stack, but break this into two pieces:
    //     * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory
    //     * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed; so if
    //       the kernel overflows its stack, it will fault rather than
    //       overwrite memory.  Known as a "guard page".
    //     Permissions: kernel RW, user NONE

ここでも stack として有効な領域は page table が作成されている模様。あと guard page なるソレについては存在フラグを落としているのが分かります。page table は確保せずに pgdir に直接、で OK なのかどうなのか。
あと、最後に以下な試験をしてます。

    for (i = 0; i < NPDENTRIES; i++) {
        switch (i) {
        case PDX(VPT):
        case PDX(UVPT):
        case PDX(KSTACKTOP-1):
        case PDX(UPAGES):
            assert(pgdir[i]);
            break;
        default:
            if (i >= PDX(KERNBASE))
                assert(pgdir[i]);
            else
                assert(pgdir[i] == 0);
            break;
        }
    }

おそらく上記で列挙したソレを盛り込めば page directory は上記の形で初期化されてるはずなのですが、初期値が 0 かどうかは確認必要かも。