static int sys_get_mac(uint32_t *low, uint32_t *high) { user_mem_assert(curenv, low, sizeof(uint32_t), PTE_P | PTE_U); user_mem_assert(curenv, high, sizeof(uint32_t), PTE_P | PTE_U); *low = e100[E1000_RAL/sizeof(uint32_t)]; *high = e100[E1000_RAH/sizeof(uint32_t)] & 0x0000ffff; 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; }
static int sys_net_rx(void * buf) { int result = 0; user_mem_assert(curenv, (const void *)buf, PGSIZE, PTE_U); result = pci_receive_packet(buf); return result; }
static void sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. user_mem_assert(curenv, s, len, 0); cprintf("%.*s", len, s); }
static int sys_net_tx(void * buf, size_t size) { //check for user buffer permissions and address int result = -1; user_mem_assert(curenv, (const void *)buf, size, PTE_U); result = pci_transmit_packet(buf ,size); return result; }
static int sys_receive_packet(void *va) { int pkt_len = 0; user_mem_assert(curenv, va, MAX_ETH_FRAME, PTE_P | PTE_W); pkt_len = nic_e100_recv_pkt(va); return pkt_len; }
// Print a string to the system console. // The string is exactly 'len' characters long. // Destroys the environment on memory errors. static void sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. // LAB 3: Your code here. user_mem_assert(curenv, (void *)s, len, PTE_U|PTE_P); // Print the string supplied by the user. cprintf("%.*s", len, s); }
static void sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. // LAB 3: Your code here. struct Env *e; envid2env(sys_getenvid(), &e, 1); user_mem_assert(e, s, len, PTE_U); // Print the string supplied by the user. cprintf("%.*s", len, s); }
// Print a string to the system console. // The string is exactly 'len' characters long. // Destroys the environment on memory errors. static void sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. // LAB 3: Your code here. //cprintf("curenv env id:%08x,s:%08x,len:%08x\n",curenv->env_id,s,len); user_mem_assert(curenv, s, len, 0); // Print the string supplied by the user. cprintf("%.*s", len, s); }
// Set the page fault upcall for 'envid' by modifying the corresponding struct // Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the // kernel will push a fault record onto the exception stack, then branch to // 'func'. // // 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_pgfault_upcall(envid_t envid, void *func) { // LAB 4: Your code here. struct Env *env; if(envid2env(envid,&env,1) == -E_BAD_ENV) return -E_BAD_ENV; env -> env_pgfault_upcall = func; //cprintf("env_pgfault_upcall:%08x\n",env->env_pgfault_upcall); user_mem_assert(env, (void *)(env->env_pgfault_upcall), 4,0); //cprintf("set pgfault up call successfully\n"); return 0; //panic("sys_env_set_pgfault_upcall not implemented"); }
// 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. static int sys_env_set_trapframe(envid_t envid, struct Trapframe *tf) { struct Env *e; int r; if ((r = envid2env(envid, &e, 1)) < 0) return r; user_mem_assert(e, tf, SIZEOF_STRUCT_TRAPFRAME, 0); spin_lock(&e->env_lock); e->env_tf = *tf; spin_unlock(&e->env_lock); 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 *e; int ret = envid2env(envid, &e, 1); if (ret) return ret; user_mem_assert(e, tf, sizeof(struct Trapframe), PTE_U); e->env_tf = *tf; e->env_tf.tf_eflags = FL_IF|3; e->env_tf.tf_cs = GD_UT|3; return 0; // panic("sys_env_set_trapframe not implemented"); }
static int sys_recv_pkt(void *va, size_t *len) { int r; user_mem_assert(curenv, va, PGSIZE/2, PTE_W | PTE_P | PTE_U); if (!len) return -E_INVAL; if ((r = receive_packet(va, len)) < 0) { curenv->env_e1000_recving = 1; curenv->env_status = ENV_NOT_RUNNABLE; curenv->env_tf.tf_regs.reg_eax = r; sched_yield(); } else { return 0; } }
// Set the page fault upcall for 'envid' by modifying the corresponding struct // Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the // kernel will push a fault record onto the exception stack, then branch to // 'func'. // // 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_pgfault_upcall(envid_t envid, void *func) { // LAB 4: Your code here. struct Env *e; // Envid valid and caller has perms to access it if (envid2env(envid, &e, 1) < 0) { return -E_BAD_ENV; } e->env_pgfault_upcall = func; user_mem_assert(e, func, 4, 0); 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! //panic("sys_env_set_trapframe not implemented"); struct Env *newenv; int ret; if((ret = envid2env(envid, &newenv, 1)) < 0) return ret; user_mem_assert(newenv, tf, sizeof(struct Trapframe), PTE_U); newenv->env_tf = *tf; newenv->env_tf.tf_eflags |= FL_IF; newenv->env_tf.tf_cs = GD_UT | 3; 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; if (envid2env(envid, &env, true) != 0) return -E_BAD_ENV; user_mem_assert(env, tf, sizeof(struct Trapframe), PTE_W); env->env_tf = *tf; env->env_tf.tf_eflags |= FL_IF; return 0; }
// Set the page fault upcall for 'envid' by modifying the corresponding struct // Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the // kernel will push a fault record onto the exception stack, then branch to // 'func'. // // 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_pgfault_upcall(envid_t envid, void *func) { // LAB 4: Your code here. int errno; struct Env *env; if ((errno = envid2env(envid, &env, 1)) < 0) { dbg_print("env 0x%08x does not exist", envid); return errno; } env->env_pgfault_upcall = func; user_mem_assert(env, func, sizeof(func), 0); return 0; //panic("sys_env_set_pgfault_upcall not implemented"); }
// 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 4: Your code here. // Remember to check whether the user has supplied us with a good // address! struct Env *e; int r; if (( r = envid2env(envid, &e, 1)) < 0) return r; user_mem_assert(curenv, (const void *)tf, sizeof(struct Trapframe), 0); tf->tf_eflags |= FL_IF; tf->tf_cs |= 3; e->env_tf = *tf; 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! cprintf("tf value esp-->%x eip %x",tf->tf_esp,tf->tf_eip); user_mem_assert(curenv,(void *)tf,sizeof(tf),0); struct Env *e; if(envid2env(envid,&e,1)<0) return -E_BAD_ENV; e->env_tf=*tf; //e->env_tf.tf_cs=tf->tf_cs|3; e->env_tf.tf_eflags|=FL_IF; e->env_tf.tf_eflags&=~(FL_IOPL_3); cprintf("\nHere inside setting trapframe\n"); return 0; //panic("sys_env_set_trapframe not implemented"); }
// // Transmit packet data pointed to by pkt to the e1000 network controller. // If the e1000 has no more space in the transmission buffer, sys_e1000_transmit // will yield the CPU and try later, much like the loop in ipc_send(). // If after 20 tries the packet cannot be transmitted, return -E_E1000_TXBUF_FULL. // // Returns 0 on succes, -E_BAD_ENV if the envid doesn't exist and -E_E1000_TXBUF_FULL // if after 20 retries the packet still cannot be sent. // static int sys_e1000_transmit(envid_t envid, char *pkt, size_t length) { struct Env *env; if (envid2env(envid, &env, 0) != 0) return -E_BAD_ENV; user_mem_assert(env, pkt, length, PTE_W); int num_tries = 20; while((e1000_transmit(pkt, length) == -1) && (num_tries > 0)) { sys_yield(); num_tries--; } if (num_tries == 0) return -E_E1000_TXBUF_FULL; return 0; }
// Print a string to the system console. // The string is exactly 'len' characters long. // Destroys the environment on memory errors. static void sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. // LAB 3: Your code here. user_mem_assert(curenv, (void *)s, len, PTE_U | PTE_P | PTE_W); pte_t * ptx; uint32_t st = ROUNDDOWN((uint32_t) s,PGSIZE); while(st < (uint32_t)s + len ){ ptx=pgdir_walk(curenv->env_pgdir,(void *)st, 0); if(!ptx || !(*ptx & PTE_P) || !(*ptx & PTE_U) ) env_destroy(curenv); st+=PGSIZE; } // Print the string supplied by the user. cprintf("%.*s", len, s); }
// 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 = NULL; int i; if((i = envid2env(envid,&env,1)) < 0) return i; user_mem_assert(env,tf,sizeof(struct Trapframe), PTE_U); tf->tf_cs |= 0x3; tf->tf_eflags |= FL_IF; env->env_tf = *tf; return 0; //panic("sys_env_set_trapframe not implemented"); }
// Set the page fault upcall for 'envid' by modifying the corresponding struct // Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the // kernel will push a fault record onto the exception stack, then branch to // 'func'. // // 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_pgfault_upcall(envid_t envid, void *func) { // LAB 4: Your code here. struct Env* e; if(envid2env(envid,&e,1) < 0) return -E_BAD_ENV; user_mem_assert(e,(void*)func,sizeof(void *),PTE_U); //return -E_BAD_ENV; if(curenv != e && e -> env_parent_id != curenv->env_id ) return -E_BAD_ENV; e->env_pgfault_upcall = func; // cprintf("in sys_env_set_pgfault_upcall,env %x set pgfault upcall\n",envid); return 0; //panic("sys_env_set_pgfault_upcall not implemented"); }
// 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! //panic("sys_env_set_trapframe not implemented"); struct Env* env; envid2env(envid,&env,1); if(env == NULL) return -E_BAD_ENV; user_mem_assert(env, tf, sizeof(struct Trapframe), PTE_U); tf->tf_ds = GD_UD | 3; tf->tf_es = GD_UD | 3; tf->tf_ss = GD_UD | 3; tf->tf_cs = GD_UT | 3; tf->tf_eflags |= FL_IF; env->env_tf=*tf; return 0; }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs & 3) == 0) { panic("kernel-mode page fault!\n"); } // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack, or the exception stack overflows, // then destroy the environment that caused the fault. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. if (curenv->env_pgfault_upcall != NULL){ struct UTrapframe *utf; if (UXSTACKTOP - PGSIZE <= tf->tf_esp && tf->tf_esp < UXSTACKTOP){ utf = (struct UTrapframe *)(tf->tf_esp - sizeof(struct UTrapframe) - 4); } else { utf = (struct UTrapframe *)(UXSTACKTOP - sizeof(struct UTrapframe)); } user_mem_assert(curenv, (void *)utf, sizeof(struct UTrapframe), PTE_U | PTE_W); utf->utf_eflags = tf->tf_eflags; utf->utf_eip = tf->tf_eip; utf->utf_err = tf->tf_err; utf->utf_esp = tf->tf_esp; utf->utf_fault_va = fault_va; utf->utf_regs = tf->tf_regs; curenv->env_tf.tf_eip = (uint32_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = (uint32_t)utf; env_run(curenv); } // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
void page_fault_handler(struct Trapframe *tf) { // Read processor's CR2 register to find the faulting address int ret; uint32_t fault_va = rcr2(); uint8_t * curr_stack; struct UTrapframe curr_frame; // Handle kernel-mode page faults. //deal with softint in which case error is not pushed to stack if(!(tf->tf_cs & 3)) { print_trapframe(tf); panic("page fault occurs in kernel mode\n"); } if(!curenv->env_pgfault_upcall) goto no_page_fault_handler; // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // Jie's Note : x86 first dec stack pointer and then store the value user_mem_assert(curenv,(void *)(UXSTACKTOP-PGSIZE),PGSIZE,PTE_U|PTE_W|PTE_P); if(tf->tf_esp < USTACKTOP) { curr_stack = (uint8_t *)UXSTACKTOP; } else { curr_stack = (uint8_t *) tf->tf_esp; curr_stack-=sizeof(uint32_t); memset(curr_stack,0,sizeof(uint32_t)); } if((uint32_t)curr_stack <= UXSTACKTOP-PGSIZE+sizeof(struct UTrapframe)+sizeof(uint32_t)) panic("exception stack overflow"); curr_stack-=sizeof(struct UTrapframe); // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. curr_frame.utf_fault_va = fault_va; curr_frame.utf_err = tf->tf_err; curr_frame.utf_eip = tf->tf_eip; curr_frame.utf_esp = tf->tf_esp; curr_frame.utf_eflags = tf->tf_eflags; memcpy(&(curr_frame.utf_regs),&(tf->tf_regs),sizeof(struct PushRegs)); memcpy(curr_stack,&curr_frame,sizeof(struct UTrapframe)); // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. curenv->env_tf.tf_eip = (uintptr_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = (uintptr_t)curr_stack; env_run(curenv); // Destroy the environment that caused the fault. no_page_fault_handler: cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs&3) == 0) panic("Kernel page fault!"); // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. if( curenv->env_pgfault_upcall ) { //cprintf("in trap.c: page_fault_handler\n"); //the curenv->env_pgfault_upcall is set. struct UTrapframe *utf; uintptr_t utf_addr; //check if the tf->tf_esp is on the exception stack if (UXSTACKTOP-PGSIZE<=tf->tf_esp && tf->tf_esp<=UXSTACKTOP-1) utf_addr = tf->tf_esp - sizeof(struct UTrapframe) - 4; else utf_addr = UXSTACKTOP - sizeof(struct UTrapframe); user_mem_assert(curenv, (void*)utf_addr, 1, PTE_W); utf = (struct UTrapframe *) utf_addr; utf->utf_fault_va = fault_va; utf->utf_err = tf->tf_err; utf->utf_regs = tf->tf_regs; utf->utf_eip = tf->tf_eip; utf->utf_eflags = tf->tf_eflags; utf->utf_esp = tf->tf_esp; // curenv->env_tf.env_tf //set the function running curenv->env_tf.tf_eip = (uintptr_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = utf_addr; env_run(curenv); } // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
static int sys_trans_pkt(void *va, size_t len) { user_mem_assert(curenv, va, len, PTE_P | PTE_U); return transmit_packet(va, len); }
// Dispatches to the correct kernel function, passing the arguments. int32_t syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5) { // Call the function corresponding to the 'syscallno' parameter. // Return any appropriate return value. switch(syscallno){ case SYS_cputs: user_mem_assert(curenv, (void *)a1, a2, PTE_U); sys_cputs((char *)a1, a2); return 0; break; case SYS_cgetc: return sys_cgetc(); break; case SYS_getenvid: return sys_getenvid(); break; case SYS_getenv_parent_id: return sys_getenv_parent_id(a1); break; case SYS_env_destroy: return sys_env_destroy(a1); break; case SYS_page_alloc: return sys_page_alloc(a1, (void *)a2, a3); break; case SYS_page_map: return sys_page_map(a1, (void *)a2, a3, (void *)a4, a5); break; case SYS_page_unmap: return sys_page_unmap(a1, (void *)a2); break; case SYS_exofork: return sys_exofork(); break; case SYS_env_set_status: return sys_env_set_status(a1, a2); break; case SYS_env_set_trapframe: return sys_env_set_trapframe(a1, (struct Trapframe *)a2); break; case SYS_env_set_pgfault_upcall: return sys_env_set_pgfault_upcall(a1, (void *)a2); break; case SYS_env_get_curdir: return sys_env_get_curdir((envid_t)a1, (char *)a2); break; case SYS_env_set_curdir: return sys_env_set_curdir((envid_t)a1, (char *)a2); break; case SYS_yield: sys_yield(); break; case SYS_ipc_try_send: return sys_ipc_try_send(a1, a2, (void *)a3, a4); break; case SYS_ipc_recv: return sys_ipc_recv((void *)a1); break; case SYS_time_msec: return sys_time_msec(); break; case SYS_net_send: return sys_net_send((void *)a1, a2); break; case SYS_net_recv: return sys_net_recv((void *)a1, a2); break; case NSYSCALLS: default: return -E_INVAL; break; } return 0; }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; struct PageInfo *pp = NULL; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs & 3) == 0) { panic("page_fault_handler: kernel-mode page fault"); } // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. // utf is a pointer to the UTrapframe in the user exception stack. // If this is the first fault, then the pointer is right below UXSTACKTOP. // Otherwise, the pointer is right below tf->tf_esp, with a 32-bit word offset. // If UXSTACKTOP-PGSIZE <= tf->tf_esp <= UXSTACKTOP-1, then it is a recursive trap, the latter case. struct UTrapframe *utf = (struct UTrapframe *)( (((UXSTACKTOP-PGSIZE)<=(tf->tf_esp))&&((tf->tf_esp)<=(UXSTACKTOP-1))) ? ((tf->tf_esp)-(sizeof(struct UTrapframe)+sizeof(uint32_t))) : (UXSTACKTOP-sizeof(struct UTrapframe)) ); if (!(curenv->env_pgfault_upcall)) { // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); } // If the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // We can do this with user_mem_assert on the portion of the stack where *utf is stored. // This obviously covers the first two cases. // It also takes care of the third case because the region below UXSTACKTOP-PGSIZE is unmapped. user_mem_assert(curenv, (void *)utf, sizeof(struct UTrapframe), PTE_W|PTE_U|PTE_P); utf->utf_fault_va = fault_va; // Copy values from the Trapframe to the UTrapframe. utf->utf_err = tf->tf_err; utf->utf_regs = tf->tf_regs; utf->utf_eip = tf->tf_eip; utf->utf_eflags = tf->tf_eflags; utf->utf_esp = tf->tf_esp; // Set the Trapframe to return to env_pgfault_upcall, with an exception stack at utf. // NOTE I am not confident that this code is correct. // TODO Test that this is correct, and correct it if necessary. tf->tf_eip = (uintptr_t)curenv->env_pgfault_upcall; tf->tf_esp = (uintptr_t)utf; }