6.828: Operating System Engineering (49)
ええと、page_insert の先頭部分を以下にしてみた。
int page_insert(pde_t *pgdir, struct Page *pp, void *va, int perm) { // Fill this function in pte_t *tmp = pgdir_walk(pgdir, va, 0); if (tmp != NULL && *tmp == page2pa(pp)) { page_remove(pgdir, va); } pte_t *pte = pgdir_walk(pgdir, va, ~0); if (pte == NULL) return -E_NO_MEM;
まだ駄目な模様。ええとこれは tmp じゃなくて pgdir_walk の戻りを PADDR なフィルタをかけないと駄目なのかな。
pte_t *tmp = (pte_t *)PADDR(pgdir_walk(pgdir, va, 0));
違う模様。printf デバッグしながら以下なナニがでっち上がりました。
int page_insert(pde_t *pgdir, struct Page *pp, void *va, int perm) { // Fill this function in pte_t *tmp = pgdir_walk(pgdir, va, 0); if (tmp != NULL && PTE_ADDR(*tmp) == page2pa(pp)) { page_remove(pgdir, va); } pte_t *pte = pgdir_walk(pgdir, va, ~0);
これで pp_ref な assert はパス。直後の以下でコケてます。
// pp2 should NOT be on the free list // could happen in ref counts are handled sloppily in page_insert assert(page_alloc(&pp) == -E_NO_MEM);
これ、どーゆー意味だろうな。page_remove 手続きが微妙なのかな。なんかソレっぽいコメントが page_insert にあるんですが微妙。
// Corner-case hint: Make sure to consider what happens when the same // pp is re-inserted at the same virtual address in the same pgdir.
失敗する assert の直前で page_free_list.lh_first の値を printf してみたら NULL ではない模様。しかしなんで以下なナニで二度目に NG になるんだろ。
// 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)); assert(pp2->pp_ref == 1); // 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); // pp2 should NOT be on the free list // could happen in ref counts are handled sloppily in page_insert assert(page_alloc(&pp) == -E_NO_MEM);
最初のソレは pte が存在してるのでセイフな認識。次のナニは page_remove するケイスのはずなのですが、page_remove が微妙なのかな。
そもそも
// - If there is already a page mapped at 'va', it should be page_remove()d.
の意味を正確に理解できてないのだろうか。あら? page_lookup が微妙なのかな。なんかコメントにそれっぽい記述あり。
// 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.
実装ですが、引数の pte_store は何も操作してません。なんかずるずるバグが出てくるこのカンジはある意味微妙ッス。