// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, uintptr_t va) { pte_t *pte; Page *pp = page_lookup(pgdir, va, &pte); if (pp != NULL) { page_decref(pp); *pte = *pte & ~0x1; tlb_invalidate(pgdir, va); } }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. struct Env *srcenv; struct Env *dstenv; pte_t *pte; struct Page *pp; // Env Ids valid and caller has perms to access them if (envid2env(srcenvid, &srcenv, 1) < 0 || envid2env(dstenvid, &dstenv, 1) < 0) { return -E_BAD_ENV; } // VAs below UTOP and page aligned if ((uintptr_t)srcva >= UTOP || (uintptr_t)srcva % PGSIZE || (uintptr_t)dstva >= UTOP || (uintptr_t)dstva % PGSIZE) { return -E_INVAL; } if ((pp = page_lookup(srcenv->env_pgdir, srcva, &pte)) == NULL) { return -E_INVAL; } // PTE_U | PTE_P must be set if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0) { return -E_INVAL; } // Only U, P, W and AVAIL can be set if ((perm & ~(PTE_U | PTE_P | PTE_W | PTE_AVAIL)) != 0) { return -E_INVAL; } // Dest page writable but source isn't if ((perm & PTE_W) && ((*pte & PTE_W) == 0)) { return -E_INVAL; } if (page_insert(dstenv->env_pgdir, pp, dstva, perm) < 0) { return -E_NO_MEM; } return 0; }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. /* lj */ struct Env *senv = NULL, *denv = NULL; int ret = 0; struct Page *p = NULL; pte_t *spte = NULL, *dpte = NULL; //cprintf("0 0x%x 0x%x 0x%x 0x%x \n",srcenvid, srcva, dstenvid, dstva); if((ret = envid2env(srcenvid, &senv, 1)) < 0) { return ret; } if((ret = envid2env(dstenvid, &denv, 1)) < 0) { return ret; } else if((size_t)dstva > UTOP || (size_t)srcva > UTOP) { return -E_INVAL; } else if(((size_t)dstva & (PGSIZE-1)) || ((size_t)srcva & (PGSIZE - 1))) { return -E_INVAL; } else if(NULL == (p = page_lookup(senv->env_pgdir, srcva, &spte))) { return -E_INVAL; } else if(0 == (perm & (PTE_U | PTE_P))) { return -E_INVAL; } else if(perm & ~(PTE_U | PTE_P | PTE_W | PTE_AVAIL)) { return -E_INVAL; } else if((perm & PTE_W) && !(*spte & PTE_W)) { return -E_INVAL; } assert(senv); assert(denv); assert(*spte & PTE_P); if((ret = page_insert(denv->env_pgdir, p, dstva, perm)) < 0) { } return ret; //panic("sys_page_map not implemented"); }
/* this function reads out a value from esp +offset and checks if it is a valid pointer */ int * value_stack_int (void * esp, int offset) { void * ptr = (void *)(esp + offset); void * result; if (is_user_vaddr((int *)ptr) && (int *)ptr != NULL ) { result = page_lookup((int *)ptr, thread_current()); if (result != NULL) return (int *) ptr; } exit_mythread(-1); 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t *tmppte; struct PageInfo *tmp = page_lookup(pgdir, va, &tmppte); if( tmp != NULL && (*tmppte & PTE_P)) { page_decref(tmp); *tmppte = 0; } tlb_invalidate(pgdir, va); }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { pte_t *pte; struct Page* pp = page_lookup(pgdir, va, &pte); if (pp) { page_decref(pp); *pte = 0; tlb_invalidate(pgdir, va); } }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t * pte_page; struct Page * page = page_lookup(pgdir, va, &pte_page); if(page) { page_decref(page); (* pte_page) = 0; tlb_invalidate(pgdir, va); } }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { pte_t *table_entry; struct PageInfo *page = page_lookup(pgdir, va, &table_entry); if (page) { // Decrement/free page, reset table entry, and invalidate TLB entry. page_decref(page); *table_entry = 0x0; tlb_invalidate(pgdir, va); } }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pml4e_t *pml4e, void *va) { // Fill this function in pte_t* pte = NULL; struct Page *page = page_lookup(pml4e, va, &pte); if(page != 0){ page_decref(page); *pte = 0; tlb_invalidate(pml4e, va); } }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t* pte_store = NULL; struct PageInfo* pg = page_lookup(pgdir, va, &pte_store); if (!pg) return; page_decref(pg); tlb_invalidate(pgdir, va); *pte_store = 0; }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate the new page, // or to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. int errno; pte_t *pte; struct Page *page; struct Env *srcEnv, *dstEnv; if (((uint32_t)srcva >= UTOP) || ((uint32_t)srcva % PGSIZE) || ((uint32_t)dstva >= UTOP) || ((uint32_t)dstva % PGSIZE)) { dbg_print("invalid address"); return -E_INVAL; } if ((errno = envid2env(srcenvid, &srcEnv, 1)) < 0) { dbg_print("env %d does not exist", srcenvid); return errno; } if ((errno = envid2env(dstenvid, &dstEnv, 1)) < 0) { dbg_print("env %d does not exist", dstenvid); return errno; } if (!(perm & PTE_U) || !(perm & PTE_P)) { dbg_print("invalid perm 0x%08x", perm); return -E_INVAL; } page = page_lookup(srcEnv->env_pgdir, srcva, &pte); if (!page || ((perm & PTE_W) && !(*pte & PTE_W))) { dbg_print("invalid page 0x%p, perm=0x%08x, *pte=0x%08x", page, perm, *pte); return -E_INVAL; } if ((errno = page_insert(dstEnv->env_pgdir, page, dstva, perm)) < 0) { dbg_print("Env %d page_insert error: va=0x%08x"); page_free(page); return errno; } return 0; //panic("sys_page_map not implemented"); }
static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. struct Env *srcenv=NULL; struct Env *destenv=NULL; struct Page *p=NULL; if(envid2env(srcenvid,&srcenv,1)<0 || envid2env(dstenvid,&destenv,1)<0) return -E_BAD_ENV; if(srcva>= (void *)UTOP || dstva>= (void *)UTOP || ((uint32_t)srcva)%PGSIZE!=0 ||((uint32_t)dstva)%PGSIZE!=0) return -E_INVAL; pte_t *srcPageToMap=NULL; p = page_lookup(srcenv->env_pgdir,srcva,&srcPageToMap); if(p==NULL) return -E_INVAL; else { if( (perm & PTE_P)!=0 && (perm & PTE_U)!=0) { if((perm & ((~(PTE_USER)) & 0xFFF))!=0) return -E_INVAL; } else return -E_INVAL; int srcperm = (*(srcPageToMap) & 0xFFF); if ((srcperm & PTE_W) == 0) { if((perm & PTE_W)!=0) return -E_INVAL; } //else { if (page_insert(destenv->env_pgdir,p,dstva,perm)<0) return -E_NO_MEM; else return 0; } } return -E_NO_MEM; }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. struct Env *env1,*env2; struct PageInfo *pg; pte_t *pte; int ret; ret = envid2env(srcenvid, &env1, 1); if(ret < 0){ cprintf("sys page map error in screnvid \n"); return -E_BAD_ENV; } ret = envid2env(dstenvid, &env2, 1); if(ret < 0){ cprintf("sys page map error in dstenvid \n"); return -E_BAD_ENV; }else if((uint64_t)srcva >= UTOP || ((uint64_t)srcva)%PGSIZE != 0){ cprintf("sys page map error. srcva is > utop or srcva is not alligned \n"); return -E_INVAL; }else if((uint64_t)dstva >= UTOP || ((uint64_t)dstva)%PGSIZE != 0){ cprintf("sys page map error. dstva is > utop or dstva is not alligned \n"); return -E_INVAL; }else if(!(perm & PTE_U) && !(perm & PTE_P) && (perm & ~PTE_SYSCALL)){ //now unchanged in the end cprintf("sys page map error. permission mismatch \n"); return -E_INVAL; } if(!(pg = page_lookup(env1->env_pml4e, srcva, &pte))){ cprintf("sys page map error. Page lookup failed for env1 \n"); return -E_INVAL; }else if(((perm & PTE_W) != 0) && ((*pte & PTE_W) == 0)){ cprintf("sys page map error. Write permission error \n"); return -E_INVAL; }else if(page_insert(env2->env_pml4e, pg, dstva, perm)){ cprintf("sys page map error. Page insert failed for env2 \n"); page_free(pg); return -E_NO_MEM; } return 0; // panic("sys_page_map 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 is not blocked, waiting for an IPC. // // The send also can fail for the other reasons listed below. // // 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 sys_ipc_recv system call. (Hint: does the // sys_ipc_recv function ever actually return?) // // If the sender wants to send 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, < 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* dstenv; int ret; pte_t *pte; uintptr_t dstva; if((ret = envid2env(envid, &dstenv, 0)) < 0) return ret; if(dstenv->env_ipc_recving == 0) return -E_IPC_NOT_RECV; if((uintptr_t)srcva >= UTOP) return -E_INVAL; if(PGOFF((uintptr_t)srcva)) return -E_INVAL; if((uintptr_t)srcva != USTACKTOP) { if((perm & ~PTE_SYSCALL) || !(perm & PTE_P) || !(perm & PTE_U)) return -E_INVAL; if((pte = pgdir_walk(curenv->env_pgdir, srcva, 0)) == NULL) return -E_INVAL; if((perm & PTE_W) && !(*pte & PTE_W)) return -E_INVAL; dstva = (uintptr_t)dstenv->env_ipc_dstva; if(dstva != USTACKTOP) { /* if((ret = sys_page_map(0, srcva, envid, (void*)dstva, perm)) < 0) return ret;*/ /* i don't use sys_page_map. because filesystem env is neither current env nor * the child of current env. sys_page_map require envid is current env or the * child of current env; */ struct Page *page; if ((page = page_lookup(curenv->env_pgdir, srcva, NULL)) == NULL) return -E_INVAL; if (page_insert(dstenv->env_pgdir, page, (void*)dstva, perm) < 0) return -E_NO_MEM; dstenv->env_ipc_perm = perm; } else { dstenv->env_ipc_perm = 0; } } else { dstenv->env_ipc_perm = 0; } dstenv->env_ipc_from = curenv->env_id; dstenv->env_ipc_value = value; dstenv->env_tf.tf_regs.reg_eax = 0; dstenv->env_ipc_recving = 0; dstenv->env_status = ENV_RUNNABLE; return 0; //panic("sys_ipc_try_send not implemented"); }
// Try to send 'value' to the target env 'envid'. // If va != 0, then also send page currently mapped at 'va', // 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 doesn't happen unless 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_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. //cprintf("envid in try send:%08x\n",envid); struct Env *env,dstenv; int32_t ret; struct Page *page; pte_t *pte; if(envid2env(envid,&env,0) != 0) return -E_BAD_ENV; if(env->env_ipc_recving == 0) return -E_IPC_NOT_RECV; else { //cprintf("try send set ipc:%8x not recv\n",envid); env->env_ipc_recving = 0; env->env_ipc_from = curenv->env_id; env->env_ipc_value = value; if(srcva == 0 ||env->env_ipc_dstva == 0) { env->env_ipc_perm = 0; if(env->env_status != ENV_RUNNABLE) { env->tickets = INIT_TICKET; global_tickets += env->tickets; } env->env_status = ENV_RUNNABLE; return 0; } else if((uint32_t)srcva < UTOP) { env->env_ipc_perm = perm; if((page = page_lookup(curenv->env_pgdir,srcva,&pte)) == NULL) return -E_INVAL; if((ret = page_insert(env->env_pgdir, page, env->env_ipc_dstva, perm)) < 0) return ret; if(ret == 0) { if(env->env_status != ENV_RUNNABLE) { env->tickets = INIT_TICKET; global_tickets += env->tickets; } env->env_status = ENV_RUNNABLE; return 1; } } return 0; } }
// // Invalidate a TLB entry, but only if the page tables being // edited are the ones currently in use by the processor. // void tlb_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. pte_t *tmppte; struct PageInfo *tmp = page_lookup(pgdir, va, &tmppte); if( tmp != NULL) { page_decref(tmp); *tmppte = 0; } invlpg(va); }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in //bluesea struct PageInfo *page = NULL; pte_t *ptep = NULL; if ((page = page_lookup(pgdir, va, &ptep)) != NULL){ page_decref(page); *ptep = *ptep & (0xfff & ~PTE_P); tlb_invalidate(pgdir, va); } }
static int sys_clear_block_access_bit(envid_t envid, void *va) { struct Env *env; pte_t *pte; envid2env(envid,&env,1); if(env == NULL) return -E_BAD_ENV; if((uintptr_t)va >= UTOP || PGOFF(va) != 0) return -E_INVAL; if(page_lookup(env->env_pgdir, va, &pte) == NULL) return -E_INVAL; *pte &= ~ PTE_A; return 0; }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { pte_t* pte; struct Page* res; res=page_lookup(pgdir,va,&pte); if(res!=NULL) { page_decref(res); *pte=0; tlb_invalidate(pgdir,va); } }
/* Returns true if uva and kva both resolve to the same phys addr. If uva is * unmapped, it will return FALSE. This is probably what you want, since after * all uva isn't kva. */ bool uva_is_kva(struct proc *p, void *uva, void *kva) { struct page *u_page; assert(kva); /* catch bugs */ /* Check offsets first */ if (PGOFF(uva) != PGOFF(kva)) return FALSE; /* Check to see if it is the same physical page */ u_page = page_lookup(p->env_pgdir, uva, 0); if (!u_page) return FALSE; return (kva2page(kva) == u_page) ? TRUE : FALSE; }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t* pte; struct Page* pp = page_lookup(pgdir, va, &pte); if (pp != NULL) { *pte = 0; page_decref(pp); tlb_invalidate(pgdir, va); } }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in /*stone's solution for lab2*/ pte_t* pte; struct Page* pp = page_lookup(pgdir, va, &pte); if (pp != NULL){ *pte = 0; page_decref(pp); tlb_invalidate(pgdir, va); } return; }
// Try to send 'value' to the target env 'envid'. // Returns 0 on success where no page mapping occurs, // 1 on success where a page mapping occurs, and < 0 on error. static int sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) { struct Env *target; int r; struct Page *p; if ((r = envid2env(envid, &target, 0)) < 0) return r; if (!target->env_ipc_recving) return -E_IPC_NOT_RECV; spin_lock(&target->env_lock); target->env_ipc_recving = 0; target->env_ipc_from = curenv->env_id; target->env_ipc_value = value; target->env_ipc_perm = 0; if (srcva) { if ((uintptr_t)srcva >= UTOP || (uintptr_t)srcva % PGSIZE) { spin_unlock(&target->env_lock); return -E_INVAL; } if (!(perm & PTE_U) || !(perm &PTE_P) || perm & ~PTE_USER) { spin_unlock(&target->env_lock); return -E_INVAL; } if ((p = page_lookup(curenv->env_pgdir, srcva, 0)) == NULL) { spin_unlock(&target->env_lock); return -E_INVAL; } /* Now it's safe to use srcva */ if (target->env_ipc_dstva) { if ((r = page_insert(target->env_pgdir, p, target->env_ipc_dstva, perm)) < 0) { spin_unlock(&target->env_lock); return r; } target->env_ipc_perm = perm; target->env_status = ENV_RUNNABLE; /* Wake up the blocking recver */ spin_unlock(&target->env_lock); return 1; } } target->env_status = ENV_RUNNABLE; /* Wake up the blocking recver */ spin_unlock(&target->env_lock); return 0; }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Lookup the page and store into page_table_entry pte_t * page_table_entry = NULL; struct PageInfo * page_info = page_lookup(pgdir, va, &page_table_entry); if (page_info != NULL) { // Decrement the counter and free if the refcount reaches zero page_decref(page_info); *page_table_entry = 0; tlb_invalidate(pgdir, va); } }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. struct Env *srcenv, *dstenv; int r1 = envid2env(srcenvid, &srcenv, 1); int r2 = envid2env(dstenvid, &dstenv, 1); /* Proper envid check*/ if (r1 < 0 || r2 < 0) { cprintf("\n envid2env error %e, %e sys_page_map\n", r1, r2); return -E_BAD_ENV; } /*Address range check*/ if((uintptr_t)srcva >= UTOP || (uintptr_t)dstva >= UTOP || PGOFF(srcva) || PGOFF(dstva)) { cprintf("\n envid2env error %e sys_page_map\n", -E_INVAL); return -E_INVAL; } /*Correct page request check*/ struct PageInfo *map; pte_t *p_entry; map = page_lookup(srcenv->env_pml4e, srcva, &p_entry); if(!map) { cprintf("\n No page available or not mapped properly SYS_PAGE_ALLOC %e \n", -E_NO_MEM); return -E_NO_MEM; } /*Proper Permission check*/ int map_perm = PTE_P | PTE_U; if ((perm & map_perm) != map_perm || (perm & ~PTE_SYSCALL)) { cprintf("\n permission error %e sys_page_map\n", -E_INVAL); return -E_INVAL; } if((perm & PTE_W) && !(*p_entry & PTE_W)) { cprintf("\n permission error %e sys_page_map\n", -E_INVAL); return -E_INVAL; } /*Page insert check*/ if(page_insert(dstenv->env_pml4e, map, dstva, perm) < 0) { cprintf("\n No memory to allocate page SYS_PAGE_MAP %e \n", -E_NO_MEM); return -E_NO_MEM; } return 0; // LAB 4: Your code here. //panic("sys_page_map not implemented"); }
// // 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 page table. // // Hint: The TA solution is implemented using page_lookup, // tlb_invalidate, and page_decref. // void page_remove(pde_t *pgdir, void *va) { // Fill this function in pte_t *pte_store; struct PageInfo *pp = page_lookup(pgdir, va, &pte_store); if(!pte_store || !(pte_store[0] & PTE_P)){ return ; } page_decref(pp); *pte_store = 0; tlb_invalidate(pgdir, va); }
void page_remove(pgd_t* pgdir, viraddr_t va) { assert(pgdir); page_t *pf; pte_t *pte_store; pf = page_lookup(pgdir, va, &pte_store); if( pf == NULL ) return; //printk("free:%x\n",va); page_decref(pf); pte_set(*pte_store,0); refresh_tlb(pgdir, va); }
/*ARGSUSED*/ static int bootfs_getapage(vnode_t *vp, u_offset_t off, size_t len, uint_t *protp, page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw, cred_t *cr) { bootfs_node_t *bnp = vp->v_data; page_t *pp, *fpp; pfn_t pfn; for (;;) { /* Easy case where the page exists */ pp = page_lookup(vp, off, rw == S_CREATE ? SE_EXCL : SE_SHARED); if (pp != NULL) { if (pl != NULL) { pl[0] = pp; pl[1] = NULL; } else { page_unlock(pp); } return (0); } pp = page_create_va(vp, off, PAGESIZE, PG_EXCL | PG_WAIT, seg, addr); /* * If we didn't get the page, that means someone else beat us to * creating this so we need to try again. */ if (pp != NULL) break; } pfn = btop((bnp->bvn_addr + off) & PAGEMASK); fpp = page_numtopp_nolock(pfn); if (ppcopy(fpp, pp) == 0) { pvn_read_done(pp, B_ERROR); return (EIO); } if (pl != NULL) { pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw); } else { pvn_io_done(pp); } return (0); }
// 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 is not blocked, waiting for an IPC. // // The send also can fail for the other reasons listed below. // // 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 sys_ipc_recv system call. (Hint: does the // sys_ipc_recv function ever actually return?) // // If the sender wants to send 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, < 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. //panic("sys_ipc_try_send not implemented"); struct Env *e; // int ret; struct Page *p; //cprintf("%08x is Sending data to: %08x Value: %08x\n",curenv->env_id,envid,value); //cprintf("Calling send ipc...\n"); envid2env(envid,&e,0); if(e==NULL) return -E_BAD_ENV; //cprintf("Calling send ipc 2...\n"); if(e->env_ipc_recving == 0) return -E_IPC_NOT_RECV; //cprintf("Calling send ipc 3...\n"); if(srcva < (void *)UTOP) { if(PGOFF(srcva) != 0) return -E_INVAL; //cprintf("Calling send ipc 4...\n"); if((perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_U & ~PTE_P & ~PTE_AVAIL & ~PTE_W) != 0){ return -E_INVAL; } //cprintf("Calling send ipc 5..\n"); if((p=page_lookup(curenv->env_pgdir, srcva, NULL)) == NULL) return -E_INVAL; //if((perm & PTE_W) && !(*p & PTE_W)) // return -E_INVAL; //cprintf("Calling send ipc 6...\n"); e->env_ipc_perm = perm; if((page_insert(e->env_pgdir, p, e->env_ipc_dstva, perm)) < 0) return -E_NO_MEM; } else { e->env_ipc_perm = 0; } //cprintf("Calling send ipc 7...\n"); e->env_ipc_recving = 0; e->env_ipc_from = curenv->env_id; e->env_ipc_value = value; e->env_status = ENV_RUNNABLE; return 0; }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Perm has the same restrictions as in sys_page_alloc, except // that it also must not grant write access to a read-only // page. // // Return 0 on success, < 0 on error. Errors are: // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. // -E_INVAL is srcva is not mapped in srcenvid's address space. // -E_INVAL if perm is inappropriate (see sys_page_alloc). // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. // -E_NO_MEM if there's no memory to allocate any necessary page tables. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { // Hint: This function is a wrapper around page_lookup() and // page_insert() from kern/pmap.c. // Again, most of the new code you write should be to check the // parameters for correctness. // Use the third argument to page_lookup() to // check the current permissions on the page. // LAB 4: Your code here. // -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist, // or the caller doesn't have permission to change one of them. struct Env *se, *de; int ret = envid2env(srcenvid, &se, 1); if (ret) return ret; //bad_env ret = envid2env(dstenvid, &de, 1); if (ret) return ret; //bad_env // cprintf("src env: %x, dst env: %x, src va: %x, dst va: %x\n", // se->env_id, de->env_id, srcva, dstva); // -E_INVAL if srcva >= UTOP or srcva is not page-aligned, // or dstva >= UTOP or dstva is not page-aligned. if (srcva>=(void*)UTOP || dstva>=(void*)UTOP || ROUNDDOWN(srcva,PGSIZE)!=srcva || ROUNDDOWN(dstva,PGSIZE)!=dstva) return -E_INVAL; // -E_INVAL is srcva is not mapped in srcenvid's address space. pte_t *pte; struct PageInfo *pg = page_lookup(se->env_pgdir, srcva, &pte); if (!pg) return -E_INVAL; // -E_INVAL if perm is inappropriate (see sys_page_alloc). int flag = PTE_U|PTE_P; if ((perm & flag) != flag) return -E_INVAL; // -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's // address space. if (((*pte&PTE_W) == 0) && (perm&PTE_W)) return -E_INVAL; // -E_NO_MEM if there's no memory to allocate any necessary page tables. ret = page_insert(de->env_pgdir, pg, dstva, perm); // cprintf("map done %x\n", ret); return ret; panic("sys_page_map not implemented"); }