6.828: Operating System Engineering (47)
ええと、直前エントリな理解だと
- pgdir_walk でページフレームを一つ確保して page table entry にする
- page_insert では page_walk で新規に確保した pte を適切に処理
- page ディスクリプタの値に合わせた値を PTX(va) の位置に格納
- permission の設定
- 要件な記述の理解がイマイチ
とりあえず
だらだらと pgdir_walk から実装検討。なんとなく以下がでっち上がる。
pte_t * pgdir_walk(pde_t *pgdir, const void *va, int create) { // Fill this function in struct Page *page; pte_t *pte = pgdir[PDX(va)]; if (pte == NULL) { if (create == 0) return NULL; if (page_alloc(&page) == -E_NO_MEM) return NULL; page->pp_ref = 1; memset(page2pa(page), 0, PGSIZE); pte[PTX(va)] = page2pa(page); } return pte; }
例えば以下な試験に通るのかどうか。
// check that pgdir_walk returns a pointer to the pte ptep = KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)])); assert(pgdir_walk(boot_pgdir, (void*)PGSIZE, 0) == ptep+PTX(PGSIZE));
これ、PDX(0x0) も PDX(PGSIZE) も同じ値なので 0x0 で page_insert した後は ptep は存在しとるはずなのですが、なんとなく return しなきゃいけないナニを間違えているような気がします。試験そのまんまな書き方してやろうかな。
return pte + PTX(va);
試験に合わせて手続き定義を書く、ってのはどうなんだろ。でもある意味試験が仕様なので、楽っちゃ楽。
次
page_insert 手続き。なんとなーくざっくりなソレが以下?
int page_insert(pde_t *pgdir, struct Page *pp, void *va, int perm) { // Fill this function in pte_t *pte = pgdir_walk(pgdir, va, ~0); if (pte == NULL) return -E_NO_MEM; *pte = page2pa(pp); *pte = *pte | perm | PTE_P; return 0; }
コメントに要件が列挙されてます。
- If there is already a page mapped at 'va', it should be page_remove()d.
- If necessary, on demand, a page table should be allocated and inserted into 'pgdir'.
- pp->pp_ref should be incremented if the insertion succeeds.
- The TLB must be invalidated if a page was formerly present at 'va'.
ええと、スデに va に map されている page があるかどうかってどうやって調べるのかな。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_t *pte; if (page_lookup(boot_pgdir, va, &pte) != NULL)
な時の pte を page_remove に渡すの? page_remove のプロトタイプてきにはビンゴなカンジがしますがどうなのか。
void page_remove(pde_t *pgdir, void *va)
先に page_lookup と page_remove を作らんと駄目だな。
とりあえず
page_lookup をでっち上げた。
struct Page * page_lookup(pde_t *pgdir, void *va, pte_t **pte_store) { // Fill this function in pte_t *pte = pgdir_walk(pgdir, va, 0); return pte == NULL ? pte : pa2page(pte); }
微妙だけどプロトタイプってことでご容赦下さい。
page_remove
コメントが以下。
// Unmaps the physical page at virtual address 'va'. // If there is no physical page at that address, silently does nothing. // // Details: // - The ref count on the physical page should decrement. // - The physical page should be freed if the refcount reaches 0. // - The pg table entry corresponding to 'va' should be set to 0. // (if such a PTE exists) // - The TLB must be invalidated if you remove an entry from // the pg dir/pg table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref.
あら、tlb_invalidate とか page_decref とかが云々ってあるな。こいつらは実装済みって理解で良いのかな。
とりあえず pte と va の関係って何だったか、と言いつつ pgdir_walk の実装を再確認。あら? page_lookup 使えとか書いてあるな。
とりあえず以下を無理矢理でっち上げてみました。
void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t *pte; struct Page *page = page_lookup(pgdir, va, &pte); page_decref(page); tlb_invalidate(pgdir, va); }
とりあえず、検証は別途ってことで。あと、boot_map_segment 手続きの実装も必要ですが、今日は限界。リキが残ってれば試験します。