void page_check(void) { struct Page *pp, *pp0, *pp1, *pp2; struct Page_list fl; pte_t *ptep; // 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); // should be no free memory assert(page_alloc(&pp) == -E_NO_MEM); // DEP Extra tests // Fill pp1 with bogus data and check for invalid tlb entries memset(page2kva(pp1), 0xFFFFFFFF, PGSIZE); // there is no page allocated at address 0 assert(page_lookup(boot_pgdir, (void *) 0x0, &ptep) == NULL); // there is no free memory, so we can't allocate a page table assert(page_insert(boot_pgdir, pp1, 0x0, 0) < 0); // free pp0 and try again: pp0 should be used for page table page_free(pp0); assert(page_insert(boot_pgdir, pp1, 0x0, 0) == 0); tlb_invalidate(boot_pgdir, 0x0); // DEP Should have shot down invalid TLB entry - let's check { int *x = 0x0; assert(*x == 0xFFFFFFFF); } assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0)); assert(check_va2pa(boot_pgdir, 0x0) == page2pa(pp1)); assert(pp1->pp_ref == 1); assert(pp0->pp_ref == 1); // 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); // DEP Extra test: // Make sure that pgdir_walk returns a pointer to the pte and // not the table or some other garbage { pte_t *p = KADDR(PTE_ADDR(boot_pgdir[PDX(PGSIZE)])); assert(pgdir_walk(boot_pgdir, (void *)PGSIZE, 0) == &p[PTX(PGSIZE)]); } // 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, PTE_U) == 0); assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2)); assert(pp2->pp_ref == 1); // DEP Extra test: // Make sure that we actually changed the permission on pp2 when we re-mapped it { pte_t *p = pgdir_walk(boot_pgdir, (void*)PGSIZE, 0); assert(((*p) & PTE_U) == PTE_U); } // 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); // 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); // 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)); // ... 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); assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp1)); assert(pp1->pp_ref == 1); assert(pp2->pp_ref == 0); // unmapping pp1 at PGSIZE should free it page_remove(boot_pgdir, (void*) PGSIZE); assert(check_va2pa(boot_pgdir, 0x0) == ~0); assert(check_va2pa(boot_pgdir, PGSIZE) == ~0); assert(pp1->pp_ref == 0); assert(pp2->pp_ref == 0); // so it should be returned by page_alloc assert(page_alloc(&pp) == 0 && pp == pp1); // should be no free memory assert(page_alloc(&pp) == -E_NO_MEM); // forcibly take pp0 back assert(PTE_ADDR(boot_pgdir[0]) == page2pa(pp0)); boot_pgdir[0] = 0; assert(pp0->pp_ref == 1); pp0->pp_ref = 0; // DEP Extra test: // Catch invalid pointer addition in pgdir_walk - i.e. pgdir + PDX(va) { // Give back pp0 for a bit page_free(pp0); void * va = (void *)((PGSIZE * NPDENTRIES) + PGSIZE); pte_t *p2 = pgdir_walk(boot_pgdir, va, 1); pte_t *p = KADDR(PTE_ADDR(boot_pgdir[PDX(va)])); assert(p2 == &p[PTX(va)]); // Clean up again boot_pgdir[PDX(va)] = 0; pp0->pp_ref = 0; } // give free list back page_free_list = fl; // free the pages we took page_free(pp0); page_free(pp1); page_free(pp2); cprintf("page_check() succeeded!\n"); }