Example #1
0
File: pmap.c Project: ajsbu/cse506
	pte_t *
pml4e_walk(pml4e_t *pml4e, const void *va, int create)
{
	struct Page *newPage = NULL;

	//if(!create) cprintf("va = %0x, pml4e[PML4(va)] = %0x\n", va, pml4e[PML4(va)]);
	if (!pml4e[PML4(va)]) {
		if (!create)
			return NULL;
		else {
			newPage = page_alloc(0);
			if (newPage == 0) {
				return NULL;
			} else {
				newPage->pp_ref++;
				pml4e[PML4(va)] = page2pa(newPage) | PTE_U | PTE_W | PTE_P;
				memset(page2kva(newPage), 0x00, PGSIZE);
			}

		}
	}

	pdpe_t* pdpe = (pdpe_t*)(KADDR((PTE_ADDR(pml4e[PML4(va)]))));
	pte_t *result = pdpe_walk(pdpe, va, create);

	if (!result && newPage) {
		pml4e[PML4(va)] = 0;
		newPage->pp_ref = 0;
		page_free(newPage);
	}

	//return result + PTX(va);

	if (result) {
		return result + PTX(va);
	}
	else {
		return result;
	}


}
Example #2
0
//
// Initialize the kernel virtual memory layout for environment e.
// Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
// and initialize the kernel portion of the new environment's address space.
// Do NOT (yet) map anything into the user portion
// of the environment's virtual address space.
//
// Returns 0 on success, < 0 on error.  Errors include:
//	-E_NO_MEM if page directory or table could not be allocated.
//
static int
env_setup_vm(struct Env *e)
{
	int i, r;
	struct Page *p = NULL;

	// Allocate a page for the page directory
	if ((r = page_alloc(&p)) < 0)
		return r;

	// Now, set e->env_pgdir and e->env_cr3,
	// and initialize the page directory.
	//
	// Hint:
	//    - The VA space of all envs is identical above UTOP
	//      (except at VPT and UVPT, which we've set below).
	//	See inc/memlayout.h for permissions and layout.
	//	Can you use boot_pgdir as a template?  Hint: Yes.
	//	(Make sure you got the permissions right in Lab 2.)
	//    - The initial VA below UTOP is empty.
	//    - You do not need to make any more calls to page_alloc.
	//    - Note: pp_ref is not maintained for most physical pages
	//	mapped above UTOP -- but you do need to increment
	//	env_pgdir's pp_ref!

	// LAB 3: Your code here.
	e->env_pgdir = page2kva(p);
	e->env_cr3 = page2pa(p);
	memset(e->env_pgdir, 0, PGSIZE);
	p->pp_ref++;
	for(i = PDX(UTOP); i < NPDENTRIES; i++){
		e->env_pgdir[i] = boot_pgdir[i];
	}

	// VPT and UVPT map the env's own page table, with
	// different permissions.
	e->env_pgdir[PDX(VPT)]  = e->env_cr3 | PTE_P | PTE_W;
	e->env_pgdir[PDX(UVPT)] = e->env_cr3 | PTE_P | PTE_U;
	//cprintf("env_setup_vm end!!\n");

	return 0;
}
Example #3
0
File: e100.c Project: mcorley/jos
//
// Allocate the receive frame area.
//
// Initialize the RFA setting each rds's link pointer to point to the next RFD 
// in the ring. The pointers need to be physical addresses because a DMA ring 
// is created to be used by the device and a device on the PCI bus does not 
// have access to the CPU's MMU to translate virtual addresses into physical 
// addresses.
//
void
e100_rfa_alloc(void) 
{
	int i, r;
	struct Page *pp;
	struct rfd *rfd = NULL, *tail = NULL;

	for (i = 0; i < RFASIZE; i++) {
		// Allocate a page for each command block.
		// Must zero out the contents of the page and
		// increment the reference count for it.
		if ((r = page_alloc(&pp)) != 0)
			panic("e100_rfa_alloc: %e\n", r);
		memset(page2kva(pp), 0, PGSIZE);
		++pp->pp_ref;

		// Initialize the RFD
		rfd = page2kva(pp);
		rfd->pa = page2pa(pp);
		rfd->size = ETH_FRAME_LEN;

		if (i == 0) {
			e100.rfds = rfd;
		} else {
			// Extend the RFA by inserting the RFD 
			// after the current tail in the list.
			tail->link = rfd->pa;
			tail->next = rfd;
			rfd->prev = tail;
		}
		// Set the new tail.
		tail = rfd;
	}
	// Complete the ring.
	tail->link = e100.rfds->pa;
	tail->next = e100.rfds;
	e100.rfds->prev = tail;

	e100.rfds_avail = RFASIZE;
	e100.rfd_to_clean = tail;
	e100.rfd_to_use = e100.rfds;
}
Example #4
0
int
page_insert(pgd_t *pgdir, struct Page *page, uintptr_t la, uint32_t perm) {
    pte_t *ptep = get_pte(pgdir, la, 1);
    if (ptep == NULL) {
        return -E_NO_MEM;
    }
    page_ref_inc(page);
    if (*ptep & PTE_P) {
        struct Page *p = pte2page(*ptep);
        if (p == page) {
            page_ref_dec(page);
        }
        else {
            page_remove_pte(pgdir, la, ptep);
        }
    }
    *ptep = page2pa(page) | PTE_P | perm;
    tlb_invalidate(pgdir, la);
    return 0;
}
Example #5
0
//
// Map the physical page 'pp' at virtual address 'va'.
// The permissions (the low 12 bits) of the page table entry
// should be set to 'perm|PTE_P'.
//
// Requirements
//   - 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'.
//
// 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.
// However, try not to distinguish this case in your code, as this
// frequently leads to subtle bugs; there's an elegant way to handle
// everything in one code path.
//
// RETURNS:
//   0 on success
//   -E_NO_MEM, if page table couldn't be allocated
//
// Hint: The TA solution is implemented using pgdir_walk, page_remove,
// and page2pa.
//
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
	// Fill this function in
	pte_t *ptep = pgdir_walk(pgdir, va, true);
	if (!ptep)
		return -E_NO_MEM;
	//这儿非常trick!
	//如果va, pp和以前的调用的page_insert相同,且pp->pp_ref++写在page_remove()
	//下面的话, page_remove()就会把pp放到page_free_list上了
	//所以必须先ref++,再检测page_remove()
	pp->pp_ref++;
	if (*ptep & PTE_P)
		page_remove(pgdir, va);
	*ptep = page2pa(pp) | perm | PTE_P;
	//page directory的权限
	pgdir[PDX(va)] |= *ptep & 0xfff;
	tlb_invalidate(pgdir, va);
	return 0;
}
Example #6
0
//
// Initialize the kernel virtual memory layout for environment e.
// Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
// and initialize the kernel portion of the new environment's address space.
// Do NOT (yet) map anything into the user portion
// of the environment's virtual address space.
//
// Returns 0 on success, < 0 on error.  Errors include:
//	-E_NO_MEM if page directory or table could not be allocated.
//
static int
env_setup_vm(struct Env *e)
{
	int i, r;
	struct Page *p = NULL;

	// Allocate a page for the page directory
	if ((r = page_alloc(&p)) < 0)
		return r;
	// Now, set e->env_pgdir and e->env_cr3,
	// and initialize the page directory.
	// Hint:
	//    - Remember that page_alloc doesn't zero the page.
	//    - The VA space of all envs is identical above UTOP
	//	(except at VPT and UVPT, which we've set below).
	//	See inc/memlayout.h for permissions and layout.
	//	Can you use boot_pgdir as a template?  Hint: Yes.
	//	(Make sure you got the permissions right in Lab 2.)
	//    - The initial VA below UTOP is empty.
	//    - You do not need to make any more calls to page_alloc.
	//    - Note: In general, pp_ref is not maintained for
	//	physical pages mapped only above UTOP, but env_pgdir
	//	is an exception -- you need to increment env_pgdir's
	//	pp_ref for env_free to work correctly.
	//    - The functions in kern/pmap.h are handy.
	// LAB 3: Your code here.

	//sunus,DEC 6,2010 
	p->pp_ref++;
	e->env_pgdir = page2kva(p); 
	e->env_cr3 = page2pa(p);
	memset(e->env_pgdir, 0, PDX(UTOP) * 4);
	memmove(&(e->env_pgdir[PDX(UTOP)]), &(boot_pgdir[PDX(UTOP)]),(1024 - PDX(UTOP)) * 4);
	//sunus,DEC 6,2010
	// VPT and UVPT map the env's own page table, with
	// different permissions.
	e->env_pgdir[PDX(VPT)]  = e->env_cr3 | PTE_P | PTE_W;
	e->env_pgdir[PDX(UVPT)] = e->env_cr3 | PTE_P | PTE_U;

	return 0;
}
Example #7
0
/**
 * Allocate CB_MAX_NUM pages, each page for a control block
 */
