// Make file descriptor 'newfdnum' a duplicate of file descriptor 'oldfdnum'. // For instance, writing onto either file descriptor will affect the // file and the file offset of the other. // Closes any previously open file descriptor at 'newfdnum'. // This is implemented using virtual memory tricks (of course!). int dup(int oldfdnum, int newfdnum) { int r; char *ova, *nva; pte_t pte; struct Fd *oldfd, *newfd; if ((r = fd_lookup(oldfdnum, &oldfd)) < 0) return r; close(newfdnum); newfd = INDEX2FD(newfdnum); ova = fd2data(oldfd); nva = fd2data(newfd); if ((vpd[VPD(ova)] & PTE_P) && (vpt[VPN(ova)] & PTE_P)) if ((r = sys_page_map(0, ova, 0, nva, vpt[VPN(ova)] & PTE_SYSCALL)) < 0) goto err; if ((r = sys_page_map(0, oldfd, 0, newfd, vpt[VPN(oldfd)] & PTE_SYSCALL)) < 0) goto err; return newfdnum; err: sys_page_unmap(0, newfd); sys_page_unmap(0, nva); return r; }
// 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; }
// Copy the mappings for shared pages into the child address space. static int copy_shared_pages(envid_t child) { // LAB 7: Your code here. uint64_t vaddr; int r; for(vaddr=0; vaddr<UTOP; vaddr += PGSIZE) { // Copying from lib/fork.c bruh. if( // Gotta use the virtual types apparently. (vpml4e[VPML4E(vaddr)] & PTE_P) // Mota mota level is present. && ((vpde[VPDPE(vaddr)] & PTE_U) && (vpde[VPDPE(vaddr)] & PTE_P)) // Slighlt less mota level is also present. && ((vpd[VPD(vaddr)] & PTE_U) && (vpd[VPD(vaddr)] & PTE_P)) && ((vpt[VPN(vaddr)] & PTE_U) && (vpt[VPN(vaddr)] & PTE_P)) ) if(vpt[VPN(vaddr)]&PTE_SHARE) { r = sys_page_map(0, (void*)vaddr, child, (void*)vaddr, vpt[VPN(vaddr)] & PTE_SYSCALL); if(r<0) { cprintf("WARN: Your environments are now throughly done for man.\n"); return -1; } } } 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) { // 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"); }
// 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 r; int pdeno, pteno; uint32_t pn = 0; for (pdeno = 0; pdeno < VPD(UTOP); pdeno++) { if (vpd[pdeno] == 0) { // skip empty PDEs pn += NPTENTRIES; continue; } for (pteno = 0; pteno < NPTENTRIES; pteno++,pn++) { if (vpt[pn] == 0) // skip empty PTEs continue; int perm = vpt[pn] & PTE_USER; if (perm & PTE_SHARE) { void *addr = (void *)(pn << PGSHIFT); r = sys_page_map(0, addr, child, addr, perm); if (r) return r; } } } 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 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"); }
// // Map our virtual page pn (address pn*PGSIZE) into the target envid // at the same virtual address. If the page is writable or copy-on-write, // the new mapping must be created copy-on-write, and then our mapping must be // marked copy-on-write as well. (Exercise: Why do we need to mark ours // copy-on-write again if it was already copy-on-write at the beginning of // this function?) // // Returns: 0 on success, < 0 on error. // It is also OK to panic on error. // static int duppage(envid_t envid, unsigned pn) { int r; // LAB 4: Your code here. pde_t *pde; pte_t *pte; void *addr=(void*)(pn*PGSIZE); pde =(pde_t*) &vpd[VPD(addr)]; if(*pde&PTE_P) { pte=(pte_t*)&vpt[VPN(addr)]; } else panic("page table for pn page is not exist"); if((*pte&PTE_W)||(*pte&PTE_COW)) { if((r=sys_page_map(0,addr,envid,addr,PTE_COW|PTE_U))<0) return r; if((r=sys_page_map(0,addr,0,addr,PTE_COW|PTE_U))<0)//映射的时候注意env的id return r; } else{ if((r=sys_page_map(0,addr,envid,addr,PTE_U|PTE_P))<0) return r; } //panic("duppage not implemented"); return 0; }
// // Custom page fault handler - if faulting page is copy-on-write, // map in our own private writable copy. // static void pgfault(struct UTrapframe *utf) { void *addr = (void *) utf->utf_fault_va; uint32_t err = utf->utf_err; int r; // Check that the faulting access was (1) a write, and (2) to a // copy-on-write page. If not, panic. // Hint: // Use the read-only page table mappings at uvpt // (see <inc/memlayout.h>). // LAB 4: Your code here. if ((err & FEC_WR) == 0 || (vpd[VPD(addr)] & PTE_P) == 0 || (vpt[VPN(addr)] & PTE_COW) == 0) panic ("pgfault: not a write or attempting to access a non-COW page"); // Allocate a new page, map it at a temporary location (PFTEMP), // copy the data from the old page to the new page, then move the new // page to the old page's address. // Hint: // You should make three system calls. // No need to explicitly delete the old page's mapping. // LAB 4: Your code here. if ((r = sys_page_alloc (0, (void *)PFTEMP, PTE_U|PTE_P|PTE_W)) < 0) panic ("pgfault: page allocation failed : %e", r); addr = ROUNDDOWN (addr, PGSIZE); memmove (PFTEMP, addr, PGSIZE); if ((r = sys_page_map (0, PFTEMP, 0, addr, PTE_U|PTE_P|PTE_W)) < 0) panic ("pgfault: page mapping failed : %e", r); //panic("pgfault not implemented"); }
// // Custom page fault handler - if faulting page is copy-on-write, // map in our own private writable copy. // static void pgfault(struct UTrapframe *utf) { void *addr = (void *) utf->utf_fault_va; uint32_t err = utf->utf_err; int r; // Check that the faulting access was (1) a write, and (2) to a // copy-on-write page. If not, panic. // Hint: // Use the read-only page table mappings at vpt // (see <inc/memlayout.h>). // LAB 4: Your code here. pde_t *pde; pte_t *pte; uint32_t *va,*srcva,*dstva; pde =(pde_t*) &vpd[VPD(addr)]; if(*pde&PTE_P) { pte=(pte_t*)&vpt[VPN(addr)]; } else{ cprintf("addr=%x err=%x *pde=%x utf_eip=%x\n",(uint32_t)addr,err,*pde,utf->utf_eip); panic("page table for fault va is not exist"); } //cprintf("addr=%x err=%x *pte=%x utf_eip=%x\n",(uint32_t)addr,err,*pte,utf->utf_eip); if(!(err&FEC_WR)||!(*pte&PTE_COW)) { cprintf("envid=%x addr=%x err=%x *pte=%x utf_eip=%x\n",env->env_id,(uint32_t)addr,err,*pte,utf->utf_eip); panic("faulting access is illegle"); } // Allocate a new page, map it at a temporary location (PFTEMP), // copy the data from the old page to the new page, then move the new // page to the old page's address. // Hint: // You should make three system calls. // No need to explicitly delete the old page's mapping. // LAB 4: Your code here. //cprintf("pgfault:env_id=%x\n",env->env_id); if((r=sys_page_alloc(0,PFTEMP,PTE_W|PTE_U|PTE_P))<0) //输入id=0表示当前环境id(curenv->env_id),这个时候不能用env->env-id,子环境中env的修改会缺页 panic("alloc a page for PFTEMP failed:%e",r); //cprintf("PFTEMP=%x add=%x\n",PFTEMP,(uint32_t)addr&0xfffff000); srcva = (uint32_t*)((uint32_t)addr&0xfffff000); dstva = (uint32_t*)PFTEMP; //strncpy((char*)PFTEMP,(char*)((uint32_t)addr&0xfffff000),PGSIZE); for(;srcva<(uint32_t*)(ROUNDUP(addr,PGSIZE));srcva++)//数据拷贝要注意,用strncpy出错了,原因还得分析 { *dstva=*srcva; dstva++; } if((r=sys_page_map(0,(void*)PFTEMP,0,(void*)((uint32_t)addr&0xfffff000),PTE_W|PTE_U|PTE_P))<0) //输入id=0表示当前环境id(curenv->env_id),这个时候不能用env->env-id,子环境中env的修改会缺页 panic("page mapping failed"); //panic("pgfault 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. 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; }
static int isfree(void *v, size_t n) { uintptr_t va, end_va = (uintptr_t) v + n; for (va = (uintptr_t) v; va < end_va; va += PGSIZE) if (va >= (uintptr_t) mend || ((vpd[VPD(va)] & PTE_P) && (vpt[VPN(va)] & PTE_P))) return 0; return 1; }
// Copy the mappings for shared pages into the child address space. static int copy_shared_pages(envid_t child) { // LAB 7: Your code here. uint64_t addr; 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)) { int perm_share = vpt[VPN(addr)] & PTE_USER; if (perm_share & PTE_SHARE) sys_page_map(0, (void *)addr, child, (void *)addr, perm_share); } } return 0; }
// Finds the smallest i from 0 to MAXFD-1 that doesn't have // its fd page mapped. // Sets *fd_store to the corresponding fd page virtual address. // // fd_alloc does NOT actually allocate an fd page. // It is up to the caller to allocate the page somehow. // This means that if someone calls fd_alloc twice in a row // without allocating the first page we return, we'll return the same // page the second time. // // Hint: Use INDEX2FD. // // Returns 0 on success, < 0 on error. Errors are: // -E_MAX_FD: no more file descriptors // On error, *fd_store is set to 0. int fd_alloc(struct Fd **fd_store) { int i; struct Fd *fd; for (i = 0; i < MAXFD; i++) { fd = INDEX2FD(i); if ((vpd[VPD(fd)] & PTE_P) == 0 || (vpt[VPN(fd)] & PTE_P) == 0) { *fd_store = fd; return 0; } } *fd_store = 0; return -E_MAX_OPEN; }
// // 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"); }
int32_t net_host_send(char *pg, int len) { // LAB 8: Your code here. if (pg == NULL) pg = (void*) UTOP; uint64_t addr = (uint64_t)pg; if( (vpml4e[VPML4E(addr)] & PTE_P) && (vpde[VPDPE(addr)] & PTE_P) && (vpd[VPD(addr)] & PTE_P) && (vpt[VPN(addr)] & PTE_P) ) { pg = (void *) PTE_ADDR( vpt[VPN(addr)] ); } int ret = vm_call( VMX_VMCALL_NETSEND, (uint64_t) pg , (uint64_t) len, 0, 0, 0 ); return ret; }
// Check that fdnum is in range and mapped. // If it is, set *fd_store to the fd page virtual address. // // Returns 0 on success (the page is in range and mapped), < 0 on error. // Errors are: // -E_INVAL: fdnum was either not in range or not mapped. int fd_lookup(int fdnum, struct Fd **fd_store) { struct Fd *fd; if (fdnum < 0 || fdnum >= MAXFD) { if (debug) cprintf("[%08x] bad fd %d\n", thisenv->env_id, fdnum); return -E_INVAL; } fd = INDEX2FD(fdnum); if (!(vpd[VPD(fd)] & PTE_P) || !(vpt[VPN(fd)] & PTE_P)) { if (debug) cprintf("[%08x] closed fd %d\n", thisenv->env_id, fdnum); return -E_INVAL; } *fd_store = fd; return 0; }
// 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"); }
// 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 i,j, r; void* va; for (i=0; i < VPD(UTOP); i++) { if (vpd[i] & PTE_P) { for (j=0; j<NPTENTRIES && i*NPDENTRIES+j < (UXSTACKTOP-PGSIZE)/PGSIZE; j++) { // make sure not to remap exception stack this way if ((vpt[i*NPDENTRIES+j] & (PTE_P | PTE_SHARE)) == (PTE_P | PTE_SHARE)) { va = (void *)((i*NPDENTRIES+j) << PGSHIFT); if ((r = sys_page_map(0, va, child, va, vpt[i*NPDENTRIES+j] & PTE_USER)) < 0) { return r; } } } } } return 0; }
// Unmap any file pages that no longer represent valid file pages // when the size of the file as mapped in our address space decreases. // Harmlessly does nothing if newsize >= oldsize. static int funmap(struct Fd* fd, off_t oldsize, off_t newsize, bool dirty) { size_t i; char *va; int r, ret; va = fd2data(fd); // Check vpd to see if anything is mapped. if (!(vpd[VPD(va)] & PTE_P)) return 0; ret = 0; for (i = ROUNDUP(newsize, PGSIZE); i < oldsize; i += PGSIZE) if (vpt[VPN(va + i)] & PTE_P) { if (dirty && (vpt[VPN(va + i)] & PTE_D) && (r = fsipc_dirty(fd->fd_file.id, i)) < 0) ret = r; sys_page_unmap(0, va + i); } return ret; }
// // 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; }
// Is this virtual address mapped? bool va_is_mapped(void *va) { return (vpml4e[VPML4E(va)] & PTE_P) && (vpde[VPDPE(va)] & PTE_P) && (vpd[VPD(va)] & PTE_P) && (vpt[PPN(va)] & PTE_P); }