6.828: Operating System Engineering (41)

pmap.c の試験な手続きを読みます。

check_page_alloc

先頭から順に、が良いのか呼ばれる順が良いのか分かりませんがとりあえず check_page_alloc から。

    LIST_FOREACH(pp0, &page_free_list, pp_link) {
        // check that we didn't corrupt the free list itself
        assert(pp0 >= pages);
        assert(pp0 < pages + npage);

        // check a few pages that shouldn't be on the free list
        assert(page2pa(pp0) != 0);
        assert(page2pa(pp0) != IOPHYSMEM);
        assert(page2pa(pp0) != EXTPHYSMEM - PGSIZE);
        assert(page2pa(pp0) != EXTPHYSMEM);
        assert(page2kva(pp0) != ROUNDDOWN(boot_freemem - 1, PGSIZE));
    }

LIST_FOREACH とか LIST_NEXT とかは略します。

  • pp0 は pages な配列の_使用可能な_全ての要素を iterate します
    • pp0 は pages 以上、pages + npage より小さくなければならない
    • pp0 を phys address に変換した値は 0 ではないこと
    • pp0 を phys address に変換した値は IOPHYSMEM (0x0A0000) ではないこと
    • pp0 を phys address に変換した値は EXTPHYSMEM (0x100000) - PGSIZE (4096) ではないこと
      • これ、IOPHYSMEM から EXTPHYSMEM までは使用できん、というアレの試験なのかな
    • pp0 を phys address に変換した値は EXTPHYSMEM (0x100000) ではないこと
    • pp0 を virtual address に変換した値はカーネルで割り当て済みな領域でないこと
      • これはカーネルが boot_alloc で assign したメモリ領域をページフレームとして使用可能としていないか、なチェックですね

一応、現状の page_init では上記はパスするはずです。次が以下。

    // should be able to allocate three pages
    pp0 = pp1 = pp2 = 0;
    assert(page_alloc(&pp0) == 0);
    assert(page_alloc(&pp1) == 0);
    assert(page_alloc(&pp2) == 0);

    assert(pp0);
    assert(pp1 && pp1 != pp0);
    assert(pp2 && pp2 != pp1 && pp2 != pp0);
    assert(page2pa(pp0) < npage*PGSIZE);
    assert(page2pa(pp1) < npage*PGSIZE);
    assert(page2pa(pp2) < npage*PGSIZE);

ここは page_alloc した三つの領域が別な場所に確保されてて、phys address てきにも問題ないこと、を確認している、はず。
次は

    // temporarily steal the rest of the free pages
    fl = page_free_list;
    LIST_INIT(&page_free_list);

いったん空きが無い状態にしといて (fl に現状は保管)

    // should be no free memory
    assert(page_alloc(&pp) == -E_NO_MEM);

空きが無いから page_alloc は -E_NO_MEM 戻すよね、という確認。
次に、スデに確保済みだった領域を解放してそれぞれ確保可能なことと、それ以上は確保できないことを確認。

    // free and re-allocate?
    page_free(pp0);
    page_free(pp1);
    page_free(pp2);
    pp0 = pp1 = pp2 = 0;
    assert(page_alloc(&pp0) == 0);
    assert(page_alloc(&pp1) == 0);
    assert(page_alloc(&pp2) == 0);
    assert(pp0);
    assert(pp1 && pp1 != pp0);
    assert(pp2 && pp2 != pp1 && pp2 != pp0);
    assert(page_alloc(&pp) == -E_NO_MEM);

で、元に戻して

    // give free list back
    page_free_list = fl;

使ってたソレを解放。

    // free the pages we took
    page_free(pp0);
    page_free(pp1);
    page_free(pp2);

現時点で page_alloc が微妙な可能性があるのですが、上記な試験はパスするはずです。次は page_check を確認します。

page_check

まず、page_alloc して別な領域に確保されているかどうかを確認。

    // should be able to allocate three pages
    pp0 = pp1 = pp2 = 0;
    assert(page_alloc(&pp0) == 0);
    assert(page_alloc(&pp1) == 0);
    assert(page_alloc(&pp2) == 0);

    assert(pp0);
    assert(pp1 && pp1 != pp0);
    assert(pp2 && pp2 != pp1 && pp2 != pp0);

空き領域が無い状態にしておいて

    // temporarily steal the rest of the free pages
    fl = page_free_list;
    LIST_INIT(&page_free_list);

page_alloc できないことを確認。

    // should be no free memory
    assert(page_alloc(&pp) == -E_NO_MEM);

次でコケてるはず。

    // there is no page allocated at address 0
    assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL);

あ、違うや。今の実装はこうなってます。

struct Page *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
	// Fill this function in
	return NULL;
}

ので、パスしないとマズい。現在の課題としてはこの試験をパスするために pgdir_walk を実装しないといけないのだけどorz という状況のはず。
それは良いのですが、この手続きが何をしなければ良いのか、というと以下らしい。

// Return the page mapped at virtual address 'va'.
// If pte_store is not zero, then we store in it the address
// of the pte for this page.  This is used by page_remove and
// can be used to verify page permissions for syscall arguments,
// but should not be used by most callers.
//
// Return NULL if there is no page mapped at va.
//
// Hint: the TA solution uses pgdir_walk and pa2page.
  • virtual address に map されてる struct Page * を戻す
  • pte_store が 0 でなければこのページの pte を設定
  • 呼び出し元はとりあえず page_remove な模様

とりあえず、この続きは明日以降、ということで。