static void
cbl_alloc () {
    int i, r;
    struct Page *p;
    struct cb *prevcb = NULL;
    struct cb *currcb = NULL;

    // Allocate physical page for Control block
    for (i = 0; i < CB_MAX_NUM; i++) {

        if ((r = page_alloc (&p)) != 0)
            panic ("cbl_init: run out of physical memory! %e\n", r);

        p -> pp_ref ++;
        memset (page2kva (p), 0, PGSIZE);

        currcb = (struct cb *)page2kva (p);
        currcb->phy_addr = page2pa (p);


        if (i == 0)
            nic.cbl.start = currcb;
        else {
            prevcb->cb_link = currcb->phy_addr;
            prevcb->next = currcb;
            currcb->prev = prevcb;
        }

        prevcb = currcb;
    }

    prevcb->cb_link = nic.cbl.start->phy_addr;
    nic.cbl.start->prev = prevcb;
    prevcb->next = nic.cbl.start;

    nic.cbl.cb_avail = CB_MAX_NUM;
    nic.cbl.cb_wait = 0;

    nic.cbl.front = nic.cbl.start;
    nic.cbl.rear = nic.cbl.start->prev;
}
Example #8
0
//
// Map the physical page 'pp' at virtual address 'va'.
// The permissions (the low 12 bits) of the page table entry
// should be set to 'perm|PTE_P'.
//
// Requirements
//   - 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'.
//
// 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.
// Don't be tempted to write special-case code to handle this
// situation, though; there's an elegant way to address it.
//
// RETURNS:
//   0 on success
//   -E_NO_MEM, if page table couldn't be allocated
//
// Hint: The TA solution is implemented using pgdir_walk, page_remove,
// and page2pa.
//
int
page_insert(pde_t *pgdir, struct Page *pp, void *va, int perm)
{
	pte_t* pte = pgdir_walk(pgdir, va, 0);
	physaddr_t ppa = page2pa(pp);

	// If some page is already mapped there
	if (pte != NULL) { 
		if (*pte & PTE_P) page_remove(pgdir, va); // also invalidates tlb
		if (page_free_list == pp) page_free_list = page_free_list->pp_link; 
	}
	else {
		pte = pgdir_walk(pgdir, va, 1); // Allocate new page table
		if (pte == NULL) return -E_NO_MEM; // failed to alloc page table
	}

	*pte = ppa | perm | PTE_P;
	pp->pp_ref++;
	tlb_invalidate(pgdir, va);
	return 0;
}
Example #9
0
//
// Map the physical page 'pp' at virtual address 'va'.
// The permissions (the low 12 bits) of the page table entry
// should be set to 'perm|PTE_P'.
//
// Requirements
//   - 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'.
//
// 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.
// However, try not to distinguish this case in your code, as this
// frequently leads to subtle bugs; there's an elegant way to handle
// everything in one code path.
//
// RETURNS:
//   0 on success
//   -E_NO_MEM, if page table couldn't be allocated
//
// Hint: The TA solution is implemented using pgdir_walk, page_remove,
// and page2pa.
//
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
	// Fill this function in
	// SUNUS, 28, October, 2013
	struct PageInfo *page;
	pte_t *pte;
	pte = pgdir_walk(pgdir, va, 1);
	if (!pte) {
		// indicate that there is no free pages.
		return -E_NO_MEM;
	}
	pp->pp_ref++;
	if (*pte) {
		page_remove(pgdir, va);
	}
	*pte = page2pa(pp);
	*pte |= (PTE_P|perm);
	tlb_invalidate(pgdir, va);
	return 0;
}
Example #10
0
/**
 * page_insert - build the map of phy addr of an Page with the linear addr @la
 * @param pgdir page directory
 * @param page the page descriptor of the page to be inserted
 * @param la logical address of the page
 * @param perm permission of the page
 * @return 0 on success and error code when failed
 */
