6.828: Operating System Engineering (51)

とりあえず remove とか lookup できちんと仕事をさせるべく修正検討。

pgdir_walk

んーと、戻してるのは page table entry の即値だな。check_va2pa だとこれをさらに PTE_ADDR なフィルタにかけたソレを戻してます。
つーかなんとなく間違えてるカンジがするなぁ。
check_va2pa だと

  • pgdir[PDX(va)] の中身に PTE_ADDR なフィルタをかける
  • 出てきたソレを KADDR なフィルタかけて p に代入
  • p[PTX(va)] に PTE_ADDR なフィルタをかける

それが pgdir_walk だと

  • pgdir[PDX(va)] の中身に PTE_ADDR なフィルタをかける
  • 出てきたソレに PTE_ADDR なフィルタをかける
  • さらにそこから出てきたソレに KADDR なフィルタかけて
  • PTX(va) を加えたアドレスを戻す

もう自分ごとですが情無いったらありゃしないorz
とゆーことで pgdir_walk を作り直せば check_va2pa みたく使えるようになるはず。

pgdir_walk 手続きを、以下なカンジにしたら

        pte = (pte_t *)KADDR(PTE_ADDR(*pde));
        *pte |= PTE_P;
    }

    return (pte_t *)PTE_ADDR(pte[PTX(va)]);

動かなくなりました。ちなみに KADDR なフィルタを外したら正常動作 (?) した模様。なぜにこちらは KADDR なフィルタが不要なのか、とか理解できてないのがモロバレ。
あら? そうじゃない。元に戻したら assert に長くパスするなぁ。とりあえず PTE_ADDR なフィルタはムダなので以下なカンジにしてます。

        *pde = page2pa(page);
        *pde |= PTE_P;
        pte = (pte_t *)PTE_ADDR(*pde);
        *pte |= PTE_P;
    }

    return (pte_t *)KADDR((physaddr_t)pte) + PTX(va);

とりあえずここはここで課題とゆーことにしといて、問題解決を。

page_lookup のソレ

とりあえず pgdir_walk は page table の先頭の kva を戻す形になってます。

    assert(pgdir_walk(boot_pgdir, (void*)PGSIZE, 0) == ptep+PTX(PGSIZE));

ので、page_lookup で引数の pte_store に格納されるべきは以下なのかな。

        pte = (pte_t *)PTE_ADDR(pte);
        *pte_store = (pte_t *)pte[PGOFF(va)];

で、page_insert に話を戻すと、現状以下の末端で panic してます。

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

    // should be able to map pp2 at PGSIZE because it's already there
    assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, 0) == 0);
    assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));
    assert(pp2->pp_ref == 1);

page_insert の不具合だな。pp_ref をきちんと制御できていない模様。というか、ごにょごにょしてるんですが、どうもいけません。そもそも va に page ディスクリプタが mapped な状態かどうかをどうやって判断するのか、というと。

  • pgdir_walk の戻りを基に page table entry の中身な phys addr げつ
  • それを使って page ディスクリプタを取得
  • valid かどうかを判断
    • じゃなくて取得できるかどうかで判断するのか

valid かどうか、ってあたりを判断するためには page_remove できちんとクリアされてないと駄目なはず、pte が。あ、remove されたら、あるいは初期状態だったら 0x0 ってのが保証されてる必要があるのか。
とりあえず

  • page_alloc で提供するページは 0 埋め保証
  • page_remove で使用を止めるページは 0 代入

うーん。いいのかなぁ。というか page_remove の中から page_initpp 手続きは呼び出せないみたいなので上記でスルーします。

これが担保されていれば page_insert では pgdir_walk(pgdir, va, 0) の戻りを基に PGOFF(va) なソレを取り出して、その値がどうか、ということを見れば良いのかなぁ。
あら、でも page_insert で新規に確保した page table についてこんなことしてますが本当に良いのかなぁ。

    pte_t *pte = pgdir_walk(pgdir, va, ~0);
    if (pte == NULL)
        return -E_NO_MEM;

    pp->pp_ref++;
    *pte = page2pa(pp);
    *pte = *pte | perm | PTE_P;

試験にパスしてるのが不思議でなりません。というかわしの理解が微妙なのだろうな。