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 な模様
とりあえず、この続きは明日以降、ということで。