6.828: Operating System Engineering (76)

実は

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

以降の部分ってあまりきちんと読んでいなかったりするので、こーゆータイミングがあって良かったと思ってます。おそらくは inc/memlayout.h のコメントなマンガにあるレイアウトと権限の設定を行なっているはず。

UPAGES

最初は UPAGES な領域の設定らしい。inc/memlayout.h のマンガが以下。

 *    UVPT      ---->  +------------------------------+ 0xef400000
 *                     |          RO PAGES            | R-/R-  PTSIZE
 *    UPAGES    ---->  +------------------------------+ 0xef000000

ちなみに手続きの記述は以下な形なのですが、

    //////////////////////////////////////////////////////////////////////
    // 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
    // Your code goes here:
    boot_pgdir[PDX(UPAGES)] |= PTE_U;
    boot_map_segment(boot_pgdir, UPAGES, ROUNDUP(npage*sizeof(struct Page), PGSIZE), PADDR(pages), PTE_W | PTE_P);

boot_map_segment って何でしょ。おそらく pages なナニを UPAGES に map させてるのだろうと思いますが、この手続きは未掘ですな。見てみます。
まずコメントから。

// Map [la, la+size) of linear address space to physical [pa, pa+size)
// in the page table rooted at pgdir.  Size is a multiple of PGSIZE.
// Use permission bits perm|PTE_P for the entries.
//
// This function is only intended to set up the ``static'' mappings
// above UTOP. As such, it should *not* change the pp_ref field on the
// mapped pages.
//
// Hint: the TA solution uses pgdir_walk

あら? これって自分で作ってるんじゃん。全く記憶にございませんでしたよ。しかもバグってるの見つけた。_Use permission bits perm|PTE_P for the entries._なソレを見つつ実装見てズッコケてたり。実装以下です。

static void
boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
{
    // Fill this function in
    int i, j, pg_idx = 0;
    physaddr_t tmp_pa;
    for(i = 0; i < size; i += PGSIZE) {
        pte_t *pte = pgdir_walk(pgdir, (void *)la + i, 0);

        if(pte == NULL) {
            pte = pgdir_walk(pgdir, (void *)la + i, ~0);
            if (pte == NULL)
                return;
        }

        if (perm & PTE_P)
            *pte = (pa + i) | perm;
    }
}

最後のソレは

        *pte = (pa + i) | perm | PTE_P;

ですなorz
あ、PTE_P は呼び出し元で指定してくれてるみたいなので略で良いみたい。
この実装だと、pages な領域の大きさが PTSIZE の範疇 (4MB?) に収まる、を前提に作成されている模様。約 1GB 程度のメモリ容量には対応できるのかどうか。

Kernel Stack

次は以下な部分の面倒を見ている模様。

 *    VPT,KSTACKTOP--> +------------------------------+ 0xefc00000      --+
 *                     |         Kernel Stack         | RW/--  KSTKSIZE   |
 *                     | - - - - - - - - - - - - - - -|                 PTSIZE
 *                     |      Invalid Memory (*)      | --/--             |
 *    ULIM     ------> +------------------------------+ 0xef800000      --+

ええと、コメント以下ッス。

    // 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

bootstack なるソレの確保は以下。(kern/entry.S)

###################################################################
# boot stack
###################################################################
	.p2align	PGSHIFT		# force page alignment
	.globl		bootstack
bootstack:
	.space		KSTKSIZE
	.globl		bootstacktop   
bootstacktop:

entry.S の別場所で stack pointer に設定されております。
で、コメントの記述で面白いのは Invalid Memory な部分で、権限を付けてないことで stack overflow が検知できる、のかな。"guard page" として知られてます的記述あり。
実装が以下。

    boot_map_segment(boot_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_P);
    boot_map_segment(boot_pgdir, ULIM, PTSIZE - KSTKSIZE, 0, 0);

KERNBASE

どんどん行きます。以下なあたりな模様。

 *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
 *                     |                              | RW/--
 *                     |   Remapped Physical Memory   | RW/--
 *                     |                              | RW/--
 *    KERNBASE ----->  +------------------------------+ 0xf0000000

コメントが以下。

    // 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

となると確かにこれはこうですね。

    boot_map_segment(boot_pgdir, KERNBASE, 0xffffffff - KERNBASE, 0, PTE_P|PTE_W);

とは言え微妙にイメージし辛かったりしますorz

ここでまた試験が出てくる

check_boot_pgdir という手続きです。このあたりから相当ハマッたらしく printf デバッグの痕跡が未だ残っています。
この手続きも仕様理解のため、確認してみます。と言いつつ勉強会な割り込みがそろそろ入るので、エントリ投入しちまえ。