int
page_insert(pgd_t *pgdir, struct Page *page, uintptr_t la, pte_perm_t perm) {
    pte_t *ptep = get_pte(pgdir, la, 1);
    if (ptep == NULL) {
        return -E_NO_MEM;
    }
    page_ref_inc(page);
    if (*ptep != 0) {
        if (ptep_present(ptep) && pte2page(*ptep) == page) {
            page_ref_dec(page);
            goto out;
        }
        page_remove_pte(pgdir, la, ptep);
    }

out:
	ptep_map(ptep, page2pa(page));
	ptep_set_perm(ptep, perm);
  mp_tlb_update(pgdir, la);
  return 0;
}
Example #11
0
File: pmap.c Project: yuki252111/os
//
// Return a page to the free list.
// (This function should only be called when pp->pp_ref reaches 0.)
//
void
page_free(struct Page *pp)
{
	// Fill this function in
	if(pp->pp_ref==0)
	{
		if(page_free_list==NULL)
		{
			pp->pp_link=page_free_list;
			page_free_list=pp;
			return;
		}
		if(page2pa(pp)<page2pa(page_free_list))
		{
			pp->pp_link=page_free_list;
			page_free_list=pp;
			return;
		}
		struct Page* skip=page_free_list;
		int found=0;
		while(skip->pp_link!=NULL)
		{
			if(page2pa(pp)>page2pa(skip)&&
			  page2pa(pp)<page2pa(skip->pp_link))
			{
			    found=1;
			    break;
			}
			skip=skip->pp_link;
		}
		if(found==0)
		{
			skip->pp_link=pp;
			pp->pp_link=NULL;
			return;
		}
		if(found==1)
		{
			struct Page* temp=skip->pp_link;
			skip->pp_link=pp;
			pp->pp_link=temp;
		}
	}
	else
	{
		panic("still have reference:%d\n",pp->pp_ref);
	}
}
Example #12
0
// check page_insert, page_remove, &c, with an installed kern_pgdir
static void
check_page_installed_pgdir(void)
{
	struct Page *pp, *pp0, *pp1, *pp2;
	struct Page *fl;
	pte_t *ptep, *ptep1;
	uintptr_t va;
	int i;

	// check that we can read and write installed pages
	pp1 = pp2 = 0;
	assert((pp0 = page_alloc(0)));
	assert((pp1 = page_alloc(0)));
	assert((pp2 = page_alloc(0)));
	page_free(pp0);
	memset(page2kva(pp1), 1, PGSIZE);
	memset(page2kva(pp2), 2, PGSIZE);
	page_insert(kern_pgdir, pp1, (void*) PGSIZE, PTE_W);
	assert(pp1->pp_ref == 1);
	assert(*(uint32_t *)PGSIZE == 0x01010101U);
	page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W);
	assert(*(uint32_t *)PGSIZE == 0x02020202U);
	assert(pp2->pp_ref == 1);
	assert(pp1->pp_ref == 0);
	*(uint32_t *)PGSIZE = 0x03030303U;
	assert(*(uint32_t *)page2kva(pp2) == 0x03030303U);
	page_remove(kern_pgdir, (void*) PGSIZE);
	assert(pp2->pp_ref == 0);

	// forcibly take pp0 back
	assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));
	kern_pgdir[0] = 0;
	assert(pp0->pp_ref == 1);
	pp0->pp_ref = 0;

	// free the pages we took
	page_free(pp0);

	cprintf("check_page_installed_pgdir() succeeded!\n");
}
Example #13
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// bluesea
// pgdir_walk具体返回的是: 
// 虚拟地址va, 所在的页面对应的page table 表项的地址,所以是二级页表page table
// 的表项的地址,而非page dir的表项
// (理由分析见check_page()中的相关分析)
// 并且是该地址的虚拟地址!
//
//
// 下面这个需求可能和这个想法有矛盾:PTE_P置为0,即缺页的时候本应该由缺页中断处理。
// 那是另外故事,在这儿,pgdir_walk基本上只用于初始化内核虚拟内存的映射,
// 所以缺页新alloc page table没什么问题。
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//	(注:这种情况下也是返回页表项的地址,而页目录的地址。页表项的各个FLAG不用管
//	只需要把页目录对应的位置PTE_P置位即可。)
//
// Hint 1: you can turn a PageInfo * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// Fill this function in
	// bluesea
	uint32_t pdx = PDX(va), ptx = PTX(va);
	pde_t *pt = 0;
	if (pgdir[pdx] & PTE_P){
		pt = KADDR(PTE_ADDR(pgdir[pdx]));
		return &pt[ptx];
	}
	if (!create)
		return NULL;
	struct PageInfo *page = page_alloc(ALLOC_ZERO);
	if (!page)
		return NULL;
	page->pp_ref = 1;
	pgdir[pdx] = page2pa(page) | PTE_P | PTE_U;
	pt = page2kva(page);
	//pt[ptx] = PTE_U;
	return &pt[ptx];
}
Example #14
0
//
// Map the physical page 'pp' at virtual address 'va'.
// The permissions (the low 12 bits) of the page table entry
// should be set to 'perm|PTE_P'.
//
// Requirements
//   - 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'.
//
// 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.
// However, try not to distinguish this case in your code, as this
// frequently leads to subtle bugs; there's an elegant way to handle
// everything in one code path.
//
// RETURNS:
//   0 on success
//   -E_NO_MEM, if page table couldn't be allocated
//
// Hint: The TA solution is implemented using pgdir_walk, page_remove,
// and page2pa.
//
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
    // Find the page_table_entry and create if needed
    pte_t * page_table_entry = pgdir_walk(pgdir, va, 1);

    if (page_table_entry == NULL) {
        return -E_NO_MEM;
    }

    pp->pp_ref++;

    // If it already exists, then remove it
    if (*page_table_entry & PTE_P) {
        // This will remove the page and tlb invalidate it
        page_remove(pgdir, va);
    }

    *page_table_entry = page2pa(pp) | perm | PTE_P;

	return 0;
}
Example #15
0
void ap_init(void)
{
	gdt_init(per_cpu_ptr(cpus, bcpuid));
	tls_init(per_cpu_ptr(cpus, bcpuid));
	kprintf("CPU%d alive\n", myid());
	/* load new pagetable(shared with bsp) */
	pmm_init_ap();
	idt_init();		// init interrupt descriptor table

	/* test pmm */
	struct Page *p = alloc_pages(2);
	kprintf("I'm %d, get 0x%016llx(PA)\n", myid(), page2pa(p));
	free_pages(p, 2);

	lapic_init();
	proc_init_ap();

	atomic_inc(&bsync); /* let BSP know we are up */

	intr_enable();		// enable irq interrupt
	cpu_idle();
}
Example #16
0
int
page_alloc(struct Page **pp)
{
	// Fill this function in
	struct Page *ppage_temp;

	ppage_temp = LIST_FIRST(&page_free_list);

	//printf("%x\n",ppage_temp);
	//printf("pages__%x\n",ppage_temp);
	if (ppage_temp != NULL) {
		*pp = ppage_temp;
		LIST_REMOVE(ppage_temp, pp_link);
		page_initpp(*pp);

		bzero((void *)KADDR(page2pa(ppage_temp)), BY2PG);

		return 0;
	}

	return -E_NO_MEM;
}
Example #17
0
pmd_t *
get_pmd(pgd_t *pgdir, uintptr_t la, bool create) {
#if PMXSHIFT == PUXSHIFT
	return get_pud(pgdir, la, create);
#else /* PMXSHIFT == PUXSHIFT */
    pud_t *pudp;
    if ((pudp = get_pud(pgdir, la, create)) == NULL) {
        return NULL;
    }
    if (!(*pudp & PTE_P)) {
        struct Page *page;
        if (!create || (page = alloc_page()) == NULL) {
            return NULL;
        }
        set_page_ref(page, 1);
        uintptr_t pa = page2pa(page);
        memset(VADDR_DIRECT(pa), 0, PGSIZE);
        *pudp = pa | PTE_U | PTE_W | PTE_P;
    }
    return &((pmd_t *)VADDR_DIRECT(PUD_ADDR(*pudp)))[PMX(la)];
#endif /* PMXSHIFT == PUXSHIFT */
}
Example #18
0
int
pgdir_walk(Pde *pgdir, u_long va, int create, Pte **ppte)
{
	// Fill this function in
	Pde *pgdir_entryp;
	Pte *pgtable;
	struct Page *ppage;

	pgdir_entryp = (Pde *)(&pgdir[PDX(va)]);
	pgtable = (Pte *)KADDR(PTE_ADDR(*pgdir_entryp));

	//	pgtable = PTE_ADDR(*pgdir_entryp);
	//printf("	in pgdir_walk pgtable_entryp=%x\n",pgtable);
	if ((*pgdir_entryp & PTE_V) == 0) {
		//printf("pgdir_walk:come 1\n");
		if (create == 0) {
			*ppte = 0;
			return 0;
		} else {	//alloc a page for page table.
			if (page_alloc(&ppage) != 0) {	//cannot alloc a page for page table
				*ppte = 0;
				return -E_NO_MEM;
			}

			pgtable = (Pte *)KADDR(page2pa(ppage));
			*pgdir_entryp = PADDR(pgtable) | PTE_V | PTE_R;
			ppage->pp_ref++;
		}
	}

	//printf("pgdir_walk:come 2\n");
	if (ppte) {
		*ppte = (Pte *)(&pgtable[PTX(va)]);
	}

	//printf("out of pgdir_walk\n");
	return 0;
}
Example #19
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// directory more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// need to handle permission!!!
	uintptr_t pd_index=0, pt_index=0;
	physaddr_t pa_ptba, pa_pte, pde_perm, pte_perm;
	pte_t *va_ptba=NULL, *va_pte=NULL;
	struct PageInfo *req_page;

	pd_index = PDX(va);
	//check address va_ptba+pt_index if it is correct pointer arithmatic or not.	
	// permissions given for directory table entry are PTE_P and PTE_W
	//*(pgdir+pd_index) = *(pgdir+pd_index) | PTE_P | PTE_W ;
	pa_ptba = *(pgdir+pd_index);
	if(!(pa_ptba & PTE_P))
	{
		// setting up page table for requested virtual address.
		if(create)
		{
			req_page = page_alloc(ALLOC_ZERO);
			if(req_page==NULL)
				return NULL;
			req_page->pp_ref++;
			pa_ptba = page2pa(req_page) | PTE_P | PTE_U | PTE_W;
			*(pgdir+pd_index) = pa_ptba;
		}
		else
			return NULL;
	}

	pde_perm = PGOFF(pa_ptba);
	pa_ptba = PTE_ADDR(pa_ptba);
	va_ptba = KADDR(pa_ptba);

	pt_index = PTX(va);
	va_pte = va_ptba + pt_index;
	return va_pte;
}
Example #20
0
File: pmap.c Project: kelwin/6.828
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// Fill this function in
	pde_t *pde;
	pte_t *pgtab;
	struct Page *pp;

	pde = &pgdir[PDX(va)];
	if (*pde & PTE_P) {
		pgtab = (pte_t *)KADDR(PTE_ADDR(*pde));
	}
	else {
		if (!create)
			return 0;
		if ((pp = page_alloc(ALLOC_ZERO)) == 0)
			return 0;
		pp->pp_ref = 1;
		pgtab = (pte_t *)KADDR(page2pa(pp));
		*pde = PADDR(pgtab) | PTE_P | PTE_W | PTE_U;
	}
	return &pgtab[PTX(va)];
}
Example #21
0
//
// Check that the pages on the page_free_list are reasonable.
//
static void
check_page_free_list(bool only_low_memory)
{
	struct Page *pp;
	unsigned pdx_limit = only_low_memory ? 4 : NPDENTRIES;
	int nfree_basemem = 0, nfree_extmem = 0;
	char *first_free_page;

	if (!page_free_list)
		panic("'page_free_list' is a null pointer!");

	// if there's a page that shouldn't be on the free list,
	// try to make sure it eventually causes trouble.
	for (pp = page_free_list; pp; pp = pp->pp_link)
		if (PDX(page2pa(pp)) < pdx_limit)
			memset(page2kva(pp), 0x97, 128);

	first_free_page = (char *) boot_alloc(0);
	for (pp = page_free_list; pp; pp = pp->pp_link) {
		// check that we didn't corrupt the free list itself
		assert(pp >= pages);
		assert(pp < pages + npages);
		assert(((char *) pp - (char *) pages) % sizeof(*pp) == 0);

		// check a few pages that shouldn't be on the free list
		assert(page2pa(pp) != 0);
		assert(page2pa(pp) != IOPHYSMEM);
		assert(page2pa(pp) != EXTPHYSMEM - PGSIZE);
		assert(page2pa(pp) != EXTPHYSMEM);
		assert(page2pa(pp) < EXTPHYSMEM || page2kva(pp) >= first_free_page);

		if (page2pa(pp) < EXTPHYSMEM)
			++nfree_basemem;
		else
			++nfree_extmem;
	}

	assert(nfree_basemem > 0);
	assert(nfree_extmem > 0);
}
Example #22
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// directory more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
	pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// Fill this function in
	pde_t* pgdir_entry = &pgdir[PDX(va)];
	pte_t* pgtb_entry = NULL;
	struct PageInfo * pg = NULL;
	
	if (!(*pgdir_entry & PTE_P)){
		if(create){
			pg = page_alloc(1);
			if (!pg) 
				return NULL;
			memset(page2kva(pg), 0, PGSIZE);
			pg->pp_ref += 1;
			*pgdir_entry = page2pa(pg)|PTE_P|PTE_U|PTE_W; 
		}else{
			return NULL;
		}
	}
	pgtb_entry = KADDR(PTE_ADDR(*pgdir_entry)); 
	return &pgtb_entry[PTX(va)];
}
Example #23
0
//
// Map the physical page 'pp' at virtual address 'va'.
// The permissions (the low 12 bits) of the page table entry
// should be set to 'perm|PTE_P'.
//
// Requirements
//   - 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'.
//
// 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.
// However, try not to distinguish this case in your code, as this
// frequently leads to subtle bugs; there's an elegant way to handle
// everything in one code path.
//
// RETURNS:
//   0 on success
//   -E_NO_MEM, if page table couldn't be allocated
//
// Hint: The TA solution is implemented using pgdir_walk, page_remove,
// and page2pa.
//
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
    // Look for the page table entry.
    int create = 1;
    pte_t *table_entry = pgdir_walk(pgdir, va, create);
    
    // No page table exists and we don't have enough memory to create one.
    if (table_entry == NULL) {
        return -E_NO_MEM;
    }
    // Checks against accidentally removing the same page as we're inserting.
    pp->pp_ref++;
    if (*table_entry & PTE_P) {
        // Remove page from table before creating a new mapping.
        page_remove(pgdir, va);
    }
    // Map table entry, and add extra permissions to page directory.
    *table_entry = page2pa(pp) | PTE_P | perm; 
    pgdir[PDX(va)] |= perm;

    return 0;
}
Example #24
0
int
mon_showmapping(int argc, char **argv, struct Trapframe *tf)
{
	uint32_t va_begin = 0, va_end = 0;
	char *endptrb, *endptre;
	CHECKPARA(argc != 2 && argc != 3);
	if (argc == 2) 
	{	
		va_begin = ROUNDDOWN((uint32_t)strtol(argv[1], &endptrb, 0),PGSIZE);
		va_end = va_begin;
		CHECKPARA( *endptrb != '\0');
	}
	else if (argc == 3) 
	{
		va_begin = ROUNDDOWN((uint32_t)strtol(argv[1], &endptrb, 0),PGSIZE);
		va_end = ROUNDUP((uint32_t)strtol(argv[2], &endptre, 0),PGSIZE);
		CHECKPARA(*endptrb != '\0' || *endptre != '\0');
	}
	cprintf("Virtual\tPhysical\tFlags\t\tRefer\n");
	while(va_begin <= va_end)
	{
		struct PageInfo *pp;
		pte_t *pteptr;
		char buf[13];
		pp = page_lookup(kern_pgdir, (void *)va_begin, &pteptr);
		if (pp == NULL || *pteptr ==0)
			cprintf("0x%08x\t%s\t\t%s\t\t%d\n", va_begin, "None", "None", 0);
		else
			cprintf("0x%08x\t0x%08x\t%s\t%d\n", va_begin, page2pa(pp),"Flag2Str"/*flag2str(*pteptr, buf)*/, pp->pp_ref );
		va_begin += PGSIZE;
	}
	
	return 0;
	
	
	
}
Example #25
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
    uintptr_t page_directory_index = PDX(va);
    uintptr_t page_table_index = PTX(va);

    pde_t page_directory_entry = pgdir[page_directory_index];
    pte_t* page_table_entry;

    if (page_directory_entry & PTE_P) {
        // Page table exists
        page_table_entry = (pte_t*) KADDR(PTE_ADDR(page_directory_entry));
        return &page_table_entry[page_table_index];
    }

    // If it does not exist and create is false, return NULL
    if (create == 0) {
        return NULL;
    }

    struct PageInfo *page = page_alloc(ALLOC_ZERO);

    // Make sure that the allocation succeeded first
    if (page == NULL) {
        return NULL;
    }

    physaddr_t addr = page2pa(page);
    page_table_entry = (pte_t *) page2kva(page);

    // Set the page table's permissions
    pgdir[page_directory_index] = addr | PTE_P | PTE_W | PTE_U;
    page->pp_ref++;

	return &page_table_entry[page_table_index];
}
Example #26
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//    the page is cleared,
//    and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
    struct PageInfo *new_page_table;
    pte_t *result;
    physaddr_t table_addr = 0x0;

    // Reference the page directory array.
    pde_t dir_entry = pgdir[PDX(va)];

    // If page table is not found in the directory and create is set, try page_alloc().
    if (dir_entry & PTE_P) { 
        // Table is already present.
        table_addr = PTE_ADDR(dir_entry);
    } else {
        if (!create) {
            // For lookups only.
            return NULL;
        }
        // Allocate a new page table.
        new_page_table = page_alloc(ALLOC_ZERO);
        if (!new_page_table) {
            // Allocation failed, exit.
            return NULL;
        }
        // Increment reference count and set page directory to point to page table's physical address.
        new_page_table->pp_ref++;
        table_addr = page2pa(new_page_table);
        pgdir[PDX(va)] = table_addr | PTE_P | PTE_W;
    }

    // Since our table address is a physical address, we need to index into it using PTX times 
    // physaddr_t. This ensures that addresses are aligned on 2-byte boundaries.
    result = (pte_t *) KADDR(table_addr + sizeof(physaddr_t) * PTX(va));
    return result;
}
Example #27
0
// Given 'pgdir', a pointer to a page directory, pgdir_walk returns
// a pointer to the page table entry (PTE) for linear address 'va'.
// This requires walking the two-level page table structure.
//
// The relevant page table page might not exist yet.
// If this is true, and create == false, then pgdir_walk returns NULL.
// Otherwise, pgdir_walk allocates a new page table page with page_alloc.
//    - If the allocation fails, pgdir_walk returns NULL.
//    - Otherwise, the new page's reference count is incremented,
//	the page is cleared,
//	and pgdir_walk returns a pointer into the new page table page.
//
// Hint 1: you can turn a Page * into the physical address of the
// page it refers to with page2pa() from kern/pmap.h.
//
// Hint 2: the x86 MMU checks permission bits in both the page directory
// and the page table, so it's safe to leave permissions in the page
// more permissive than strictly necessary.
//
// Hint 3: look at inc/mmu.h for useful macros that mainipulate page
// table and page directory entries.
//
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	// Fill this function in
	// SUNUS, 23, October, 2013
	pde_t *pde;
	pte_t *pte;
	pte_t *entry;
	struct PageInfo *p;
	pde = &pgdir[PDX(va)];
	if ((!*pde) && create) {
		p = page_alloc(ALLOC_ZERO);
		if (!p)
			return NULL;
		p->pp_ref++;
		*pde = page2pa(p);
		*pde |= (PTE_P|PTE_U|PTE_W);
	}
	else if (!*pde)
		return NULL;
	entry = (pde_t *)PTE_ADDR(*pde);
	pte = &entry[PTX(va)];
	return (pte_t *)KADDR((pte_t)pte);
}
Example #28
0
// check page_insert, page_remove, &c
static void
check_page(void)
{
	struct Page *pp, *pp0, *pp1, *pp2;
	struct Page *fl;
	pte_t *ptep, *ptep1;
	void *va;
	uintptr_t mm1, mm2;
	int i;
	extern pde_t entry_pgdir[];

	// should be able to allocate three pages
	pp0 = pp1 = pp2 = 0;
	assert((pp0 = page_alloc(0)));
	assert((pp1 = page_alloc(0)));
	assert((pp2 = page_alloc(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;
	page_free_list = 0;

    
	// should be no free memory
	assert(!page_alloc(0));

	// there is no page allocated at address 0
	assert(page_lookup(kern_pgdir, (void *) 0x0, &ptep) == NULL);

	// there is no free memory, so we can't allocate a page table
	assert(page_insert(kern_pgdir, pp1, 0x0, PTE_W) < 0);

	// free pp0 and try again: pp0 should be used for page table
	page_free(pp0);

	assert(page_insert(kern_pgdir, pp1, 0x0, PTE_W) == 0);

	assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));

	assert(check_va2pa(kern_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(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
    assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp2));
    assert(pp2->pp_ref == 1);

	// should be no free memory
	assert(!page_alloc(0));

	// should be able to map pp2 at PGSIZE because it's already there
	assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
	assert(check_va2pa(kern_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(0));

	// check that pgdir_walk returns a pointer to the pte
	ptep = (pte_t *) KADDR(PTE_ADDR(kern_pgdir[PDX(PGSIZE)]));
	assert(pgdir_walk(kern_pgdir, (void*)PGSIZE, 0) == ptep+PTX(PGSIZE));

	// should be able to change permissions too.
	assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W|PTE_U) == 0);
	assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp2));
	assert(pp2->pp_ref == 1);
	assert(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U);
	assert(kern_pgdir[0] & PTE_U);

	// should be able to remap with fewer permissions
	assert(page_insert(kern_pgdir, pp2, (void*) PGSIZE, PTE_W) == 0);
	assert(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_W);
	assert(!(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U));

	// should not be able to map at PTSIZE because need free page for page table
	assert(page_insert(kern_pgdir, pp0, (void*) PTSIZE, PTE_W) < 0);

	// insert pp1 at PGSIZE (replacing pp2)
	assert(page_insert(kern_pgdir, pp1, (void*) PGSIZE, PTE_W) == 0);
	assert(!(*pgdir_walk(kern_pgdir, (void*) PGSIZE, 0) & PTE_U));

	// should have pp1 at both 0 and PGSIZE, pp2 nowhere, ...
	assert(check_va2pa(kern_pgdir, 0) == page2pa(pp1));
	assert(check_va2pa(kern_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((pp = page_alloc(0)) && pp == pp2);

	// unmapping pp1 at 0 should keep pp1 at PGSIZE
	page_remove(kern_pgdir, 0x0);
	assert(check_va2pa(kern_pgdir, 0x0) == ~0);
	assert(check_va2pa(kern_pgdir, PGSIZE) == page2pa(pp1));
	assert(pp1->pp_ref == 1);
	assert(pp2->pp_ref == 0);

	// unmapping pp1 at PGSIZE should free it
	page_remove(kern_pgdir, (void*) PGSIZE);
	assert(check_va2pa(kern_pgdir, 0x0) == ~0);
	assert(check_va2pa(kern_pgdir, PGSIZE) == ~0);
	assert(pp1->pp_ref == 0);
	assert(pp2->pp_ref == 0);

	// so it should be returned by page_alloc
	assert((pp = page_alloc(0)) && pp == pp1);

	// should be no free memory
	assert(!page_alloc(0));

	// forcibly take pp0 back
	assert(PTE_ADDR(kern_pgdir[0]) == page2pa(pp0));
	kern_pgdir[0] = 0;
	assert(pp0->pp_ref == 1);
	pp0->pp_ref = 0;

	// check pointer arithmetic in pgdir_walk
	page_free(pp0);
	va = (void*)(PGSIZE * NPDENTRIES + PGSIZE);
	ptep = pgdir_walk(kern_pgdir, va, 1);
	ptep1 = (pte_t *) KADDR(PTE_ADDR(kern_pgdir[PDX(va)]));
	assert(ptep == ptep1 + PTX(va));
	kern_pgdir[PDX(va)] = 0;
	pp0->pp_ref = 0;

	// check that new page tables get cleared
	memset(page2kva(pp0), 0xFF, PGSIZE);
	page_free(pp0);
	pgdir_walk(kern_pgdir, 0x0, 1);
	ptep = (pte_t *) page2kva(pp0);
	for(i=0; i<NPTENTRIES; i++)
		assert((ptep[i] & PTE_P) == 0);
	kern_pgdir[0] = 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);

	// test mmio_map_region
	mm1 = (uintptr_t) mmio_map_region(0, 4097);
	mm2 = (uintptr_t) mmio_map_region(0, 4096);
	// check that they're in the right region
	assert(mm1 >= MMIOBASE && mm1 + 8096 < MMIOLIM);
	assert(mm2 >= MMIOBASE && mm2 + 8096 < MMIOLIM);
	// check that they're page-aligned
	assert(mm1 % PGSIZE == 0 && mm2 % PGSIZE == 0);
	// check that they don't overlap
	assert(mm1 + 8096 <= mm2);
	// check page mappings
	assert(check_va2pa(kern_pgdir, mm1) == 0);
	assert(check_va2pa(kern_pgdir, mm1+PGSIZE) == PGSIZE);
	assert(check_va2pa(kern_pgdir, mm2) == 0);
	assert(check_va2pa(kern_pgdir, mm2+PGSIZE) == ~0);
	// check permissions
	assert(*pgdir_walk(kern_pgdir, (void*) mm1, 0) & (PTE_W|PTE_PWT|PTE_PCD));
	assert(!(*pgdir_walk(kern_pgdir, (void*) mm1, 0) & PTE_U));
	// clear the mappings
	*pgdir_walk(kern_pgdir, (void*) mm1, 0) = 0;
	*pgdir_walk(kern_pgdir, (void*) mm1 + PGSIZE, 0) = 0;
	*pgdir_walk(kern_pgdir, (void*) mm2, 0) = 0;

	cprintf("check_page() succeeded!\n");
}
Example #29
0
//
// Check the physical page allocator (page_alloc(), page_free(),
// and page_init()).
//
static void
check_page_alloc(void)
{
	struct Page *pp, *pp0, *pp1, *pp2;
	int nfree;
	struct Page *fl;
	char *c;
	int i;

	if (!pages)
		panic("'pages' is a null pointer!");

	// check number of free pages
	for (pp = page_free_list, nfree = 0; pp; pp = pp->pp_link)
		++nfree;

	// should be able to allocate three pages
	pp0 = pp1 = pp2 = 0;
	assert((pp0 = page_alloc(0)));
	assert((pp1 = page_alloc(0)));
	assert((pp2 = page_alloc(0)));

	assert(pp0);
	assert(pp1 && pp1 != pp0);
	assert(pp2 && pp2 != pp1 && pp2 != pp0);
	assert(page2pa(pp0) < npages*PGSIZE);
	assert(page2pa(pp1) < npages*PGSIZE);
	assert(page2pa(pp2) < npages*PGSIZE);

	// temporarily steal the rest of the free pages
	fl = page_free_list;
	page_free_list = 0;

	// should be no free memory
	assert(!page_alloc(0));

	// free and re-allocate?
	page_free(pp0);
	page_free(pp1);
	page_free(pp2);
	pp0 = pp1 = pp2 = 0;
	assert((pp0 = page_alloc(0)));
  	assert((pp1 = page_alloc(0)));
	assert((pp2 = page_alloc(0)));
	assert(pp0);
	assert(pp1 && pp1 != pp0);
	assert(pp2 && pp2 != pp1 && pp2 != pp0);
	assert(!page_alloc(0));

	// test flags
	memset(page2kva(pp0), 1, PGSIZE);
	page_free(pp0);
	assert((pp = page_alloc(ALLOC_ZERO)));
	assert(pp && pp0 == pp);
	c = page2kva(pp);
	for (i = 0; i < PGSIZE; i++)
		assert(c[i] == 0);

	// give free list back
	page_free_list = fl;

	// free the pages we took
	page_free(pp0);
	page_free(pp1);
	page_free(pp2);

	// number of free pages should be the same
	for (pp = page_free_list; pp; pp = pp->pp_link)
		--nfree;
	assert(nfree == 0);

	cprintf("check_page_alloc() succeeded!\n");
}
Example #30
0
//
// Check that the pages on the page_free_list are reasonable.
//
static void
check_page_free_list(bool only_low_memory)
{
	struct Page *pp;
	unsigned pdx_limit = only_low_memory ? 1 : NPDENTRIES;
	int nfree_basemem = 0, nfree_extmem = 0;
	char *first_free_page;

	if (!page_free_list)
		panic("'page_free_list' is a null pointer!");

	if (only_low_memory) {
		// Move pages with lower addresses first in the free
		// list, since entry_pgdir does not map all pages.
		struct Page *pp1, *pp2;
		struct Page **tp[2] = { &pp1, &pp2 };
		for (pp = page_free_list; pp; pp = pp->pp_link) {
			int pagetype = PDX(page2pa(pp)) >= pdx_limit;
			*tp[pagetype] = pp;
			tp[pagetype] = &pp->pp_link;
		}
		*tp[1] = 0;
		*tp[0] = pp2;
		page_free_list = pp1;
	}

	// if there's a page that shouldn't be on the free list,
	// try to make sure it eventually causes trouble.
    for(pp = page_free_list; pp; pp=pp->pp_link) { 
		if (PDX(page2pa(pp)) < pdx_limit)
			memset(page2kva(pp), 0x97, 128);
    }

	first_free_page = (char *) boot_alloc(0);
	for (pp = page_free_list; pp; pp = pp->pp_link) {
		// check that we didn't corrupt the free list itself
		assert(pp >= pages);
		assert(pp < pages + npages);
		assert(((char *) pp - (char *) pages) % sizeof(*pp) == 0);

		// check a few pages that shouldn't be on the free list
		assert(page2pa(pp) != 0);
		assert(page2pa(pp) != IOPHYSMEM);
		assert(page2pa(pp) != EXTPHYSMEM - PGSIZE);
		assert(page2pa(pp) != EXTPHYSMEM);
		assert(page2pa(pp) < EXTPHYSMEM || (char *) page2kva(pp) >= first_free_page);
		// (new test for lab 4)
		assert(page2pa(pp) != MPENTRY_PADDR);
		assert(page2pa(pp) < EXTPHYSMEM ||
                (char *) page2kva(pp) >= first_free_page);

		if (page2pa(pp) < EXTPHYSMEM)
			++nfree_basemem;
		else
			++nfree_extmem;
	}

	assert(nfree_basemem > 0);
	assert(nfree_extmem > 0);
    cprintf("check_page_free() succeeded!\n");
}