6.828: Operating System Engineering (55)

なんとなく (でもないけど) 直前エントリなナニを盛り込んでコンパイルエラーも取れた
のですが、試験にパスしません。まだまだ微妙な模様。

というか

pgdir_walk は page_table の先頭アドレスを戻す、という考え方自体がダウトな気がしてきました。あ、別に先頭アドレス戻しても良いのですが Requirements の

// - If there is already a page mapped at 'va', it should be page_remove()d.

な記述を見るに pgdir_walk は va にマップされてる pte のアドレスを戻すべき、な気がします。

盛り込み後

なんか以下なあたりで試験にパスしません。

    // should be able to map pp2 at PGSIZE because pp0 is already allocated for page table
    assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, 0) == 0);
    assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));

どうやら page_remove とかのあたりが微妙なのか、と気づく。このあたりはまだ手を入れてませんでした。をー、page_lookup で pgdir_walk 使ってるじゃん。いやはや。
しかも上記な試験で page_remove を呼んでること自体がダウト。
ってかメモリ空間のイメージはデキてるはずなのですが、それを C な手続きに書けてないあたりが非常に情無い限りで。
ただ、おかげでこのハードルを超えた後は凄く楽になりそうではあります。

続き

自宅で続きをナニ。なんとか以下な部分まで来れました。

    // should be able to change permissions too.
    assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, PTE_U) == 0);
    assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
    assert(pp2->pp_ref == 1);
    assert(*pgdir_walk(boot_pgdir, (void*) PGSIZE, 0) & PTE_U);
    assert(boot_pgdir[0] & PTE_U);

いっちゃん下の assert で失敗。これは一体どーゆー意味なんだろ。あ、修正元に以下なコードがあった。

    if (perm & PTE_U)
        pgdir[PDX(va)] |= PTE_U;

とりあえずいっちゃん下の assert にパスするためのソレだと思われます。随分先までパスするようになって次にひっかかったのは以下の下側の assert

    // should not be able to map at PTSIZE because need free page for page table
    assert(page_insert(boot_pgdir, pp0, (void*) PTSIZE, 0) < 0);

    // insert pp1 at PGSIZE (replacing pp2)
    assert(page_insert(boot_pgdir, pp1, (void*) PGSIZE, 0) == 0);
    assert(!(*pgdir_walk(boot_pgdir, (void*) PGSIZE, 0) & PTE_U));

    // should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
    assert(check_va2pa(boot_pgdir, 0) == page2pa(pp1));
    assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1));

あら、これはどーゆー意味なのかな。ええと pp1 は 0x0 な va の page table entry な物理ページを指していたのだけれど、上記の insert で PGSIZE な va の page table entry な物理ページになったということなのかなぁ。
もしかして無条件に page_alloc しちゃ駄目ってこと?

    if(pte == NULL) {
        pte = pgdir_walk(pgdir, va, ~0);
        if (pte == NULL)
            return -E_NO_MEM;
    } else {
        if(*pte != 0x0) {
            page_remove(pgdir, va);
            if(pp == page_lookup(pgdir, va, NULL))
                page_alloc(&pp);
        }
    }

なんとなく上記なカンジでまた数歩進みました。

    // ... and ref counts should reflect this
    assert(pp1->pp_ref == 2);
    assert(pp2->pp_ref == 0);

    // pp2 should be returned by page_alloc
    assert(page_alloc(&pp) == 0 && pp == pp2);

    // unmapping pp1 at 0 should keep pp1 at PGSIZE
    page_remove(boot_pgdir, 0x0);
    assert(check_va2pa(boot_pgdir, 0x0) == ~0);

面白くはあるのですが果てが無いな。
とりあえず Hadoop 弄くる課題設定してたりするので今からはそちらで手を動かしつつクタバる方向ッス。