// 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. int r; struct Env* env; struct Env* dstenv; pte_t* pte; struct Page* page; if ((r=envid2env(srcenvid,&env,1))<0) return -E_BAD_ENV; if ((r=envid2env(dstenvid,&dstenv,1))<0) return -E_BAD_ENV; if ((uint32_t)srcva>=UTOP || (uint32_t)dstva>=UTOP || srcva!=ROUNDUP(srcva,PGSIZE) || dstva!=ROUNDUP(dstva,PGSIZE)) return -E_INVAL; if ((perm&(PTE_U|PTE_P))!=(PTE_U|PTE_P)) return -E_INVAL; if ((page=page_lookup(env->env_pgdir,srcva,&pte))==NULL) return -E_INVAL; if ((perm&PTE_W)!=0 && (((*pte)&PTE_W)==0)) return -E_INVAL; if ((r=page_insert(dstenv->env_pgdir,page,dstva,perm))<0) return -E_NO_MEM; return 0; // panic("sys_page_map not implemented"); }
// Map the page of memory at 'srcva' in srcenvid's address space // at 'dstva' in dstenvid's address space with permission 'perm'. // Return 0 on success, < 0 on error. static int sys_page_map(envid_t srcenvid, void *srcva, envid_t dstenvid, void *dstva, int perm) { struct Env *es, *ed; struct Page *p; pte_t *pte; int r; if ((r = envid2env(srcenvid, &es, 1)) < 0 || (r = envid2env(dstenvid, &ed, 1)) < 0) return r; if ((uintptr_t)srcva >= UTOP || (uintptr_t)srcva % PGSIZE || (uintptr_t)dstva >= UTOP || (uintptr_t)dstva % PGSIZE) return -E_INVAL; if ((!(perm & (PTE_U + PTE_P))) || perm & ~PTE_USER) return -E_INVAL; if (!(p = page_lookup(es->env_pgdir, srcva, &pte))) return -E_INVAL; if (((perm & PTE_W) && !(*pte & PTE_W))) return -E_INVAL; if ((r = page_insert(ed->env_pgdir, p, dstva, perm)) < 0) return r; 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. if (srcva >= (void *)UTOP || dstva >= (void *)UTOP || (perm & 0x5) != 0x5 || PGOFF(srcva) || PGOFF(dstva) || (perm & (~PTE_SYSCALL))) return -E_INVAL; struct Env *src_env, *dst_env; envid2env(srcenvid, &src_env, 1); envid2env(dstenvid, &dst_env, 1); if (!src_env || !dst_env) { return -E_BAD_ENV; } pte_t *pte; struct Page *page = page_lookup(src_env->env_pgdir, srcva, &pte); if (!page || (!(*pte & PTE_W) && (perm & PTE_W))) { return -E_INVAL; } if (page_insert(dst_env->env_pgdir, page, dstva, perm)) { return -E_NO_MEM; } return 0; // panic("sys_page_map not implemented"); }
// 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. int ret; pte_t *src_pte; struct Page *pp; struct Env *srcenv, *dstenv; if((uintptr_t)srcva >= UTOP || (uintptr_t)dstva >= UTOP) return -E_INVAL; if((uintptr_t)srcva % PGSIZE || (uintptr_t)dstva % PGSIZE) return -E_INVAL; if((perm & ~PTE_SYSCALL) || !(perm & PTE_P) || !(perm & PTE_U)) return -E_INVAL; if((ret = envid2env(srcenvid, &srcenv, 1)) < 0) return ret; if((ret = envid2env(dstenvid, &dstenv, 1)) < 0) return ret; if((pp = page_lookup(srcenv->env_pgdir, srcva, &src_pte)) == NULL) return -E_INVAL; if((perm & PTE_W) && !(*src_pte & PTE_W)) return -E_INVAL; if((ret = page_insert(dstenv->env_pgdir, pp, dstva, perm)) < 0); return ret; return 0; // panic("sys_page_map not implemented"); }
// 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. int rslt; struct Env *src, *dst; pte_t *srcpte; struct PageInfo *pg; if((rslt = envid2env(srcenvid, &src, 1)) != 0) return rslt; if((rslt = envid2env(dstenvid, &dst, 1)) != 0) return rslt; if(srcva >= (void *)UTOP || (((size_t)srcva % PGSIZE) != 0)) return -E_INVAL; if(dstva >= (void *)UTOP || (((size_t)dstva % PGSIZE) != 0)) return -E_INVAL; if((pg = page_lookup(src->env_pgdir, srcva, &srcpte)) == NULL || !(*srcpte & PTE_P)) return -E_INVAL; if((perm & (PTE_U | PTE_P)) != (PTE_U | PTE_P)) return -E_INVAL; if((perm & PTE_W) && !(*srcpte & PTE_W)) return -E_INVAL; rslt = page_insert(dst->env_pgdir, pg, dstva, perm); return rslt; //panic("sys_page_map not implemented"); }
// 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. // // TODO: after finishing lab6 refactor this function (and any other // funcs that are defined here; 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. // page_lookup returns page that is mapped at particular va addr // page_insert does the actual page mapping uint32_t src = (uint32_t)srcva; uint32_t dst = (uint32_t)dstva; int mask = ~(PTE_U | PTE_P | PTE_AVAIL | PTE_W); int ret = -1; bool write_perm = perm & PTE_W; struct Env *srcenv, *dstenv; pte_t *pte; struct PageInfo *p; if (!(perm & (PTE_U | PTE_P)) || (mask & perm)) { return -E_INVAL; } if (src % PGSIZE != 0 || dst % PGSIZE != 0 || (uint32_t)src >= UTOP || (uint32_t)dst >= UTOP) { return -E_INVAL; } ret = envid2env(srcenvid, &srcenv, 0); if (ret < 0) { return ret; } ret = envid2env(dstenvid, &dstenv, 0); if (ret < 0) { return ret; } // get source page that will be mapped onto dstenv p = page_lookup(srcenv->env_pgdir, srcva, &pte); if (!p) { return -E_INVAL; } if (!(*pte & PTE_W) && write_perm) { return -E_INVAL; } ret = page_insert(dstenv->env_pgdir, p, dstva, perm); if (ret < 0) { return ret; } 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. // aj-code struct Env *dstenv, *srcenv; int r; pte_t *pte_ptr; if ((r=envid2env(envid, &dstenv, 0)) < 0) { cprintf("\nReached dest env bad environment"); return -E_BAD_ENV; } if ((r=envid2env(0, &srcenv, 0)) < 0) { return -E_BAD_ENV; } if (dstenv->env_ipc_recving == 0) return -E_IPC_NOT_RECV; dstenv->env_ipc_recving = 0; dstenv->env_ipc_from = curenv->env_id; dstenv->env_ipc_value = value; // page transfer if ((uintptr_t)srcva<UTOP) { struct Page *src_page; struct Page *dst_page; pte_t *src_pte; pte_t *dst_pte; src_page = page_lookup(srcenv->env_pml4e, srcva, &src_pte); if (!src_page) { return -E_INVAL; } int result_dst = page_insert(dstenv->env_pml4e, src_page, dstenv->env_ipc_dstva, perm); if (result_dst) { return -E_NO_MEM; } dstenv->env_ipc_perm = perm; } else { //not a page transfer dstenv->env_ipc_perm = 0; } dstenv->env_status = ENV_RUNNABLE; return 0; panic("sys_ipc_try_send not implemented"); }
// 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. int result_src, result_dst; struct Env *src_env = NULL, *dst_env = NULL; result_src = envid2env(srcenvid, &src_env, 1); result_dst = envid2env(dstenvid, &dst_env, 1); if (result_src || result_dst) { return -E_BAD_ENV; } if ((uintptr_t)srcva>=UTOP || ROUNDUP(srcva, PGSIZE) != srcva || (uintptr_t)dstva>=UTOP || ROUNDUP(dstva, PGSIZE) != dstva) { return -E_INVAL; } struct Page *src_page; struct Page *dst_page; pte_t *src_pte; pte_t *dst_pte; src_page = page_lookup(src_env->env_pml4e, srcva, &src_pte); if (!src_page) { return -E_INVAL; } /* uint64_t src_permission = *src_pte & 0xfff; int source_page_readonly = (src_permission & PTE_W)==0; if (((perm & (PTE_U|PTE_P)) != (PTE_U|PTE_P)) || ((perm & (~PTE_SYSCALL)) != 0) || ((perm & PTE_W) && source_page_readonly)) { return -E_INVAL; } */ result_dst = page_insert(dst_env->env_pml4e, src_page, dstva, perm); if (result_dst) { return -E_NO_MEM; } return result_dst; panic("sys_page_map not implemented"); }
// 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"); }
// 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"); }
// 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"); }
// 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"); }
// 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. // Lab 4 ex 7 // To do lab 4 check perm int returnVal; struct Page *pageVal; struct Env *srcEnv,*destEnv; pte_t *srcPt,*destPt; if((uint64_t)srcva>UTOP)return -E_INVAL; if((uint64_t)dstva>UTOP)return -E_INVAL; if((uint64_t)srcva>(uint64_t)ROUNDDOWN(srcva,PGSIZE))return -E_INVAL; if((uint64_t)dstva>(uint64_t)ROUNDDOWN(dstva,PGSIZE))return -E_INVAL; if((perm & PTE_U) == 0) return -E_INVAL; if((perm & PTE_P) == 0) return -E_INVAL; if((perm & ~PTE_SYSCALL) != 0) return -E_INVAL; returnVal = envid2env(srcenvid,&srcEnv,0); if(returnVal!=0) return -E_BAD_ENV; returnVal = envid2env(dstenvid,&destEnv,0); if(returnVal!=0) return -E_BAD_ENV; pageVal = page_lookup(srcEnv->env_pml4e,srcva,&srcPt); if(pageVal == NULL) return -E_INVAL; if(!(perm & PTE_U) && !(perm & PTE_P)) return -E_INVAL; if(((perm & PTE_W) != 0) && ((*srcPt & PTE_W) == 0)) return -E_INVAL; returnVal = page_insert(destEnv->env_pml4e,pageVal,dstva,perm); if(returnVal != 0) return -E_INVAL; return returnVal; }
// 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. See PTE_SYSCALL in inc/mmu.h. // // 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. //panic("sys_page_alloc not implemented"); struct Env *e; struct Page *p; int r; //cprintf("[sys_page_alloc]:perm is %d\n",perm); if( va >=(void *)UTOP || (perm & 5) != 5 || PGOFF(va)!=0 || (perm & (~PTE_SYSCALL))!=0) return -E_INVAL; r = envid2env(envid, &e, 1); if(r < 0) return -E_BAD_ENV; p = page_alloc(ALLOC_ZERO); if(p == NULL) return -E_NO_MEM; r = page_insert(e->env_pgdir, p, va, perm); if(r < 0){ page_free(p); return -E_NO_MEM; } memset(page2kva(p), 0, PGSIZE); return 0; }
// 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. int r = 0; struct Env *dstEnv = NULL; if ((r=envid2env(envid, &dstEnv, 0)) < 0) { return r; } if (!dstEnv->env_ipc_recving) { return -E_IPC_NOT_RECV; } dstEnv->env_ipc_recving = 0; dstEnv->env_ipc_from = curenv->env_id; dstEnv->env_ipc_value = value; dstEnv->env_status = ENV_RUNNABLE; if ((uint32_t)srcva < UTOP && (uint32_t)(dstEnv->env_ipc_dstva) < UTOP) { if ((r = sys_page_map(0, srcva, envid, dstEnv->env_ipc_dstva, perm)) < 0) { return r; } dstEnv->env_ipc_perm = perm; } else { dstEnv->env_ipc_perm = 0; } return 0; //panic("sys_ipc_try_send 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(). int errno; struct Env *env; struct Page *page; if ((errno = envid2env(envid, &env, 1)) < 0) { dbg_print("env %d does not exist", envid); return errno; } if (((uint32_t)va >= UTOP) || ((uint32_t)va % PGSIZE)) { dbg_print("invalid va address"); return -E_INVAL; } page_remove(env->env_pgdir, va); return 0; // LAB 4: Your code here. //panic("sys_page_unmap not implemented"); }
// Allocate a new environment. // Returns envid of new environment, or < 0 on error. Errors are: // -E_NO_FREE_ENV if no free environment is available. static envid_t sys_exofork(void) { // Create the new environment with env_alloc(), from kern/env.c. // It should be left as env_alloc created it, except that // status is set to ENV_NOT_RUNNABLE, and the register set is copied // from the current environment -- but tweaked so sys_exofork // will appear to return 0. // LAB 4: Your code here. //cprintf("in kern/sys_exofork\n"); envid_t parent_id = sys_getenvid(); struct Env* envn; int ret = env_alloc(&envn, parent_id); if(ret!=0 || !envn){ cprintf("sys_exofork : env_alloc failed.\n"); return -E_NO_FREE_ENV; } struct Env* penv; if(envid2env(parent_id, &penv, 1)!=0){ cprintf("sys_exofork : can't find penv.\n"); return -E_INVAL; } ret = envn->env_id; envn->env_status = ENV_NOT_RUNNABLE; envn->env_tf = penv->env_tf; envn->env_tf.tf_regs.reg_eax = 0; //cprintf("out kern/sys_exofork\n"); return ret; }
// 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. See PTE_SYSCALL in inc/mmu.h. // // 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. int rslt; struct Env *tmp; struct PageInfo *p = NULL; if((rslt = envid2env(envid, &tmp, 1)) != 0) return rslt; if(va >= (void *)UTOP || (((size_t)va % PGSIZE) != 0)) return -E_INVAL; if((perm & (PTE_U | PTE_P)) != (PTE_U | PTE_P)) return -E_INVAL; if((p = page_alloc(1)) == (void*)NULL) return -E_NO_MEM; if((rslt = page_insert(tmp->env_pgdir, p, va, perm)) != 0) { page_free(p); return rslt; } memset(page2kva(p), 0, PGSIZE); return rslt; //panic("sys_page_alloc not implemented"); }
// 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. See PTE_SYSCALL in inc/mmu.h. // // 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. if((uint32_t)va > UTOP) return -E_INVAL; if((uint32_t)va % PGSIZE) return -E_INVAL; if((perm & PTE_U) == 0 || (perm & PTE_P) == 0) return -E_INVAL; struct Env *env; int r = envid2env(envid, &env, 1); if(r == -E_BAD_ENV) return r; struct Page *new_page = page_alloc(ALLOC_ZERO); if(new_page == NULL) return -E_NO_MEM; r = page_insert(env->env_pgdir,new_page, va, perm); if(r < 0){ page_free(new_page); return -E_NO_MEM; } return 0; }
// Set envid's trap frame to 'tf'. // tf is modified to make sure that user environments always run at code // protection level 3 (CPL 3) with interrupts enabled. // // Returns 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. static int sys_env_set_trapframe(envid_t envid, struct Trapframe *tf) { // LAB 5: Your code here. // Remember to check whether the user has supplied us with a good // address! struct Env *env; pte_t *entry; user_mem_assert(curenv, tf, sizeof(struct Trapframe), 0); if (envid2env(envid, &env, 1) != 0){ return -E_BAD_ENV; } entry = pgdir_walk(curenv->env_pgdir, (void *)tf, 0); if (entry == NULL){ return -E_INVAL; } env->env_tf = *tf; // Missing here env->env_tf.tf_ds |= 3; env->env_tf.tf_es |= 3; env->env_tf.tf_ss |= 3; env->env_tf.tf_cs |= 3; env->env_tf.tf_eflags |= FL_IF; env->env_tf.tf_eflags &= ~(FL_IOPL_MASK); 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. /*stone's solution for lab4-C*/ //panic("sys_ipc_try_send not implemented"); struct Env* e; int r; if ((r = envid2env(envid, &e, 0)) < 0) return r; if (!e->env_ipc_recving || e->env_ipc_from != 0) return -E_IPC_NOT_RECV; e->env_ipc_perm = 0; if (srcva < (void*)UTOP){ if (((uint32_t)srcva % PGSIZE) != 0) return -E_INVAL; if (!(perm & PTE_U) || !(perm & PTE_P)) return -E_INVAL; struct Page* p; pte_t* pte; if ((p = page_lookup(curenv->env_pgdir, srcva, &pte)) == NULL) return -E_INVAL; if ((perm & PTE_W) > 0 && !(*pte & PTE_W)) return -E_INVAL; if ((r = page_insert(e->env_pgdir, p, e->env_ipc_dstva, perm)) < 0) return -E_NO_MEM; } e->env_ipc_recving = 0; e->env_ipc_value = value; e->env_ipc_from = curenv->env_id; e->env_ipc_perm = perm; e->env_tf.tf_regs.reg_eax = 0; e->env_status = ENV_RUNNABLE; 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. See PTE_SYSCALL in inc/mmu.h. // // 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. /*stone's solution for lab4-A*/ //panic("sys_page_alloc 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; if (!(perm & PTE_U) || !(perm & PTE_P)) return -E_INVAL; struct Page* p; if ((p = page_alloc(ALLOC_ZERO)) == 0) return -E_NO_MEM; if ((r = page_insert(e->env_pgdir, p, va, perm)) < 0){ page_free(p); return -E_NO_MEM; } 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. See PTE_SYSCALL in inc/mmu.h. // // 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; int r; if ((r=envid2env(envid,&env,1))<0) return -E_BAD_ENV; if ((uint32_t)va>=UTOP)// || PGOFF(va)!=0) return -E_INVAL; if (!((perm&(PTE_U|PTE_P))==(PTE_U|PTE_P))) return -E_INVAL; struct Page* page; if ((page=page_alloc(ALLOC_ZERO))==NULL) return -E_NO_MEM; if ((r=page_insert(env->env_pgdir,page,va,perm))<0) { page_free(page); return -E_NO_MEM; } return 0; }
// Set envid's env_status to status, which must be ENV_RUNNABLE // or ENV_NOT_RUNNABLE. // // Returns 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 status is not a valid status for an environment. static int sys_env_set_status(envid_t envid, int status) { // Hint: Use the 'envid2env' function from kern/env.c to translate an // envid to a struct Env. // You should set envid2env's third argument to 1, which will // check whether the current environment has permission to set // envid's status. // LAB 4: Your code here. struct Env *e; if(envid2env(envid,&e,1)<0) return -E_BAD_ENV; else { if(status!=ENV_RUNNABLE && status!=ENV_NOT_RUNNABLE) return -E_INVAL; else { e->env_status=status; return 0; } } //panic("sys_env_set_status not implemented"); }
// 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. See PTE_SYSCALL in inc/mmu.h. // // 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. // cprintf("alloc at address:%0x\n", va); 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; if (((perm & PTE_U) == 0) || ((perm & PTE_P) == 0) || ((perm | PTE_SYSCALL) != PTE_SYSCALL)) { return -E_INVAL; } struct PageInfo *pp = page_alloc(ALLOC_ZERO); if (pp == NULL) return -E_NO_MEM; res = page_insert(e->env_pgdir, pp, va, perm); if (res < 0) { page_free(pp); } return res; // panic("sys_page_alloc 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. // panic("sys_ipc_try_send not implemented"); // cprintf("ipc_try_send: %x %x\n",envid,srcva); int r; struct Env* env; if ((r=envid2env(envid,&env,0))<0) return -E_BAD_ENV; if (!env->env_ipc_recving || env->env_ipc_from!=0) return -E_IPC_NOT_RECV; env->env_ipc_perm = 0; if (srcva<(void*)UTOP){ if (ROUNDUP(srcva,PGSIZE)!=srcva && ROUNDDOWN(srcva,PGSIZE)!=srcva) return -E_INVAL; if ((perm&(PTE_P | PTE_U))!=(PTE_P | PTE_U)) return -E_INVAL; pte_t *pte; struct Page* pg; if ((pg=page_lookup(curenv->env_pgdir,srcva,&pte))==0) return -E_INVAL; if (!(*pte & PTE_W) && (perm & PTE_W)) return -E_INVAL; if ((r=page_insert(env->env_pgdir,pg,env->env_ipc_dstva,perm))<0) return r; env->env_ipc_perm = perm; } env->env_ipc_recving = 0; env->env_ipc_from = curenv->env_id; env->env_ipc_value = value; env->env_status = ENV_RUNNABLE; return 0; }
// Set envid's env_status to status, which must be ENV_RUNNABLE // or ENV_NOT_RUNNABLE. // // Returns 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 status is not a valid status for an environment. static int sys_env_set_status(envid_t envid, int status) { // Hint: Use the 'envid2env' function from kern/env.c to translate an // envid to a struct Env. // You should set envid2env's third argument to 1, which will // check whether the current environment has permission to set // envid's status. // LAB 4: Your code here. struct Env *e = NULL; int result = envid2env(envid, &e, 1); if(result){ return result; } if((status != ENV_RUNNABLE) && (status != ENV_NOT_RUNNABLE)){ return -E_INVAL; } e->env_status = status; return result; panic("sys_env_set_status not implemented"); }