// 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 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"); }
// // 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; }
// 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; }
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; }
// 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"); }
// 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); }