// Challenge! int sfork(void) { int r; pde_t *pde; pte_t *pte; unsigned i; uint32_t addr; envid_t envid; envid = sys_exofork();//创建子环境 if(envid < 0) panic("sys_exofork: %e", envid); if(envid==0)//子环境中 { env = &envs[ENVX(sys_getenvid())]; return 0; } else{//父环境中,注意:这里需要设置父环境的缺页异常栈,还需要设置子环境的缺页异常栈, //父子环境的页异常栈不共享?具体原因还得思考 env = &envs[ENVX(sys_getenvid())]; set_pgfault_handler(pgfault);//设置缺页异常处理函数,这里设置了父环境的缺页异常栈 for(i=0;i<(unsigned)VPN(UTOP);i++)//重映射writable or copy-to-write的页面 { addr=i*PGSIZE; pde =(pde_t*) &vpd[VPD(addr)]; if(*pde&PTE_P)//这里只处理有物理页面映射的页表项 { pte=(pte_t*)&vpt[VPN(addr)]; } else continue; if((i==(unsigned)VPN(USTACKTOP-PGSIZE))||(i==(unsigned)VPN(PFTEMP))) //特殊处理,用户层普通栈 { if((r=duppage(envid,i))<0) return r; continue; } if((r=sduppage(envid,i))<0) return r; } if((r=sys_page_alloc(envid,(void*)(UXSTACKTOP-PGSIZE),PTE_W|PTE_U|PTE_P))<0) return r;//设置子环境的缺页异常栈 if((r=sys_env_set_pgfault_upcall(envid,(void*)_pgfault_upcall))<0) return r;//设置子环境的缺页异常处理入口点 if((r=sys_env_set_status(envid,ENV_RUNNABLE))<0) return r;//设置子环境的状态为可运行 return envid; } //panic("sfork not implemented"); //return -E_INVAL; }
envid_t dumbfork(void) { envid_t envid; uint8_t *addr; int r; extern unsigned char end[]; // Allocate a new child environment. // The kernel will initialize it with a copy of our register state, // so that the child will appear to have called sys_exofork() too - // except that in the child, this "fake" call to sys_exofork() // will return 0 instead of the envid of the child. envid = sys_exofork(); if (envid < 0) panic("sys_exofork: %e", envid); if (envid == 0) { // We're the child. // The copied value of the global variable 'thisenv' // is no longer valid (it refers to the parent!). // Fix it and return 0. cprintf("I am the child \n"); thisenv = &envs[ENVX(sys_getenvid())]; return 0; } // We're the parent. // Eagerly copy our entire address space into the child. // This is NOT what you should do in your fork implementation. /* balvisio: * 'end' is a magic symbol automatically generated by the linker, * which points to the end of the dumbfork bss segment. * the first virtual address that the linker did *not* assign * to any code or global variables. (balvisio: Not sure though * need to confirm. In dumbfork it is 0x802008) */ for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE) duppage(envid, addr); // Also copy the stack we are currently running on. duppage(envid, ROUNDDOWN(&addr, PGSIZE)); // Start the child environment running if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0) panic("sys_env_set_status: %e", r); return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. set_pgfault_handler(pgfault); int r, childid; childid = sys_exofork(); if (childid <0) panic("exofork error in fork()!\n"); else if (childid ==0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } else { int addr; for (addr = UTEXT; addr<UXSTACKTOP-PGSIZE; addr+=PGSIZE) { int pn = PGNUM(addr); if (((uvpd[PDX(addr)] & PTE_P) >0) && ((uvpt[pn] & PTE_P) >0) && ((uvpt[pn] & PTE_U) > 0)) duppage(childid, pn); } extern void _pgfault_upcall(); sys_page_alloc(childid, (void*) (UXSTACKTOP - PGSIZE), PTE_U|PTE_W|PTE_P); sys_env_set_pgfault_upcall(childid, _pgfault_upcall); sys_env_set_status(childid, ENV_RUNNABLE); return childid; } }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. envid_t envid; uint64_t addr; uint32_t err; extern unsigned char end[]; int r; set_pgfault_handler(pgfault); envid = sys_exofork(); if (envid < 0) panic("sys_exofork: %e", envid); if (envid == 0) { // We're the child. // The copied value of the global variable 'thisenv' // is no longer valid (it refers to the parent!). // Fix it and return 0. thisenv = &envs[ENVX(sys_getenvid())]; return 0; } //Allocate exception stack for the child if ((err = sys_page_alloc(envid, (void *) (UXSTACKTOP - PGSIZE), PTE_P|PTE_U|PTE_W)) < 0) panic("Error in sys_page_alloc: %e", err); // We're the parent. // Map our entire address space into the child. for (addr = UTEXT; addr < USTACKTOP-PGSIZE; addr += PGSIZE) { if((vpml4e[VPML4E(addr)] & PTE_P) && (vpde[VPDPE(addr)] & PTE_P) && (vpd[VPD(addr)] & PTE_P) && (vpt[VPN(addr)] & PTE_P)) { duppage(envid, VPN(addr)); } } //Allocate a new stack for the child and copy the contents of parent on to it. addr = USTACKTOP-PGSIZE; if ((r = sys_page_alloc(0, (void *)PFTEMP, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc failed: %e\n", r); memcpy(PFTEMP, (void *) ROUNDDOWN(addr, PGSIZE), PGSIZE); void *vaTemp = (void *) ROUNDDOWN(addr, PGSIZE); if ((r = sys_page_map(0, (void *)PFTEMP, envid, vaTemp, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_map failed: %e\n", r); if ((r = sys_page_unmap(0, (void *)PFTEMP)) < 0) panic("sys_page_unmap failed: %e\n", r); //Set child's page fault handler if ((err = sys_env_set_pgfault_upcall(envid, _pgfault_upcall) < 0)) panic("Error in sys_env_set_pgfault_upcall: %e",err); //Set the child ready to run if ((err = sys_env_set_status(envid, ENV_RUNNABLE)) < 0) panic("sys_env_set_status: %e", err); return envid; panic("fork not implemented"); }
// Copy the mappings for shared pages into the child address space. static int copy_shared_pages(envid_t child) { // LAB 7: Your code here. int dir_index = 0 ; int i = 0 ; int pn; for ( dir_index = 0 ; dir_index < PDX(UTOP) ; dir_index++ ) { //check if vpd[dir-index] is present if( vpd[dir_index] & PTE_P ) { for(i=0;i< NPTENTRIES;i++) { pn = dir_index * NPTENTRIES + i ; duppage(child,pn ); } } } return 0; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { extern void _pgfault_upcall(); // LAB 4: Your code here. set_pgfault_handler(pgfault); envid_t envid = sys_exofork(); if (envid == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } if (envid < 0) { panic("sys_exofork failed: %e", envid); } uint32_t addr; for (addr = 0; addr < USTACKTOP; addr += PGSIZE) { if ((uvpd[PDX(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_U)) { duppage(envid, PGNUM(addr)); } } int alloc_err = sys_page_alloc(envid, (void *)(UXSTACKTOP-PGSIZE), PTE_U|PTE_W|PTE_P); if (alloc_err) { panic("sys_page_alloc failed with error: %e", alloc_err); } sys_env_set_pgfault_upcall(envid, _pgfault_upcall); int set_status_err = sys_env_set_status(envid, ENV_RUNNABLE); if (set_status_err) { panic("sys_env_set_status"); } return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. set_pgfault_handler (pgfault); envid_t envid; uint32_t addr; int r; envid = sys_exofork(); if (envid < 0) panic("sys_exofork: %e", envid); // We’re the child if (envid == 0) { env = &envs[ENVX(sys_getenvid())]; return 0; } // We’re the parent. for (addr = UTEXT; addr < UXSTACKTOP - PGSIZE; addr += PGSIZE) { if ((vpd[VPD(addr)] & PTE_P) > 0 && (vpt[VPN(addr)] & PTE_P) > 0 && (vpt[ VPN(addr)] & PTE_U) > 0) duppage (envid, VPN(addr)); } if ((r = sys_page_alloc (envid, (void *)(UXSTACKTOP - PGSIZE), PTE_U|PTE_W|PTE_P)) < 0) panic ("fork: page allocation failed : %e", r); extern void _pgfault_upcall (void); sys_env_set_pgfault_upcall (envid, _pgfault_upcall); // Start the child environment running if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0) panic("fork: set child env status failed : %e", r); return envid; //panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. //panic("fork not implemented"); void *addr; set_pgfault_handler(pgfault); envid_t forkid = sys_exofork(); if (forkid < 0) panic("sys_exofork: %e", forkid); if(forkid == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } for (addr = (uint8_t*) UTEXT; addr < (void *) USTACKTOP; addr += PGSIZE) if( (uvpd[PDX(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_P) ) duppage(forkid, PGNUM(addr)); if (sys_page_alloc(forkid, (void *)(UXSTACKTOP-PGSIZE), PTE_U|PTE_W|PTE_P) < 0) panic("user stack alloc failure\n"); extern void _pgfault_upcall(); if(sys_env_set_pgfault_upcall(forkid, _pgfault_upcall) < 0) panic("set pgfault upcall fails %d\n", forkid); if(sys_env_set_status(forkid, ENV_RUNNABLE) < 0) panic("set %d runnable fails\n", forkid); return forkid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. //panic("fork not implemented"); extern void _pgfault_upcall(void); set_pgfault_handler(pgfault); envid_t id = sys_exofork(); int r; if (id < 0) panic("exofork: child"); if (id == 0) { thisenv = envs + ENVX(sys_getenvid()); return 0; } // cprintf("fork id: %x",id); if ((r=sys_page_alloc(id, (void*)(UXSTACKTOP-PGSIZE), PTE_U | PTE_W | PTE_P))<0) return r; int i; for (i=0;i<UTOP-PGSIZE;i+=PGSIZE) if ((vpd[PDX(i)] & PTE_P) && (vpt[PGNUM(i)] & PTE_P)) { // cprintf("i:%x ",i); if ((r=duppage(id,PGNUM(i)))<0) return r; } if ((r=sys_env_set_pgfault_upcall(id,(void*)_pgfault_upcall))<0) return r; if ((r=sys_env_set_status(id, ENV_RUNNABLE))<0) return r; return id; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. int r; envid_t envid; set_pgfault_handler(pgfault); if((envid = sys_exofork())<0) panic("sys_exofork error: %e\n",envid); if(envid == 0){ thisenv = &envs[ENVX(sys_getenvid())]; return 0; } uint32_t vaddr; extern unsigned char end[]; for (vaddr = 0 ; vaddr < UTOP; vaddr += PGSIZE ){ //Check sequentially if ((vpml4e[VPML4E(vaddr)] & PTE_P ) && (vpde[VPDPE(vaddr)] & PTE_P ) && (vpd[VPD(vaddr)] & PTE_P ) && (vpt[VPN(vaddr)] & PTE_P)){ //Order is imp... if ((vaddr != (UXSTACKTOP - PGSIZE)) && (vaddr != (USTACKTOP - PGSIZE))){ duppage(envid, (uint64_t)vaddr / PGSIZE); } } } if ((r = sys_page_alloc(envid,(void*)(USTACKTOP - PGSIZE), PTE_U | PTE_W | PTE_P ))<0){ panic("error from sys_page_alloc: %e\n", r); } else { if ((r = sys_page_alloc(0, PFTEMP, PTE_U|PTE_W|PTE_P)) < 0) panic("error from sys_page_alloc: %e", r); memmove(PFTEMP, (void *)(USTACKTOP - PGSIZE), PGSIZE); if ((r = sys_page_map(0,PFTEMP, envid, (void *)(USTACKTOP - PGSIZE) , PTE_U|PTE_W|PTE_P)) < 0) panic("error from sys_page_map: %e", r); } if((r = sys_page_alloc(envid,(void*)(UXSTACKTOP - PGSIZE), PTE_U | PTE_W | PTE_P ))<0) panic("error from sys_page_alloc : %e\n",r); if((r=sys_env_set_pgfault_upcall(envid, thisenv->env_pgfault_upcall))!=0) panic("error from sys_env_set_pgfault_upcall : %e\n",r); if((r = sys_env_set_status(envid, ENV_RUNNABLE))<0) panic("error from sys_env_set_status : %e\n",r); return envid; }
envid_t dumbfork(void) { envid_t envid; uint8_t *addr; int r; extern unsigned char end[]; // Allocate a new child environment. // The kernel will initialize it with a copy of our register state, // so that the child will appear to have called sys_exofork() too - // except that in the child, this "fake" call to sys_exofork() // will return 0 instead of the envid of the child. envid = sys_exofork(); if (envid < 0) { panic("sys_exofork: %e", envid); } if (envid == 0) { // We're the child. // The copied value of the global variable 'env' // is no longer valid (it refers to the parent!). // Fix it and return 0. env = &envs[ENVX(sys_getenvid())]; return 0; } // We're the parent. // Eagerly copy our entire address space into the child. // This is NOT what you should do in your fork implementationp. for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE) duppage(envid, addr); // Also copy the stack we are currently running on. duppage(envid, ROUNDDOWN(&addr, PGSIZE)); // Start the child environment running if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0) { panic("sys_env_set_status: %e", r); } return envid; }
// The parent installs pgfault() as the C-level page fault handler, using the set_pgfault_handler() function you implemented above. // The parent calls sys_exofork() to create a child environment. // For each writable or copy-on-write page in its address space below UTOP, the parent calls duppage, which should map the page copy-on-write into the address space of the child and then remap the page copy-on-write in its own address space. duppage sets both PTEs so that the page is not writeable, and to contain PTE_COW in the "avail" field to distinguish copy-on-write pages from genuine read-only pages. // The exception stack is not remapped this way, however. Instead you need to allocate a fresh page in the child for the exception stack. // Since the page fault handler will be doing the actual copying and the page fault handler runs on the exception stack, the exception stack cannot be made copy-on-write: who would copy it? // fork() also needs to handle pages that are present, but not writable or copy-on-write. // The parent sets the user page fault entrypoint for the child to look like its own. // The child is now ready to run, so the parent marks it runnable. // // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. set_pgfault_handler(pgfault); envid_t eid = sys_exofork(); if(eid < 0) // error panic("couldn't fork child. %e",eid); else if(eid == 0) { // child thisenv = envs+ENVX(sys_getenvid()); return 0; } else { //parent uint64_t r; for (r = 0; r < (uint64_t)(UXSTACKTOP-PGSIZE); r += PGSIZE) { if( (vpml4e[VPML4E(r)] & PTE_P) && (vpde[VPDPE(r)] & PTE_P) && (vpd[VPD(r)] & PTE_P) && (vpt[VPN(r)] & PTE_P)) { duppage(eid, VPN(r)); } } //Duppage the stack for the child duppage(eid, VPN(USTACKTOP-PGSIZE)); // Instead you need to allocate a fresh page in the child for the exception stack if((r= sys_page_alloc(eid, (void *)(UXSTACKTOP-PGSIZE), PTE_U|PTE_P|PTE_W)) < 0) panic("fork failed setting UXSTACK for child %e", r); //The parent sets the user page fault entrypoint for the child to look like its own. if((r= sys_env_set_pgfault_upcall(eid, thisenv->env_pgfault_upcall)) < 0) // panic("fork failed setting pgfault handler %e", r); //The child is now ready to run, so the parent marks it runnable. if((r= sys_env_set_status(eid, ENV_RUNNABLE)) < 0) panic("fork failed setting status %e", r); //cprintf("forked the child\n"); return eid; } //panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. //panic("fork not implemented"); envid_t envid=-1; pte_t ptentry=0, ptable=0, page_num=0; pde_t pdentry=0; uintptr_t addr=0; int pdindex = 0, pte_perm=0, pte_loop=0; int r=-1; //cprintf("\nin fork envid:%x\n", thisenv->env_id); set_pgfault_handler(pgfault); if((envid=sys_exofork())<0) panic("\nCannot create a child process:%e\n",envid); //cprintf("\nenvid of newly created child:%x\n",envid); if (envid == 0) { // We're the child. // The copied value of the global variable 'thisenv' // is no longer valid (it refers to the parent!). // Fix it and return 0. thisenv = &envs[ENVX(sys_getenvid())]; //set_pgfault_handler(pgfault); return 0; } //Incrementing by PGSIZE in loop because 1 page of pgsize corresponds to 1 page taable entry //Incrementing the address by 4MB because uvpd has no entry means 1 uvpd->4 MB region so need to skip it. while(addr<(UXSTACKTOP-PGSIZE)) { //cprintf("parent address:%x",addr); if(uvpd[PDX(addr)] & PTE_P) { if(uvpt[PGNUM(addr)] & PTE_P) { //cprintf("\ncalling duppgae for address %x\n",addr); duppage(envid, PGNUM(addr)); } addr += PGSIZE; } else { addr = addr + PTSIZE; } } if ((r = sys_page_alloc(envid,(void *)UXSTACKTOP-PGSIZE, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc: %e", r); if ((r = sys_env_set_pgfault_upcall(envid, _pgfault_upcall)) < 0) panic("pagefault upcall setup error: %e", r); sys_env_set_status(envid, ENV_RUNNABLE); //cprintf("\n fork exiting - envid:%x\n",thisenv->env_id); return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "env" and the user exception stack in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. // Assembly language pgfault entrypoint defined in lib/pgfaultentry.S. extern void _pgfault_upcall(void); envid_t chenvid; void *addr; void *addr2; unsigned pn; pte_t pte, pde; int count, r, entries; set_pgfault_handler(pgfault); if ( (chenvid = sys_exofork()) < 0) panic("fork() - no free env!"); else if (chenvid == 0){ //we are in child - ren env = &envs[ENVX(sys_getenvid())]; return 0; } //we are in parent - ren //copy mappings - ren entries = NPDENTRIES; for(addr = 0; entries--; addr+=NPTENTRIES*PGSIZE){ //walk through page directory - ren pde = vpd[PDX(addr)]; if (pde & PTE_P) { //walk through page table - ren for(addr2 = addr, count = NPTENTRIES; ((uintptr_t)addr2 < (uintptr_t)UTOP - PGSIZE) && (count); addr2+=PGSIZE, count--){ pte = vpt[VPN(addr2)]; if (pte & PTE_P){ duppage(chenvid, (uintptr_t)addr2/PGSIZE); } } if (count) break; //reached exception stack - ren } } if( (r = sys_page_alloc(chenvid, (void *) UXSTACKTOP-PGSIZE, PTE_U | PTE_P | PTE_W)) < 0) panic("fork() - could not allocate exception stack for the child!"); if( (r = sys_env_set_pgfault_upcall(chenvid, (void *) _pgfault_upcall)) < 0) panic("fork() - could not set page fault entrypoint for the child!"); if( (r = sys_env_set_status(chenvid, ENV_RUNNABLE)) < 0) panic("fork() - could not set child ENV_RUNNABLE!"); return chenvid; }
envid_t fork(void) { // LAB 4: Your code here. // seanyliu int r; int pdidx = 0; int peidx = 0; envid_t childid; set_pgfault_handler(pgfault); // create child environment childid = sys_exofork(); if (childid < 0) { panic("fork: failed to create child %d", childid); } if (childid == 0) { env = &envs[ENVX(sys_getenvid())]; return 0; } // loop through pg dir, avoid user exception stack (which is immediately below UTOP for (pdidx = 0; pdidx < PDX(UTOP); pdidx++) { // check if the pg is present if (!(vpd[pdidx] & PTE_P)) continue; // loop through pg table entries for (peidx = 0; (peidx < NPTENTRIES) && (pdidx*NPDENTRIES+peidx < (UXSTACKTOP - PGSIZE)/PGSIZE); peidx++) { if (vpt[pdidx * NPTENTRIES + peidx] & PTE_P) { if ((r = duppage(childid, pdidx * NPTENTRIES + peidx)) < 0) { panic("fork: duppage failed: %d", r); } } } } // allocate fresh page in the child for exception stack. if ((r = sys_page_alloc(childid, (void *)(UXSTACKTOP - PGSIZE), PTE_U | PTE_P | PTE_W)) < 0) { panic("fork: %d", r); } // parent sets the user page fault entrypoint for the child to look like its own. if ((r = sys_env_set_pgfault_upcall(childid, env->env_pgfault_upcall)) < 0) { panic("fork: %d", r); } // parent marks child runnable if ((r = sys_env_set_status(childid, ENV_RUNNABLE)) < 0) { panic("fork: %d", r); } return childid; //panic("fork not implemented"); }
int dumbfork(void) { int addr, envid, r; extern u_char end[]; // Allocate a new child environment. // The kernel will initialize it with a copy of our register state, // so that the child will appear to have called sys_env_alloc() too - // except that in the child, this "fake" call to sys_env_alloc() // will return 0 instead of the envid of the child. envid = sys_env_alloc(); if (envid < 0) panic("sys_env_fork: %e", envid); if (envid == 0) { // We're the child. // The copied value of the global variable 'env' // is no longer valid (it refers to the parent!). // Fix it and return 0. env = &envs[ENVX(sys_getenvid())]; return 0; } // We're the parent. // Eagerly copy our entire address space into the child. // This is NOT what you should do in your fork implementation. for (addr=UTEXT; addr<(u_int)end; addr+=BY2PG) duppage(envid, addr); // Also copy the stack we are currently running on. duppage(envid, ROUNDDOWN((u_int)&addr, BY2PG)); // Start the child environment running // (at the point above where the register state was copied). if ((r=sys_set_status(envid, ENV_RUNNABLE)) < 0) panic("sys_set_status: %e", r); return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // Step 1: install user mode pgfault handler. set_pgfault_handler(pgfault); // Step 2: create child environment. envid_t envid = sys_exofork(); if (envid < 0) { panic("fork: cannot create child env"); } else if (envid == 0) { // child environment. thisenv = &envs[ENVX(sys_getenvid())]; return 0; } // Step 3: duplicate pages. int ipd; for (ipd = 0; ipd < PDX(UTOP); ipd++) { // No page table yet. if (!(uvpd[ipd] & PTE_P)) continue; int ipt; for (ipt = 0; ipt < NPTENTRIES; ipt++) { unsigned pn = (ipd << 10) | ipt; if (pn != PGNUM(UXSTACKTOP - PGSIZE)) { duppage(envid, pn); } } } // allocate a new page for child to hold the exception stack. if (sys_page_alloc(envid, (void *)(UXSTACKTOP - PGSIZE), PTE_W | PTE_U | PTE_P)) { panic("fork: no phys mem for xstk"); } // Step 4: set user page fault entry for child. if (sys_env_set_pgfault_upcall(envid, thisenv->env_pgfault_upcall)) { panic("fork: cannot set pgfault upcall"); } // Step 5: set child status to ENV_RUNNABLE. if (sys_env_set_status(envid, ENV_RUNNABLE)) { panic("fork: cannot set env status"); } return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. set_pgfault_handler(pgfault); envid_t childid = sys_exofork(); if(childid < 0) panic("Fork Failed\n"); if(childid == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } int i, j; for(i = 0; i < PDX(UTOP); i++) { if (!(uvpd[i] & PTE_P)) continue; for(j = 0; (j < 1024) && (i*NPDENTRIES + j < PGNUM(UXSTACKTOP - PGSIZE)); j++ ) { if(!uvpt[i*NPDENTRIES + j] & PTE_P) continue; if(duppage(childid, i*NPDENTRIES + j) < 0) panic("dup page failed"); } } if ((sys_page_alloc(childid, (void *)(UXSTACKTOP - PGSIZE), PTE_U | PTE_P | PTE_W)) < 0) { panic("Allocation of page for Exception stack cups!\n"); } if ((sys_env_set_pgfault_upcall(childid, thisenv->env_pgfault_upcall)) < 0) { panic("Unable to set child process' upcall"); } // Copy own uxstack to temp page memmove((void *)(UXSTACKTOP - PGSIZE), PFTEMP, PGSIZE); int r; // Unmap temp page if (sys_page_unmap(sys_getenvid(), PFTEMP) < 0) { return -1; } if ((r = sys_env_set_pgfault_upcall(childid, thisenv->env_pgfault_upcall)) < 0) panic("sys_env_set_pgfault_upcall: error %e\n", r); if ((r = sys_env_set_status(childid, ENV_RUNNABLE)) < 0) { cprintf("sys_env_set_status: error %e\n", r); return -1; } return childid; panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. int r; envid_t child_envid; set_pgfault_handler(pgfault); child_envid = sys_exofork(); if (child_envid < 0) panic("sys_exofork: %e\n", child_envid); if (child_envid == 0) { // child // Fix thisenv like dumbfork does and return 0 thisenv = &envs[ENVX(sys_getenvid())]; return 0; } // We're in the parent // Iterate over all pages until UTOP. Map all pages that are present // and let duppage worry about the permissions. // Note that we don't remap anything above UTOP because the kernel took // care of that for us in env_setup_vm(). uint32_t page_num; pte_t *pte; for (page_num = 0; page_num < PGNUM(UTOP - PGSIZE); page_num++) { uint32_t pdx = ROUNDDOWN(page_num, NPDENTRIES) / NPDENTRIES; if ((uvpd[pdx] & PTE_P) == PTE_P && ((uvpt[page_num] & PTE_P) == PTE_P)) { duppage(child_envid, page_num); } } // Allocate exception stack space for child. The child can't do this themselves // because the mechanism by which it would is to run the pgfault handler, which // needs to run on the exception stack (catch 22). if ((r = sys_page_alloc(child_envid, (void *) (UXSTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) panic("sys_page_alloc: %e\n", r); // Set page fault handler for the child if ((r = sys_env_set_pgfault_upcall(child_envid, _pgfault_upcall)) < 0) panic("sys_env_set_pgfault_upcall: %e\n", r); // Mark child environment as runnable if ((r = sys_env_set_status(child_envid, ENV_RUNNABLE)) < 0) panic("sys_env_set_status: %e\n", r); return child_envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "env" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. int r; pde_t *pde; pte_t *pte; unsigned i; uint32_t addr; envid_t envid; envid = sys_exofork();//创建子环境 if(envid < 0) panic("sys_exofork: %e", envid); if(envid==0)//子环境中 { env = &envs[ENVX(sys_getenvid())]; return 0; } else{//父环境中 set_pgfault_handler(pgfault);//设置缺页异常处理函数,这里设置了父环境的缺页异常栈 for(i=0;i<(unsigned)VPN(UTOP);i++)//重映射writable or copy-to-write的页面 { if(i==(unsigned)VPN(UXSTACKTOP-PGSIZE))//特殊处理,用户层缺页异常栈 continue; addr=i*PGSIZE; pde =(pde_t*) &vpd[VPD(addr)]; if(*pde&PTE_P)//这里只处理有物理页面映射的页表项 { pte=(pte_t*)&vpt[VPN(addr)]; } else continue; if((*pte&PTE_W)||(*pte&PTE_COW)) { if((r=duppage(envid,i))<0) return r; } } if((r=sys_page_alloc(envid,(void*)(UXSTACKTOP-PGSIZE),PTE_W|PTE_U|PTE_P))<0) return r;//设置子环境的缺页异常栈 if((r=sys_env_set_pgfault_upcall(envid,(void*)_pgfault_upcall))<0) return r;//设置子环境的缺页异常处理入口点 if((r=sys_env_set_status(envid,ENV_RUNNABLE))<0) return r;//设置子环境的状态为可运行 return envid; } //panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: our code here. // static int pri = 10000; cprintf("fork start\n"); set_pgfault_handler(pgfault); int envid = sys_exofork(); if (envid < 0) { panic("sys_exofork: %e", envid); } int r; if (envid == 0) { // cprintf("child\n"); thisenv = &envs[ENVX(sys_getenvid())]; return 0; } else { // cprintf("father\n"); uint32_t i; for (i = 0; i != UTOP; i += PGSIZE) if ((uvpd[PDX(i)] & PTE_P) && (uvpt[i / PGSIZE] & PTE_P) && (uvpt[i / PGSIZE] & PTE_U)) { //cprintf("%d\n", uvpd[PDX(i)] & PTE_P); duppage(envid, i / PGSIZE); } // cprintf("father1\n"); r = sys_page_alloc(envid, (void *)(UXSTACKTOP - PGSIZE), PTE_U |PTE_W | PTE_P); if (r < 0) panic("sys_page_alloc: %e", r); extern void _pgfault_upcall(void); r = sys_env_set_pgfault_upcall(envid, _pgfault_upcall); if (r < 0) panic("set pgfault upcall fail : %e", r); // pri--; // sys_change_priority(envid, pri); r = sys_env_set_status(envid, ENV_RUNNABLE); if (r < 0) panic("set child process to ENV_RUNNABLE error : %e", r); return envid; } panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. //------------ Lab4 ---------------------------------------------------------------------------------------- set_pgfault_handler(pgfault); envid_t pid = sys_exofork(); //cprintf("pid: %x\n", pid); if (pid < 0) panic("sys_exofork failed in fork %e\n", pid); //cprintf("fork point2!\n"); if (pid == 0) { //cprintf("child forked!\n"); thisenv = &envs[ENVX(sys_getenvid())]; //cprintf("child fork ok!\n"); return 0; } uint32_t i; for (i = 0; i < UTOP; i += PGSIZE){ if ( (uvpd[PDX(i)] & PTE_P) && (uvpt[i / PGSIZE] & PTE_P) && (uvpt[i / PGSIZE] & PTE_U) ) duppage(pid, i / PGSIZE); } int res; res = sys_page_alloc(pid, (void *)(UXSTACKTOP - PGSIZE), PTE_U | PTE_W | PTE_P); if (res < 0) panic("sys_page_alloc failed in fork %e\n", res); extern void _pgfault_upcall(void); res = sys_env_set_pgfault_upcall(pid, _pgfault_upcall); if (res < 0) panic("sys_env_set_pgfault_upcall failed in fork %e\n", res); res = sys_env_set_status(pid, ENV_RUNNABLE); if (res < 0) panic("sys_env_set_status failed in fork %e\n", res); return pid; //------------ Lab4 ---------------------------------------------------------------------------------------- //panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. envid_t envidnum; uint32_t addr; int r; extern void _pgfault_upcall(void); set_pgfault_handler(pgfault); envidnum = sys_exofork(); if (envidnum < 0) panic("sys_exofork: %e", envidnum); // We’re the child if (envidnum == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } // We’re the parent. for (addr = UTEXT; addr < UXSTACKTOP - PGSIZE; addr += PGSIZE) { if( (vpd[PDX(addr)] & PTE_P) > 0 && (vpt[PGNUM(addr)] & PTE_P) > 0 && (vpt[PGNUM(addr)] & PTE_U) > 0) duppage(envidnum,PGNUM(addr)); } if ((r = sys_page_alloc (envidnum, (void *)(UXSTACKTOP - PGSIZE), PTE_U|PTE_W|PTE_P)) < 0) panic ("fork: page allocation failed : %e", r); //cprintf("%x-----%x\n",&envid,envid); sys_env_set_pgfault_upcall (envidnum, _pgfault_upcall); //cprintf("%x-----%x\n",&envid,envid); // Start the child environment running if((r = sys_env_set_status(envidnum, ENV_RUNNABLE)) < 0) panic("fork: set child env status failed : %e", r); //cprintf("%x-----%x\n",&envid,envid); //cprintf("fork in %x have set %x ,runnable\n",sys_getenvid(),envidnum); //cprintf("fork in %x have set %x ,runnable\n",sys_getenvid(),envidnum); //cprintf("%x-----%x\n",&envidnum,envidnum); return envidnum; //panic("fork not implemented"); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { envid_t envid; uint8_t *addr; uintptr_t va; int r; // LAB 4: Your code here. set_pgfault_handler(pgfault); envid = sys_exofork(); if (envid < 0) { panic("sys_exofork: %d", envid); } if (envid == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } // We are parent for(va = UTEXT; va < UTOP - PGSIZE; va += PGSIZE) { if ((uvpd[PDX(va)] & PTE_P) && (uvpt[PGNUM(va)] & PTE_P) && (uvpt[PGNUM(va)] & PTE_U)) { if ((r = duppage(envid, PGNUM(va))) < 0) return r; } } // The user exception stack page if ((r = sys_page_alloc(envid, (void*)(UXSTACKTOP-PGSIZE), PTE_P|PTE_U|PTE_W) < 0)) { panic("fork: sys_page_alloc: %e", r); } // Done mapping pages sys_env_set_pgfault_upcall(envid, thisenv->env_pgfault_upcall); sys_env_set_status(envid, ENV_RUNNABLE); return envid; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. set_pgfault_handler(pgfault); envid_t envid; uint32_t addr; envid = sys_exofork(); if (envid == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; } if (envid < 0) panic("sys_exofork: %e", envid); for (addr = 0; addr < USTACKTOP; addr += PGSIZE) if ((uvpd[PDX(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_P)&& (uvpt[PGNUM(addr)] & PTE_U)) { duppage(envid, PGNUM(addr)); } if (sys_page_alloc(envid, (void *)(UXSTACKTOP-PGSIZE), PTE_U|PTE_W|PTE_P) < 0) panic("in fork: sys_page_alloc wrong!"); extern void _pgfault_upcall(); sys_env_set_pgfault_upcall(envid, _pgfault_upcall); if (sys_env_set_status(envid, ENV_RUNNABLE) < 0) panic("sys_env_set_status"); return envid; //panic("fork not implemented"); }
int fixfault(Segment *s, uintptr addr, int read, int doputmmu) { int type; int ref; Pte **p, *etp; uintptr mmuphys=0, soff; Page **pg, *lkp, *new; Page *(*fn)(Segment*, uintptr); addr &= ~(BY2PG-1); soff = addr-s->base; p = &s->map[soff/PTEMAPMEM]; if(*p == 0) *p = ptealloc(); etp = *p; pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; type = s->type&SG_TYPE; if(pg < etp->first) etp->first = pg; if(pg > etp->last) etp->last = pg; switch(type) { default: panic("fault"); break; case SG_TEXT: /* Demand load */ if(pagedout(*pg)) pio(s, addr, soff, pg); mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; (*pg)->modref = PG_REF; break; case SG_BSS: case SG_SHARED: /* Zero fill on demand */ case SG_STACK: if(*pg == 0) { new = newpage(1, &s, addr); if(s == 0) return -1; *pg = new; } goto common; case SG_DATA: common: /* Demand load/pagein/copy on write */ if(pagedout(*pg)) pio(s, addr, soff, pg); /* * It's only possible to copy on write if * we're the only user of the segment. */ if(read && conf.copymode == 0 && s->ref == 1) { mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID; (*pg)->modref |= PG_REF; break; } lkp = *pg; lock(lkp); if(lkp->image == &swapimage) ref = lkp->ref + swapcount(lkp->daddr); else ref = lkp->ref; if(ref == 1 && lkp->image){ /* save a copy of the original for the image cache */ duppage(lkp); ref = lkp->ref; } unlock(lkp); if(ref > 1){ new = newpage(0, &s, addr); if(s == 0) return -1; *pg = new; copypage(lkp, *pg); putpage(lkp); }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use uvpd, uvpt, and duppage. // Remember to fix "thisenv" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { envid_t child; unsigned pagenum; int i; // First set up the page fault handler set_pgfault_handler(pgfault); // Create a new child environment and store its id. Return the error // on failure child = sys_exofork(); if(child < 0) { // There was some error, return the error return child; } else if(child == 0) { // This is the child, thisenv needs to be fixed thisenv = &envs[ENVX(sys_getenvid())]; return child; } // Map every page under UTOP using duppage. Writable pages will // be mapped to a COW page, and non-writable pages will be mapped // to read-only pages. Very simple. // // The only exception is the exception stack (located at UXSTACKTOP- // PGSIZE). A new page should be allocated in the child for this. for(pagenum = 0; pagenum < PGNUM(UTOP); pagenum++) { // Check to see if the page directory entry and page table // entry for this page exist. if((uvpd[PDX(pagenum*PGSIZE)]&PTE_P) == 0 || (uvpt[pagenum]&PTE_P) == 0) continue; if(pagenum == PGNUM(UXSTACKTOP-PGSIZE)) // Found the exception stack page sys_page_alloc(child, (void *)(pagenum*PGSIZE), PTE_U|PTE_W); else // Duplicate the page duppage(child, pagenum); } // Get the child environment struct and set its pagefault handlers // by copying the ones from the parent. if(sys_env_set_pgfault_upcall(child, thisenv->env_pgfault_upcall) != 0) panic("unable to set child page fault upcall"); if(sys_env_set_global_pgfault(child, thisenv->env_pgfault_global) != 0) panic("unable to set child page fault handler"); for(i = 0; i < MAXHANDLERS; i++) { // Don't add a handler that doesn't exist if(thisenv->env_pgfault_handlers[i].erh_maxaddr == 0) continue; // Attempt to set the handler if(sys_env_set_region_pgfault(child, thisenv->env_pgfault_handlers[i].erh_handler, (void *)thisenv->env_pgfault_handlers[i].erh_minaddr, (void *)thisenv->env_pgfault_handlers[i].erh_maxaddr) != 0); panic("unable to set child page fault handler"); } // Finally, mark the child as runnable. if(sys_env_set_status(child, ENV_RUNNABLE) != 0) panic("can't set child status to runnable"); // Return the child id return child; }
// // User-level fork with copy-on-write. // Set up our page fault handler appropriately. // Create a child. // Copy our address space and page fault handler setup to the child. // Then mark the child as runnable and return. // // Returns: child's envid to the parent, 0 to the child, < 0 on error. // It is also OK to panic on error. // // Hint: // Use vpd, vpt, and duppage. // Remember to fix "env" in the child process. // Neither user exception stack should ever be marked copy-on-write, // so you must allocate a new page for the child's user exception stack. // envid_t fork(void) { // LAB 4: Your code here. // panic("fork not implemented"); envid_t child_envid; extern void _pgfault_upcall(void); int r; uint32_t pde_x, pte_x, vpn; // page directory index, page table index and page number // Set up our page fault handler appropriately. set_pgfault_handler(pgfault); if (debug) cprintf("\n After set_pgfaulthandler()\n"); // Create a child. child_envid = sys_exofork(); if (debug) cprintf("\n After exofork()\n"); if (child_envid < 0) return child_envid; if (debug) cprintf("\n After child_envid >= 0\n"); // panic(" panic in lib/fork.c - fork():sys_exofork: %e", child_env); // fix "env" in the child process if (child_envid == 0) { if (debug) cprintf("\n After child_envid == 0\n"); env = &envs[ENVX(sys_getenvid())]; return 0; } // reached here... we're the parent process // Map the address space except the user exception stack if (debug) cprintf("\n After child_envid > 0\n"); for (pde_x = VPD(0); pde_x < VPD(UTOP); pde_x++) { if ((vpd[pde_x] & PTE_P) == PTE_P) { for (pte_x = 0; pte_x < NPTENTRIES; pte_x++) { vpn = (pde_x << (PDXSHIFT - PTXSHIFT)) + pte_x; //removed hardcoding if(((vpt[vpn] & PTE_P) == PTE_P) && (vpn < VPN(UXSTACKTOP - PGSIZE))) { if (debug) cprintf("\n Before duppage\n"); duppage(child_envid, vpn); if (debug) cprintf("\n After duppage\n"); } } } } if (debug) cprintf("\n After duppaging()\n"); // Allocate and copy the use exception stack for the child environment // Allocate a page for the stack in the child if ((r = sys_page_alloc(child_envid, (void*)(UXSTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) return r; if (debug) cprintf("\n After set_pgfaulthandler()\n"); // Map this page to a free virtual address space in parent if ((r = sys_page_map(child_envid, (void*)(UXSTACKTOP - PGSIZE), 0, (void*)UTEMP, PTE_P | PTE_U | PTE_W)) < 0) return r; if (debug) cprintf("\n After sys_page_map()\n"); // Copy the parent exception stack to the above, i.e. page from child mapped to parent's address space memmove((void*)UTEMP, (void*)(UXSTACKTOP - PGSIZE), PGSIZE); if (debug) cprintf("\n After memmove()\n"); // Unmap this page from the parent sys_page_unmap(0, (void*)UTEMP); if (debug) cprintf("\n After sys_page_unmap()\n"); // Set up the page fault handler if ((r = sys_env_set_pgfault_upcall(child_envid, _pgfault_upcall)) < 0) return r; // panic(" panic in lib/fork.c - fork():sys_env_set_pgfault_upcall: %e", child_env); if (debug) cprintf("\n After set_upcall()\n"); // Mark the child runnable if ((r = sys_env_set_status(child_envid, ENV_RUNNABLE)) < 0) return r; // panic(" panic in lib/fork.c - fork():sys_env_set_status: %e", child_env); if (debug) cprintf("\n After set_status()\n"); return child_envid; }