// // Frees env e and all memory it uses. // void env_free(struct Env *e) { pte_t *pt; uint32_t pdeno, pteno; physaddr_t pa; // If freeing the current environment, switch to boot_pgdir // before freeing the page directory, just in case the page // gets reused. if (e == curenv) lcr3(boot_cr3); // Note the environment's demise. cprintf("[%08x] free env %08x\n", curenv ? curenv->env_id : 0, e->env_id); // Flush all mapped pages in the user portion of the address space static_assert(UTOP % PTSIZE == 0); for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) { // only look at mapped page tables if (!(e->env_pgdir[pdeno] & PTE_P)) continue; // find the pa and va of the page table pa = PTE_ADDR(e->env_pgdir[pdeno]); pt = (pte_t*) KADDR(pa); // unmap all PTEs in this page table for (pteno = 0; pteno <= PTX(~0); pteno++) { if (pt[pteno] & PTE_P) page_remove(e->env_pgdir, PGADDR(pdeno, pteno, 0)); } // free the page table itself e->env_pgdir[pdeno] = 0; page_decref(pa2page(pa)); } // free the page directory pa = e->env_cr3; e->env_pgdir = 0; e->env_cr3 = 0; page_decref(pa2page(pa)); // return the environment to the free list e->env_status = ENV_FREE; LIST_INSERT_HEAD(&env_free_list, e, env_link); }
int page_insert(pgd_t* pgdir, page_t *pf,viraddr_t va, uint32_t perm) { assert(pgdir && pf); pte_t* pte = _page_walk(pgdir, va,true); if (!pte) return -ENOMEM; atomic_inc(&pf->_count); if (pte_present(*pte)) page_remove(pgdir, va); pte_val(*pte) = page2phys(pf) | perm | _PAGE_PRESENT; refresh_tlb(pgdir, va); return 0; }
// Allocate a page of memory and map it at 'va' with permission // 'perm' in the address space of 'envid'. // The page's contents are set to 0. // If a page is already mapped at 'va', that page is unmapped as a // side effect. // // perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set, // but no other bits may be set. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. // -E_INVAL if perm is inappropriate (see above). // -E_NO_MEM if there's no memory to allocate the new page, // or to allocate any necessary page tables. static int sys_page_alloc(envid_t envid, void *va, int perm) { // Hint: This function is a wrapper around page_alloc() and // page_insert() from kern/pmap.c. // Most of the new code you write should be to check the // parameters for correctness. // If page_insert() fails, remember to free the page you // allocated! // LAB 4: Your code here. struct Env *env; if(envid2env(envid, &env, 1) == -E_BAD_ENV) { //cprintf("bad environment envid in sys page alloc:%08x\n",envid); return -E_BAD_ENV; } else if((uintptr_t)va >= UTOP || (uint32_t)va % PGSIZE) return -E_INVAL; else if((perm & PTE_U) && (perm & PTE_P)) { if(perm & ((~(PTE_U|PTE_P|PTE_W|PTE_AVAIL) & 0xfff))) return -E_INVAL; } if((vpd[PDX(va)] & PTE_P) && (vpt[VPN(va)] & PTE_P)) page_remove(env->env_pgdir,va); //cprintf("env id:%08x\n",env->env_id); struct Page * page; if(page_alloc(&page) == -E_NO_MEM) return -E_NO_MEM; //cprintf("page alloc kva:%08x\n",page2kva(page)); // At this time, we use the page table of the kernel // so we clear the phsical page according to the kernel virtual address memset(page2kva(page),0x0,PGSIZE); //cprintf("page insert,env_id:%08x,env_pgdir:%08x,page:%08x,va:%08x\n", // env->env_id,env->env_pgdir,page,va); if(page_insert(env -> env_pgdir, page, va, perm) != 0) { page_free(page); return -E_NO_MEM; } //cprintf("page insert success\n"); return 0; //panic("sys_page_alloc not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *e = NULL; int res = envid2env(envid, &e, 1); if (res < 0) return res; if (((int)va >= UTOP) || ((int)va % PGSIZE != 0)) return -E_INVAL; page_remove(e->env_pgdir, va); return 0; // panic("sys_page_unmap not implemented"); }
/** * @brief Map the physical page 'pp' into the virtual address 'va' in page * directory 'pgdir' * * 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'. * - page_incref() should be called if the insertion succeeds. * - The TLB must be invalidated if a page was formerly present at 'va'. * (this is handled in page_remove) * * No support for jumbos here. We will need to be careful when trying to * insert regular pages into something that was already jumbo. We will * also need to be careful with our overloading of the PTE_PS and * PTE_PAT flags... * * @param[in] pgdir the page directory to insert the page into * @param[in] pp a pointr to the page struct representing the * physical page that should be inserted. * @param[in] va the virtual address where the page should be * inserted. * @param[in] perm the permition bits with which to set up the * virtual mapping. * * @return ESUCCESS on success * @return -ENOMEM if a page table could not be allocated * into which the page should be inserted * */ int page_insert(pde_t *pgdir, struct page *page, void *va, int perm) { pte_t* pte = pgdir_walk(pgdir, va, 1); if (!pte) return -ENOMEM; /* Two things here: First, we need to up the ref count of the page we want * to insert in case it is already mapped at va. In that case we don't want * page_remove to ultimately free it, and then for us to continue as if pp * wasn't freed. (moral = up the ref asap) */ kref_get(&page->pg_kref, 1); /* Careful, page remove handles the cases where the page is PAGED_OUT. */ if (!PAGE_UNMAPPED(*pte)) page_remove(pgdir, va); *pte = PTE(page2ppn(page), PTE_P | perm); return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. if (va>=(void*)UTOP || ROUNDDOWN(va,PGSIZE)!=va) return -E_INVAL; struct Env *e; int ret = envid2env(envid, &e, 1); if (ret) return ret; //bad_env page_remove(e->env_pgdir, va); return 0; panic("sys_page_unmap not implemented"); }
// (if no page is mapped, the function silently succeeds) // // Return 0 on success, < 0 on error. // // Cannot unmap pages above UTOP. int sys_mem_unmap(int sysno,u_int envid, u_int va) { // Your code here. int ret; struct Env *env; struct Page *ppage; Pte *ppte; ret = 0; if((ret = envid2env(envid, &env, 0))<0) return ret; page_remove(env->env_pgdir, va); return ret; // panic("sys_mem_unmap not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *env; int r; if ((r=envid2env(envid,&env,1))<0) return -E_BAD_ENV; if ((uint32_t)va>=UTOP || ROUNDUP(va,PGSIZE)!=va) return -E_INVAL; page_remove(env->env_pgdir,va); return 0; // panic("sys_page_unmap not implemented"); }
// Try to send 'value' to the target env 'envid'. // If srcva < UTOP, then also send page currently mapped at 'srcva', // so that receiver gets a duplicate mapping of the same page. // // The send fails with a return value of -E_IPC_NOT_RECV if the // target has not requested IPC with sys_ipc_recv. // // Otherwise, the send succeeds, and the target's ipc fields are // updated as follows: // env_ipc_recving is set to 0 to block future sends; // env_ipc_from is set to the sending envid; // env_ipc_value is set to the 'value' parameter; // env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise. // The target environment is marked runnable again, returning 0 // from the paused ipc_recv system call. // // If the sender sends a page but the receiver isn't asking for one, // then no page mapping is transferred, but no error occurs. // The ipc only happens when no errors occur. // // Returns 0 on success where no page mapping occurs, // 1 on success where a page mapping occurs, and < 0 on error. // Errors are: // -E_BAD_ENV if environment envid doesn't currently exist. // (No need to check permissions.) // -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv, // or another environment managed to send first. // -E_INVAL if srcva < UTOP but srcva is not page-aligned. // -E_INVAL if srcva < UTOP and perm is inappropriate // (see sys_page_alloc). // -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's // address space. // -E_INVAL if (perm & PTE_W), but srcva is read-only in the // current environment's address space. // -E_NO_MEM if there's not enough memory to map srcva in envid's // address space. static int sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) { // LAB 4: Your code here. struct Env *env; int err, ret = 0; pte_t *pte; struct Page *pp = NULL; if ((err = envid2env(envid, &env, 0)) < 0) return err; if (env->env_ipc_recving == 0) return -E_IPC_NOT_RECV; env->env_ipc_perm = 0; if ((uint32_t)srcva < UTOP && (uint32_t)env->env_ipc_dstva < UTOP) { if (((perm & (~PTE_USER)) != 0) || ((perm & (PTE_U | PTE_P)) != (PTE_U | PTE_P))) return -E_INVAL; pp = page_lookup(curenv->env_pgdir, srcva, &pte); if ((*pte & PTE_P) == 0 || pp == NULL) return -E_INVAL; if (((*pte & PTE_W) == 0) && (perm & PTE_W)) return -E_INVAL; env->env_ipc_perm = perm; page_lookup(env->env_pgdir, env->env_ipc_dstva, &pte); if ((*pte & PTE_P) == 0) { if ((err = page_insert(env->env_pgdir, pp, env->env_ipc_dstva, perm)) < 0) return err; } else { page_remove(env->env_pgdir, env->env_ipc_dstva); if ((err = page_insert(env->env_pgdir, pp, env->env_ipc_dstva, perm)) < 0) return err; } ret = 1; } env->env_ipc_recving = 0; env->env_ipc_from = curenv->env_id; env->env_ipc_value = value; env->env_status = ENV_RUNNABLE; return ret; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. if(va >= (void *)UTOP || ROUNDUP(va, PGSIZE) != va) { return -E_INVAL; } struct Env *env; int ret; if((ret = envid2env(envid, &env, 1)) < 0) { return -E_INVAL; } page_remove(env->env_pgdir, va); return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *task; if (envid2env(envid, &task, 1) < 0) return -E_BAD_ENV; if ((unsigned int)va >= UTOP || va != ROUNDDOWN(va, PGSIZE)) return -E_INVAL; page_remove(task->env_pgdir, va); return 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 *tmp = pgdir_walk(pgdir, va, 1); if( tmp == NULL ) return -E_NO_MEM; pp->pp_ref += 1; if( (*tmp & PTE_P) != 0 ) page_remove(pgdir, va); *tmp = page2pa(pp) | perm | PTE_P; pp->pp_link = NULL; return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). struct Env* envnow; int r = envid2env(envid, &envnow, 1); if(r < 0) { cprintf("\n envid2env error %e sys_page_map\n", r); return r; } if ((uint64_t)va >= UTOP || PGOFF(va)) return -E_INVAL; page_remove(envnow->env_pml4e, va); return 0; // LAB 4: Your code here. //panic("sys_page_unmap not implemented"); }
// // 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* pg_entry = pgdir_walk(pgdir, va, 1); if (!pg_entry) { return -E_NO_MEM; } pp->pp_ref++; if (*pg_entry & PTE_P){ tlb_invalidate(pgdir, va); page_remove(pgdir, va); } *pg_entry = page2pa(pp) | perm | PTE_P; pgdir[PDX(va)] |= perm | PTE_P; return 0; }
// check_pgfault - check correctness of pgfault handler static void check_pgfault(void) { size_t nr_free_pages_store = nr_free_pages(); size_t slab_allocated_store = slab_allocated(); check_mm_struct = mm_create(); assert(check_mm_struct != NULL); struct mm_struct *mm = check_mm_struct; pgd_t *pgdir = mm->pgdir = boot_pgdir; assert(pgdir[0] == 0); struct vma_struct *vma = vma_create(0, PTSIZE, VM_WRITE); assert(vma != NULL); insert_vma_struct(mm, vma); uintptr_t addr = 0x100; assert(find_vma(mm, addr) == vma); int i, sum = 0; for (i = 0; i < 100; i ++) { *(char *)(addr + i) = i; sum += i; } for (i = 0; i < 100; i ++) { sum -= *(char *)(addr + i); } assert(sum == 0); page_remove(pgdir, ROUNDDOWN(addr, PGSIZE)); free_page(pa2page(PMD_ADDR(*get_pmd(pgdir, addr, 0)))); free_page(pa2page(PUD_ADDR(*get_pud(pgdir, addr, 0)))); free_page(pa2page(PGD_ADDR(*get_pgd(pgdir, addr, 0)))); pgdir[0] = 0; mm->pgdir = NULL; mm_destroy(mm); check_mm_struct = NULL; assert(nr_free_pages_store == nr_free_pages()); assert(slab_allocated_store == slab_allocated()); cprintf("check_pgfault() succeeded!\n"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. int ret; struct Env *env; if((uintptr_t)va >= UTOP) return -E_INVAL; if((uintptr_t)va % PGSIZE) return -E_INVAL; if((ret = envid2env(envid, &env, 1)) < 0) return ret; page_remove(env->env_pgdir, va); return 0; // panic("sys_page_unmap not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *env; if (envid2env(envid, &env, 1) != 0) return -E_BAD_ENV; if ((uint32_t) va >= UTOP || (uint32_t) va % PGSIZE != 0) return -E_INVAL; page_remove(env->env_pgdir, va); return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. if (va >= (void *)UTOP || PGOFF(va)) return -E_INVAL; struct Env *env; if (envid2env(envid, &env, 1)) { return -E_BAD_ENV; } page_remove(env->env_pgdir, va); return 0; // panic("sys_page_unmap not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. int ret; struct Env *e; ret = envid2env(envid, &e, 1); if (ret < 0) { return ret; } if ((uint32_t)va >= UTOP || (uint32_t)va % PGSIZE != 0) { return -E_INVAL; } page_remove(e->env_pgdir, va); return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *env; if(envid2env(envid, &env, 1) == -E_BAD_ENV) return -E_BAD_ENV; else if((uint32_t)va >= UTOP || (uint32_t)va % PGSIZE) return -E_INVAL; else { page_remove(env->env_pgdir,va); return 0; } //panic("sys_page_unmap not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. int rslt; struct Env *tmp; pte_t *srcpte; struct PageInfo *pg; if((rslt = envid2env(envid, &tmp, 1)) != 0) return rslt; if(va >= (void *)UTOP || (((size_t)va % PGSIZE) != 0)) return -E_INVAL; page_remove(tmp->env_pgdir, va); return 0; //panic("sys_page_unmap not implemented"); }
// 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; //cprintf("1"); // 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))); //cprintf("1"); page_free(pp0); memset(page2kva(pp1), 1, PGSIZE); memset(page2kva(pp2), 2, PGSIZE); //cprintf("1"); page_insert(kern_pgdir, pp1, (void*) PGSIZE, PTE_W); //cprintf("1"); assert(pp1->pp_ref == 1); //cprintf("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); //cprintf("1"); // 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; //cprintf("1"); // free the pages we took page_free(pp0); cprintf("check_page_installed_pgdir() succeeded!\n"); }
// // 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) { // Fill this function in /*stone's solution for lab2*/ pte_t *pte = pgdir_walk(pgdir, va, 1); if (pte == NULL) return -E_NO_MEM; if (pp == page_lookup(pgdir, va, &pte)){ tlb_invalidate(pgdir, va); *pte = page2pa(pp) | perm | PTE_P; } else{ page_remove(pgdir, va); pp->pp_ref++; *pte = page2pa(pp) | perm | PTE_P; } return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *e=NULL; if((uint32_t)va>=UTOP) return -E_INVAL; //cprintf("\nPageUnmap %x\n",va); if(envid2env(envid,&e,1)<0) return -E_BAD_ENV; else { page_remove(e->env_pgdir,va); return 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) { // Fill this function in pte_t *pte; pte = pgdir_walk(pgdir, va, 1); if (!pte) return -E_NO_MEM; /* Incrementing pp->pp_ref before page_remove is the elegant way */ /* to deal with re-insertion. */ ++pp->pp_ref; if (*pte & PTE_P) { page_remove(pgdir, va); } *pte = page2pa(pp) | perm | PTE_P; tlb_invalidate(pgdir, va); return 0; }
// check_pgfault - check correctness of pgfault handler static void check_pgfault(void) { size_t nr_free_pages_store = nr_free_pages(); check_mm_struct = mm_create(); assert(check_mm_struct != NULL); struct mm_struct *mm = check_mm_struct; pde_t *pgdir = mm->pgdir = boot_pgdir; assert(pgdir[0] == 0); struct vma_struct *vma = vma_create(0, PTSIZE, VM_WRITE); assert(vma != NULL); insert_vma_struct(mm, vma); uintptr_t addr = 0x100; assert(find_vma(mm, addr) == vma); int i, sum = 0; for (i = 0; i < 100; i ++) { // cprintf("%d\n", i); *(char *)(addr + i) = i; sum += i; } // assert(0); for (i = 0; i < 100; i ++) { sum -= *(char *)(addr + i); } assert(sum == 0); page_remove(pgdir, ROUNDDOWN(addr, PGSIZE)); free_page(pde2page(pgdir[0])); pgdir[0] = 0; mm->pgdir = NULL; mm_destroy(mm); check_mm_struct = NULL; assert(nr_free_pages_store == nr_free_pages()); cprintf("check_pgfault() succeeded!\n"); }
static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env* env; if(envid2env(envid, &env,1) != 0) { return -E_BAD_ENV; } if(va == NULL || (uint64_t)va >= UTOP || (uint64_t)va % PGSIZE != 0) { return -E_INVAL; } page_remove(env->env_pml4e, va); return 0; //panic("sys_page_unmap not implemented"); }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. struct Env *env; struct Page *pp = NULL; int err; if ((err = envid2env(envid, &env, 1)) < 0) return err; if ((uintptr_t)va >= UTOP || PGOFF(va) != 0) return -E_INVAL; page_remove(env->env_pgdir, va); return 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* pte = pgdir_walk(pgdir, va, 1); if (pte == NULL) return -E_NO_MEM; if ((*pte & PTE_P)) { if (pa2page(PTE_ADDR(*pte)) != pp) page_remove(pgdir, va); else{ --pp->pp_ref; tlb_invalidate(pgdir, va); } } *pte = page2pa(pp) | perm | PTE_P; pp -> pp_ref++; return 0; }
// Unmap the page of memory at 'va' in the address space of 'envid'. // If no page is mapped, the function silently succeeds. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if environment envid doesn't currently exist, // or the caller doesn't have permission to change envid. // -E_INVAL if va >= UTOP, or va is not page-aligned. static int sys_page_unmap(envid_t envid, void *va) { // Hint: This function is a wrapper around page_remove(). // LAB 4: Your code here. /*stone's solution for lab4-A*/ //panic("sys_page_unmap not implemented"); struct Env* e; int r; if ((r = envid2env(envid, &e, 1)) < 0) return r; if (va >= (void*)UTOP) return -E_INVAL; if (((uint32_t)va % PGSIZE) != 0) return -E_INVAL; page_remove(e->env_pgdir, va); return 0; }