intenvid2env(u_int envid, struct Env **penv, int checkperm) { structEnv *e;
/* Step 1: Assign value to 'e' using 'envid'. */ /* Hint: * If envid is zero, set 'penv' to 'curenv' and return 0. * You may want to use 'ENVX'. */ /* Exercise 4.3: Your code here. (1/2) */ if (envid == 0) { *penv = curenv; return0; } e = &envs[ENVX(envid)];
/* Step 2: Check when 'checkperm' is non-zero. */ /* Hints: * Check whether the calling env has sufficient permissions to manipulate the * specified env, i.e. 'e' is either 'curenv' or its immediate child. * If violated, return '-E_BAD_ENV'. */ /* Exercise 4.3: Your code here. (2/2) */ if (checkperm && e != curenv && e->env_parent_id != curenv->env_id) { return -E_BAD_ENV; }
/* Step 1: Check if 'va' is a legal user virtual address using 'is_illegal_va'. */ /* Exercise 4.4: Your code here. (1/3) */
if (is_illegal_va(va)) { return -E_INVAL; }
/* Step 2: Convert the envid to its corresponding 'struct Env *' using 'envid2env'. */ /* Hint: **Always** validate the permission in syscalls! */ /* Exercise 4.4: Your code here. (2/3) */ try(envid2env(envid, &env, 1));
/* Step 3: Allocate a physical page using 'page_alloc'. */ /* Exercise 4.4: Your code here. (3/3) */ try(page_alloc(&pp));
/* Step 4: Map the allocated page at 'va' with permission 'perm' using 'page_insert'. */ return page_insert(env->env_pgdir, env->env_asid, pp, va, perm); }
/* Step 1: Check if 'srcva' and 'dstva' are legal user virtual addresses using * 'is_illegal_va'. */ /* Exercise 4.5: Your code here. (1/4) */
if (is_illegal_va(srcva) || is_illegal_va(dstva)) { return -E_INVAL; }
/* Step 2: Convert the 'srcid' to its corresponding 'struct Env *' using 'envid2env'. */ /* Exercise 4.5: Your code here. (2/4) */ try(envid2env(srcid, &srcenv, 1));
/* Step 3: Convert the 'dstid' to its corresponding 'struct Env *' using 'envid2env'. */ /* Exercise 4.5: Your code here. (3/4) */ try(envid2env(dstid, &dstenv, 1));
/* Step 4: Find the physical page mapped at 'srcva' in the address space of 'srcid'. */ /* Return -E_INVAL if 'srcva' is not mapped. */ /* Exercise 4.5: Your code here. (4/4) */ pp = page_lookup(srcenv->env_pgdir, srcva, NULL); if (pp == NULL) { return -E_INVAL; }
/* Step 5: Map the physical page at 'dstva' in the address space of 'dstid'. */ return page_insert(dstenv->env_pgdir, dstenv->env_asid, pp, dstva, perm); }
/* Step 1: Check if 'va' is a legal user virtual address using 'is_illegal_va'. */ /* Exercise 4.6: Your code here. (1/2) */ if (is_illegal_va(va)) { return -E_INVAL; }
/* Step 2: Convert the envid to its corresponding 'struct Env *' using 'envid2env'. */ /* Exercise 4.6: Your code here. (2/2) */
try(envid2env(envid, &e, 1));
/* Step 3: Unmap the physical page at 'va' in the address space of 'envid'. */ page_remove(e->env_pgdir, e->env_asid, va); return0; }
T7
voidschedule(int yield) 指定yield为1指定切换
1 2 3 4 5
void __attribute__((noreturn)) sys_yield(void) { // Hint: Just use 'schedule' with 'yield' set. /* Exercise 4.7: Your code here. */ schedule(1); }
intsys_ipc_recv(u_int dstva) { /* Step 1: Check if 'dstva' is either zero or a legal address. */ if (dstva != 0 && is_illegal_va(dstva)) { return -E_INVAL; }
/* Step 2: Set 'curenv->env_ipc_recving' to 1. */ /* Exercise 4.8: Your code here. (1/8) */
curenv->env_ipc_recving = 1;
/* Step 3: Set the value of 'curenv->env_ipc_dstva'. */ /* Exercise 4.8: Your code here. (2/8) */
curenv->env_ipc_dstva = dstva;
/* Step 4: Set the status of 'curenv' to 'ENV_NOT_RUNNABLE' and remove it from * 'env_sched_list'. */ /* Exercise 4.8: Your code here. (3/8) */
/* Step 1: Check if 'srcva' is either zero or a legal address. */ /* Exercise 4.8: Your code here. (4/8) */
if (srcva != 0 && is_illegal_va(srcva)) { return -E_INVAL; }
/* Step 2: Convert 'envid' to 'struct Env *e'. */ /* This is the only syscall where the 'envid2env' should be used with 'checkperm' UNSET, * because the target env is not restricted to 'curenv''s children. */ /* Exercise 4.8: Your code here. (5/8) */ try(envid2env(envid, &e, 0));
/* Step 3: Check if the target is waiting for a message. */ /* Exercise 4.8: Your code here. (6/8) */ if (e->env_ipc_recving == 0) { return -E_IPC_NOT_RECV; }
/* Step 5: Set the target's status to 'ENV_RUNNABLE' again and insert it to the tail of * 'env_sched_list'. */ /* Exercise 4.8: Your code here. (7/8) */ e->env_status = ENV_RUNNABLE; TAILQ_INSERT_TAIL(&env_sched_list, e, env_sched_link);
/* Step 6: If 'srcva' is not zero, map the page at 'srcva' in 'curenv' to 'e->env_ipc_dstva' * in 'e'. */ /* Return -E_INVAL if 'srcva' is not zero and not mapped in 'curenv'. */ if (srcva != 0) { /* Exercise 4.8: Your code here. (8/8) */ p = page_lookup(curenv->env_pgdir, srcva, NULL); if (p == NULL) { return -E_INVAL; } try(page_insert(e->env_pgdir, e->env_asid, p, e->env_ipc_dstva, perm)); } return0; }
/* Step 2: If the page is writable, and not shared with children, and not marked as COW yet, * then map it as copy-on-write, both in the parent (0) and the child (envid). */ /* Hint: The page should be first mapped to the child before remapped in the parent. (Why?) */ /* Exercise 4.10: Your code here. (2/2) */ if ((perm & PTE_D) == 0 || (perm & PTE_LIBRARY) || (perm & PTE_COW)) { if ((r = syscall_mem_map(0, (void *)addr, envid, (void *)addr, perm)) < 0) { user_panic("user panic mem map error: %d", r); } } else { if ((r = syscall_mem_map(0, (void *)addr, envid, (void *)addr, (perm & ~PTE_D) | PTE_COW)) < 0) { user_panic("user panic mem map error: %d", r); } if ((r = syscall_mem_map(0, (void *)addr, 0, (void *)addr, (perm & ~PTE_D) | PTE_COW)) < 0) { user_panic("user panic mem map error: %d", r); } } }
/* Step 1: Find the 'perm' in which the faulting address 'va' is mapped. */ /* Hint: Use 'vpt' and 'VPN' to find the page table entry. If the 'perm' doesn't have * 'PTE_COW', launch a 'user_panic'. */ /* Exercise 4.13: Your code here. (1/6) */ perm = PTE_FLAGS(vpt[VPN(va)]); if ((perm & PTE_COW) == 0) { user_panic("PTE_COW not found, va=%08x, perm=%08x", va, perm); }
/* Step 2: Remove 'PTE_COW' from the 'perm', and add 'PTE_D' to it. */ /* Exercise 4.13: Your code here. (2/6) */ perm = (perm & ~PTE_COW) | PTE_D;
/* Step 3: Allocate a new page at 'UCOW'. */ /* Exercise 4.13: Your code here. (3/6) */
syscall_mem_alloc(0, (void *)UCOW, perm);
/* Step 4: Copy the content of the faulting page at 'va' to 'UCOW'. */ /* Hint: 'va' may not be aligned to a page! */ /* Exercise 4.13: Your code here. (4/6) */
/* Step 1: Set our TLB Mod user exception entry to 'cow_entry' if not done yet. */ if (env->env_user_tlb_mod_entry != (u_int)cow_entry) { try(syscall_set_tlb_mod_entry(0, cow_entry)); }
/* Step 2: Create a child env that's not ready to be scheduled. */ // Hint: 'env' should always point to the current env itself, so we should fix it to the // correct value. child = syscall_exofork(); if (child == 0) { env = envs + ENVX(syscall_getenvid()); return0; }
/* Step 3: Map all mapped pages below 'USTACKTOP' into the child's address space. */ // Hint: You should use 'duppage'. /* Exercise 4.15: Your code here. (1/2) */ for (i = 0; i < PDX(UXSTACKTOP); i++) { if (vpd[i] & PTE_V) { for (u_int j = 0; j < PAGE_SIZE / sizeof(Pte); j++) { u_long va = (i * (PAGE_SIZE / sizeof(Pte)) + j) << PGSHIFT; if (va >= USTACKTOP) { break; } if (vpt[VPN(va)] & PTE_V) { duppage(child, VPN(va)); } } } }
/* Step 4: Set up the child's tlb mod handler and set child's 'env_status' to * 'ENV_RUNNABLE'. */ /* Hint: * You may use 'syscall_set_tlb_mod_entry' and 'syscall_set_env_status' * Child's TLB Mod user exception entry should handle COW, so set it to 'cow_entry' */ /* Exercise 4.15: Your code here. (2/2) */ syscall_set_tlb_mod_entry(child, cow_entry); syscall_set_env_status(child, ENV_RUNNABLE);