⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmap.c~

📁 jos lab3代码
💻 C~
📖 第 1 页 / 共 2 页
字号:
	//     Some of it is in use, some is free. Where is the kernel?	//     Which pages are used for page tables and other data structures?	//	// Change the code to reflect this.	int i,con;	LIST_INIT(&page_free_list);	for (i = 0; i < npage; i++)	 {			con=1;		if(i!=0&&i<basemem/PGSIZE)			con=0;		if(i>=((int)boot_freemem-KERNBASE)/PGSIZE)			con=0;		pages[i].pp_ref = con;		if(!con)		LIST_INSERT_HEAD(&page_free_list, &pages[i], pp_link);	}}//// Initialize a Page structure.// The result has null links and 0 refcount.// Note that the corresponding physical page is NOT initialized!//static voidpage_initpp(struct Page *pp){	memset(pp, 0, sizeof(*pp));}//// Allocates a physical page.// Does NOT set the contents of the physical page to zero -// the caller must do that if necessary.//// *pp_store -- is set to point to the Page struct of the newly allocated// page//// RETURNS //   0 -- on success//   -E_NO_MEM -- otherwise //// Hint: use LIST_FIRST, LIST_REMOVE, and page_initpp// Hint: pp_ref should not be incremented intpage_alloc(struct Page **pp_store){	// Fill this function in	struct Page *p = LIST_FIRST(&page_free_list);    	if(p == NULL)        	return -E_NO_MEM;    	LIST_REMOVE(p, pp_link);    	page_initpp(p);    	*pp_store = p;    	return 0;}//// Return a page to the free list.// (This function should only be called when pp->pp_ref reaches 0.)//voidpage_free(struct Page *pp){	// Fill this function in	 LIST_INSERT_HEAD(&page_free_list, pp, pp_link);}//// Decrement the reference count on a page,// freeing it if there are no more refs.//voidpage_decref(struct Page* pp){	if (--pp->pp_ref == 0)		page_free(pp);}// 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.//// If the relevant page table doesn't exist in the page directory, then://    - If create == 0, pgdir_walk returns NULL.//    - Otherwise, pgdir_walk tries to allocate a new page table//	with page_alloc.  If this fails, pgdir_walk returns NULL.//    - pgdir_walk sets pp_ref to 1 for the new page table.//    - Finally, pgdir_walk returns a pointer into the new page table.//// Hint: you can turn a Page * into the physical address of the// page it refers to with page2pa() from kern/pmap.h.pte_t *pgdir_walk(pde_t *pgdir, const void *va, int create){	// Fill this function in    pte_t *p;    struct Page *pp;    physaddr_t pa;    pgdir = &pgdir[PDX(va)];    if(!(*pgdir & PTE_P)){        if(!create){ return NULL;}        if(page_alloc(&pp) != 0) return NULL;        pp->pp_ref++;        pa = page2pa(pp);        memset(KADDR(PTE_ADDR(pa)), 0 ,PGSIZE);        *pgdir = pa | PTE_U | PTE_P | PTE_W;    }    p = (pte_t*) KADDR(PTE_ADDR((*pgdir)));    return  &p[PTX(va)];}//// 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'.//// Details//   - If there is already a page mapped at 'va', it is page_remove()d.//   - If necessary, on demand, allocates a page table and inserts it 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'.//// 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.//intpage_insert(pde_t *pgdir, struct Page *pp, void *va, int perm) {// Fill this function in	pte_t * p;	if((p=pgdir_walk(pgdir,va,1))==0)		return -E_NO_MEM;	if(*p&PTE_P)	{		if(pa2page(PTE_ADDR(*p))!=pp)		{			page_remove(pgdir,va);			pp->pp_ref++;		}		*p=page2pa(pp)|perm|PTE_P;	}	else	{		*p=page2pa(pp)|perm|PTE_P;		pp->pp_ref++;	}    return 0;}//// Map [la, la+size) of linear address space to physical [pa, pa+size)// in the page table rooted at pgdir.  Size is a multiple of PGSIZE.// Use permission bits perm|PTE_P for the entries.//// This function is only intended to set up the ``static'' mappings// above UTOP. As such, it should *not* change the pp_ref field on the// mapped pages.//// Hint: the TA solution uses pgdir_walkstatic voidboot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm){	int i=0;	for(i=0;i<size;i+=PGSIZE)	{		*(pgdir_walk(pgdir,(void *)(la+i),1))=PTE_ADDR(pa+i)|perm|PTE_P;	}	// Fill this function in}//// 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// but should not be used by other callers.//// Return 0 if there is no page mapped at va.//// Hint: the TA solution uses pgdir_walk and pa2page.//struct Page *page_lookup(pde_t *pgdir, void *va, pte_t **pte_store){	// Fill this function in	*pte_store=pgdir_walk(pgdir,va,0);	if(*pte_store != 0&&(**pte_store&PTE_P) )		return pa2page(PTE_ADDR(**pte_store));	return NULL;}//// 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.//voidpage_remove(pde_t *pgdir, void *va){	// Fill this function in	pte_t* pp;	struct Page *p=page_lookup(pgdir,va,&pp);	if( p!=NULL){		page_decref(p);		*pp=0;		tlb_invalidate(pgdir,va);	} }//// Invalidate a TLB entry, but only if the page tables being// edited are the ones currently in use by the processor.//voidtlb_invalidate(pde_t *pgdir, void *va){	// Flush the entry only if we're modifying the current address space.	// For now, there is only one address space, so always invalidate.	invlpg(va);}static uintptr_t user_mem_check_addr;//// Check that an environment is allowed to access the range of memory// [va, va+len) with permissions 'perm | PTE_P'.// Normally 'perm' will contain PTE_U at least, but this is not required.// 'va' and 'len' need not be page-aligned; you must test every page that// contains any of that range.  You will test either 'len/PGSIZE',// 'len/PGSIZE + 1', or 'len/PGSIZE + 2' pages.//// A user program can access a virtual address if (1) the address is below// ULIM, and (2) the page table gives it permission.  These are exactly// the tests you should implement here.//// If there is an error, set the 'user_mem_check_addr' variable to the first// erroneous virtual address.//// Returns 0 if the user program can access this range of addresses,// and -E_FAULT otherwise.//intuser_mem_check(struct Env *env, const void *va, size_t len, int perm){	// LAB 3: Your code here.  // LAB 3: Your code here. uintptr_t va_start = (uintptr_t) va; uintptr_t va_end = va_start + len; uintptr_t vp = PPN(va_start) << PGSHIFT; uintptr_t vp_end = PPN(va_end) << PGSHIFT; perm |= PTE_P; for (; vp <= vp_end; vp += PGSIZE) {  pte_t *ppte = pgdir_walk(env->env_pgdir, (void *) vp, 0);  if ((ppte != NULL) && ((*ppte & perm) == perm))   continue;  user_mem_check_addr = (vp < va_start) ? va_start : vp;  return -E_FAULT; } return 0;}//// Checks that environment 'env' is allowed to access the range// of memory [va, va+len) with permissions 'perm | PTE_U'.// If it can, then the function simply returns.// If it cannot, 'env' is destroyed.//voiduser_mem_assert(struct Env *env, const void *va, size_t len, int perm){	if (user_mem_check(env, va, len, perm | PTE_U) < 0) {		cprintf("[%08x] user_mem_check assertion failure for "			"va %08x\n", curenv->env_id, user_mem_check_addr);		env_destroy(env);	// may not return	}}// check page_insert, page_remove, &cstatic voidpage_check(void){	struct Page *pp, *pp0, *pp1, *pp2;	struct Page_list fl;	pte_t *ptep, *ptep1;	void *va;	int i;	// 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);	// 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);	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);	// 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);	// 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));	// should be able to change permissions too.	assert(page_insert(boot_pgdir, pp2, (void*) PGSIZE, PTE_U) == 0);	assert(check_va2pa(boot_pgdir, PGSIZE) == page2pa(pp2));	assert(pp2->pp_ref == 1);	assert(*pgdir_walk(boot_pgdir, (void*) PGSIZE, 0) & PTE_U);	// 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);	#if 0	// should be able to page_insert to change a page	// and see the new data immediately.	memset(page2kva(pp1), 1, PGSIZE);	memset(page2kva(pp2), 2, PGSIZE);	page_insert(boot_pgdir, pp1, 0x0, 0);	assert(pp1->pp_ref == 1);	assert(*(int*)0 == 0x01010101);	page_insert(boot_pgdir, pp2, 0x0, 0);	assert(*(int*)0 == 0x02020202);	assert(pp2->pp_ref == 1);	assert(pp1->pp_ref == 0);	page_remove(boot_pgdir, 0x0);	assert(pp2->pp_ref == 0);#endif	// 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;		// check pointer arithmetic in pgdir_walk	page_free(pp0);	va = (void*)(PGSIZE * NPDENTRIES + PGSIZE);	ptep = pgdir_walk(boot_pgdir, va, 1);	ptep1 = KADDR(PTE_ADDR(boot_pgdir[PDX(va)]));	assert(ptep == ptep1 + PTX(va));	boot_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(boot_pgdir, 0x0, 1);	ptep = page2kva(pp0);	for(i=0; i<NPTENTRIES; i++)		assert((ptep[i] & PTE_P) == 0);	boot_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);		cprintf("page_check() succeeded!\n");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -