// 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. // LAB 3: Your code here. // panic("syscall not implemented"); switch (syscallno) { case SYS_cputs: sys_cputs((char *)a1, a2); break; case SYS_cgetc: return sys_cgetc(); case SYS_env_destroy: return sys_env_destroy(a1); case SYS_getenvid: return sys_getenvid(); case SYS_yield: sys_yield(); break; case SYS_page_alloc: return sys_page_alloc(a1, (void *)a2, a3); case SYS_page_map: return sys_page_map(a1, (void *)a2, a3, (void *)a4, a5); case SYS_page_unmap: return sys_page_unmap(a1, (void *)a2); case SYS_env_set_status: return sys_env_set_status(a1, a2); case SYS_exofork: return sys_exofork(); case SYS_env_set_pgfault_upcall: return sys_env_set_pgfault_upcall(a1, (void *)a2); case SYS_ipc_try_send: return sys_ipc_try_send(a1, a2, (void*)a3, a4); case SYS_ipc_recv: return sys_ipc_recv((void*)a1); case SYS_env_set_trapframe: return sys_env_set_trapframe(a1, (struct Trapframe *)a2); case SYS_time_msec: return sys_time_msec(); case SYS_trans_pkt: return sys_trans_pkt((void*)a1, a2); case SYS_recv_pkt: return sys_recv_pkt((void *)a1, (size_t *)a2); default: return -E_INVAL; } return 0; }
// 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. // LAB 3: Your code here. switch (syscallno){ case SYS_getenvid: return sys_getenvid(); case SYS_cputs: sys_cputs((const char*)a1, a2); return 0; case SYS_cgetc: return sys_cgetc(); case SYS_env_destroy: return sys_env_destroy(a1); case SYS_map_kernel_page: return sys_map_kernel_page((void*)a1, (void*)a2); case SYS_sbrk: return sys_sbrk(a1); case SYS_yield: sys_yield(); return 0; case SYS_exofork: return sys_exofork(); case SYS_env_set_status: return sys_env_set_status((envid_t)a1, (int)a2); case SYS_page_alloc: return sys_page_alloc((envid_t)a1, (void *)a2, (int)a3); case SYS_page_map: return sys_page_map((envid_t)*((uint32_t*)a1), (void*)*((uint32_t*)a1+1), (envid_t)*((uint32_t*)a1+2), (void*)*((uint32_t*)a1+3), (int)*((uint32_t*)a1+4)); case SYS_page_unmap: return sys_page_unmap((envid_t)a1, (void*)a2); case SYS_env_set_priority: return sys_env_set_priority((envid_t)a1, (int) a2); case SYS_env_set_pgfault_upcall: return sys_env_set_pgfault_upcall((envid_t)a1, (void*)a2); case SYS_ipc_recv: return sys_ipc_recv((void*)a1); case SYS_ipc_try_send: return sys_ipc_try_send((envid_t)a1, a2, (void*)a3, (int)a4); default: return -E_INVAL; } }
// 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. // LAB 3: Your code here. //panic("syscall not implemented"); int ret = 0; switch (syscallno) { case SYS_cputs: sys_cputs((char*)a1, a2); ret = 0; break; case SYS_cgetc: ret = sys_cgetc(); break; case SYS_getenvid: ret = sys_getenvid(); break; case SYS_env_destroy: sys_env_destroy(a1); ret = 0; break; case SYS_yield: sys_yield(); break; case SYS_exofork: return sys_exofork(); 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_env_set_status: return sys_env_set_status(a1, a2); break; case SYS_env_set_pgfault_upcall: return sys_env_set_pgfault_upcall(a1, (void*)a2); break; default: ret = -E_INVAL; } return ret; }
// Dispatches to the correct kernel function, passing the arguments. int64_t syscall(uint64_t syscallno, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5) { // Call the function corresponding to the 'syscallno' parameter. // Return any appropriate return value. // LAB 3: Your code here. uint64_t retval = 0; switch (syscallno) { case SYS_cputs: sys_cputs((char *) a1, (size_t) a2); return retval; case SYS_cgetc: return (int64_t) sys_cgetc(); case SYS_getenvid: return (int64_t) sys_getenvid(); case SYS_env_destroy: return (int64_t) sys_env_destroy((envid_t) a1); case SYS_yield: sys_yield(); return retval; case SYS_exofork: return (int64_t)sys_exofork(); case SYS_page_alloc: return (int64_t)sys_page_alloc((envid_t)a1, (void *)a2, (int)a3); case SYS_page_map: return (int64_t)sys_page_map((envid_t)a1, (void *)a2, (envid_t)a3, (void *)a4, (int)a5); case SYS_page_unmap: return (int64_t)sys_page_unmap((envid_t)a1, (void *)a2); case SYS_env_set_status: return (int64_t)sys_env_set_status((envid_t)a1, (int)a2); case SYS_env_set_pgfault_upcall: return (int64_t)sys_env_set_pgfault_upcall((envid_t)a1, (void *)a2); case SYS_ipc_try_send: return (int64_t) sys_ipc_try_send((envid_t) a1, (uint32_t) a2, (void *) a3, (unsigned) a4); case SYS_ipc_recv: return (int64_t)sys_ipc_recv((void*)a1); case SYS_env_set_trapframe: return sys_env_set_trapframe((envid_t)a1, (struct Trapframe*)a2); case SYS_time_msec: return sys_time_msec(); case SYS_net_try_send: return sys_net_try_send((char *) a1, (int) a2); case SYS_net_try_receive: return sys_net_try_receive((char *) a1, (int *) a2); default: return -E_INVAL; } panic("syscall not implemented"); }
// 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 i, 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[PDX(ova)]) { for (i = 0; i < PTSIZE; i += PGSIZE) { pte = vpt[VPN(ova + i)]; if (pte&PTE_P) { // should be no error here -- pd is already allocated if ((r = sys_page_map(0, ova + i, 0, nva + i, pte & PTE_USER)) < 0) goto err; } } } if ((r = sys_page_map(0, oldfd, 0, newfd, vpt[VPN(oldfd)] & PTE_USER)) < 0) goto err; return newfdnum; err: sys_page_unmap(0, newfd); for (i = 0; i < PTSIZE; i += PGSIZE) sys_page_unmap(0, nva + i); return r; }
// // 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"); }
// // 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; envid_t e_id = sys_getenvid(); // // 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. //cprintf("Calling pgfault"); if (!(err & FEC_WR)) { panic("user page fault called on read (should be write)"); } // if (!(uvpt[PGNUM(addr)] & PTE_COW)) { // panic("\n----------------------------------\nuser page fault called on non COW page with: \nAddress %p \nEnvironment=%d", addr, e_id); // } // 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. // LAB 4: Your code here. void* page_addr = ROUNDDOWN(addr, PGSIZE); int alloc_err = sys_page_alloc(e_id, PFTEMP, PTE_P | PTE_U | PTE_W); if (alloc_err) { panic("sys_page_alloc failed"); } memcpy(PFTEMP, page_addr, PGSIZE); int map_err = sys_page_map(e_id, PFTEMP, e_id, page_addr, PTE_P | PTE_U | PTE_W); if (map_err) { panic("sys_page_map failed"); } int umap_err = sys_page_unmap(e_id, PFTEMP); if (umap_err) { panic("sys_page_unmap failed"); } return; }
void serve(void) { uint32_t req, whom; int perm; while (1) { perm = 0; req = ipc_recv((int32_t *) &whom, (void *) REQVA, &perm); if (debug) cprintf("fs req %d from %08x [page %08x: %s]\n", req, whom, vpt[VPN(REQVA)], REQVA); // All requests must contain an argument page if (!(perm & PTE_P)) { cprintf("Invalid request from %08x: no argument page\n", whom); continue; // just leave it hanging... } switch (req) { case FSREQ_OPEN: serve_open(whom, (struct Fsreq_open*)REQVA); break; case FSREQ_MAP: serve_map(whom, (struct Fsreq_map*)REQVA); break; case FSREQ_SET_SIZE: serve_set_size(whom, (struct Fsreq_set_size*)REQVA); break; case FSREQ_CLOSE: serve_close(whom, (struct Fsreq_close*)REQVA); break; case FSREQ_DIRTY: serve_dirty(whom, (struct Fsreq_dirty*)REQVA); break; case FSREQ_REMOVE: serve_remove(whom, (struct Fsreq_remove*)REQVA); break; case FSREQ_SYNC: serve_sync(whom); break; default: cprintf("Invalid request code %d from %08x\n", whom, req); break; } sys_page_unmap(0, (void*) REQVA); } }
// // 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; pte_t pte; envid_t envid; void *va; // 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. //check # 1 - ren if (!(err & FEC_WR)) panic ("pgfault() - page fault caused not by write!"); //check # 2 - ren pte = (pte_t)vpt[VPN(addr)]; pte &= 0xF00; if (pte != PTE_COW) panic ("pgfault() - access was not to a copy-on-write 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. envid = sys_getenvid(); va = (void*)ROUNDDOWN(addr, PGSIZE); if ( (r = sys_page_alloc(envid, PFTEMP, PTE_U | PTE_P | PTE_W)) < 0) sys_env_destroy(envid); memcpy(PFTEMP, va, PGSIZE); if ( (r = sys_page_map(envid, PFTEMP, envid, va, PTE_U | PTE_P | PTE_W)) < 0) sys_env_destroy(envid); if ((r = sys_page_unmap(envid, PFTEMP)) < 0) //fourth system call, hm - ren sys_env_destroy(envid); }
void duppage(envid_t dstenv, void *addr) { int r; // This is NOT what you should do in your fork. if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc: %e", r); if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_map: %e", r); memmove(UTEMP, addr, PGSIZE); if ((r = sys_page_unmap(0, UTEMP)) < 0) panic("sys_page_unmap: %e", r); }
// Make sure this block is unmapped. void unmap_block(uint32_t blockno) { int r; if (!block_is_mapped(blockno)) return; assert(block_is_free(blockno) || !block_is_dirty(blockno)); if ((r = sys_page_unmap(0, diskaddr(blockno))) < 0) panic("unmap_block: sys_mem_unmap: %e", r); assert(!block_is_mapped(blockno)); }
static int map_segment(envid_t child, uintptr_t va, size_t memsz, int fd, size_t filesz, off_t fileoffset, int perm) { int i, r; void *blk; //cprintf("map_segment %x+%x\n", va, memsz); if ((i = PGOFF(va))) { va -= i; memsz += i; filesz += i; fileoffset -= i; } for (i = 0; i < memsz; i += PGSIZE) { if (i >= filesz) { // allocate a blank page if ((r = sys_page_alloc(0, UTEMP, perm)) < 0) { return r; } memset(UTEMP, 0, PGSIZE); sys_page_map(0, UTEMP, child, (void *)(va+i), perm); return r; } else { // from file if (perm & PTE_W) { // must make a copy so it can be writable if ((r = sys_page_alloc(0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0) return r; if ((r = seek(fd, fileoffset + i)) < 0) return r; if ((r = read(fd, UTEMP, MIN(PGSIZE, filesz-i))) < 0) return r; memset(UTEMP+MIN(PGSIZE, filesz-i), 0, PGSIZE-MIN(PGSIZE, filesz-i)); if ((r = sys_page_map(0, UTEMP, child, (void*) (va + i), perm)) < 0) panic("spawn: sys_page_map data: %e", r); sys_page_unmap(0, UTEMP); } else { // can map buffer cache read only if ((r = read_map(fd, fileoffset + i, &blk)) < 0) return r; if ((r = sys_page_map(0, blk, child, (void*) (va + i), perm)) < 0) panic("spawn: sys_page_map text: %e", r); } } } return 0; }
// Frees file descriptor 'fd' by closing the corresponding file // and unmapping the file descriptor page. // If 'must_exist' is 0, then fd can be a closed or nonexistent file // descriptor; the function will return 0 and have no other effect. // If 'must_exist' is 1, then fd_close returns -E_INVAL when passed a // closed or nonexistent file descriptor. // Returns 0 on success, < 0 on error. int fd_close(struct Fd *fd, bool must_exist) { struct Fd *fd2; struct Dev *dev; int r; if ((r = fd_lookup(fd2num(fd), &fd2)) < 0 || fd != fd2) return (must_exist ? r : 0); if ((r = dev_lookup(fd->fd_dev_id, &dev)) >= 0) r = (*dev->dev_close)(fd); // Make sure fd is unmapped. Might be a no-op if // (*dev->dev_close)(fd) already unmapped it. (void) sys_page_unmap(0, fd); return r; }
// Send a proof over IPC void send_proof(envid_t to, Proof p) { // Copy the proof to UTEMP sys_page_alloc(0, UTEMP, PTE_U | PTE_W); Heap tempHeap; init_heap(&tempHeap, UTEMP, PGSIZE); Heap *oldHeap = set_heap(&tempHeap); Proof copy = proof_cp(p); size_t offset = (uintptr_t)copy - (uintptr_t)UTEMP; // Send the proof ipc_send(to, offset, UTEMP, PTE_U); sys_page_unmap(0, UTEMP); // Reset the heap set_heap(oldHeap); }
// // 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. //cprintf("In the handler of pgfault with va:%x\n", addr); cprintf("Entered in pagefault entered. Fault va: %p, err: %d, perm: %d, VPN(addr): %d, addr>>PGSHIFT: %d\n", \ addr, err, PTE_COW, vpt[VPN(addr)], (uint32_t)addr>>PGSHIFT); if(vpt[VPN(addr)] == 0 || addr == 0) { cprintf("In \n"); return; } if(!((err & FEC_WR) && (vpt[VPN(addr)] & PTE_COW))) panic("Incorrectly entered in pagefault entered. Fault va: %p, err: %d, perm: %d, VPN(addr): %d, addr>>PGSHIFT: %d\n", \ addr, err, PTE_COW, vpt[VPN(addr)], (uint32_t)addr>>PGSHIFT); // 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. // Allocate a new page at PFTEMP //cprintf("Check: %04x %04x\n", env->env_id, sys_getenvid()); sys_page_alloc(0, (void *)PFTEMP, PTE_W | PTE_U | PTE_P); // Copy the old contents into the new page memmove((void *)PFTEMP, (void *)ROUNDDOWN((uint32_t)addr, PGSIZE), PGSIZE); // Now map the page to the sys_page_map(0, (void *)PFTEMP, \ 0, (void *)ROUNDDOWN((uint32_t)addr,PGSIZE), PTE_W | PTE_U | PTE_P); sys_page_unmap(0, PFTEMP); //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; //cprintf("envid: %x, eip: %x, fault_va: %x\n", thisenv->env_id, utf->utf_eip, addr); // 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)) { panic("pgfault: error is not a write. it is %e with falting addr 0x%x\n", err, addr); } if (!(uvpt[PGNUM(addr)] & PTE_COW)) { panic("pgfault: page not COW\n"); } // 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. // LAB 4: Your code here. if ((r = sys_page_alloc(0, PFTEMP, PTE_U|PTE_W|PTE_P)) < 0) { panic("pgfault: sys_page_alloc fail %e", r); } memmove(PFTEMP, ROUNDDOWN(addr, PGSIZE), PGSIZE); if ((r = sys_page_map(0, PFTEMP, 0, ROUNDDOWN(addr, PGSIZE), PTE_P|PTE_U|PTE_W)) < 0) { panic("pgfault: sys_page_map: %e", r); } if ((r = sys_page_unmap(0, PFTEMP)) < 0) { panic("pgfault: sys_page_unmap: %e", r); } }
// 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. // LAB 3: Your code here. switch (syscallno) { case (SYS_cputs): sys_cputs((const char *) a1, a2); return 0; case (SYS_cgetc): return sys_cgetc(); case (SYS_getenvid): return sys_getenvid(); case (SYS_env_destroy): return sys_env_destroy(a1, a2); case (SYS_yield): sys_yield(); return 0; case (SYS_exofork): return sys_exofork(); case (SYS_env_set_status): return sys_env_set_status(a1, a2); case (SYS_page_alloc): return sys_page_alloc(a1, (void *) a2, a3); case (SYS_page_map): return sys_page_map(a1, (void *) a2, a3, (void *) a4, a5); case (SYS_page_unmap): return sys_page_unmap(a1, (void *) a2); case (SYS_env_set_pgfault_upcall): return sys_env_set_pgfault_upcall(a1, (void *) a2); case (SYS_ipc_try_send): return sys_ipc_try_send(a1, a2, (void *) a3, a4); case (SYS_ipc_recv): return sys_ipc_recv((void *) a1); case (SYS_env_set_trapframe): return sys_env_set_trapframe(a1, (struct Trapframe *) a2); case (SYS_time_msec): return sys_time_msec(); case (SYS_e1000_transmit): return sys_e1000_transmit(a1, (char *) a2, a3); default: return -E_INVAL; } }
int sys_env_set_thisenv(envid_t envid, void *thisenv) { void *pgva = (void *) ROUNDDOWN(thisenv, PGSIZE); if (sys_page_map(envid, pgva, curenv->env_id, (void *) UTEMP, PTE_P|PTE_U|PTE_W) < 0) return -E_INVAL; *((struct Env **)(UTEMP + PGOFF(thisenv))) = &((struct Env *)UENVS)[ENVX(envid)]; if (sys_page_unmap(curenv->env_id, (void *) UTEMP) < 0) return -E_INVAL; 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 vpt // (see <inc/memlayout.h>). // LAB 4: Your code here. // seanyliu if (!(err & FEC_WR) || !(vpt[VPN(addr)] & PTE_COW)) { panic("pgfault, err != FEC_WR or not copy-on-write 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. // seanyliu addr = ROUNDDOWN(addr, PGSIZE); // Allocate a new page, map it at a temporary location (PFTEMP), if ((r = sys_page_alloc(sys_getenvid(), (void *)PFTEMP, PTE_U | PTE_W | PTE_P)) < 0) { panic("pgfault: sys_page_alloc %d", r); } // copy the data from the old page to the new page memmove(PFTEMP, addr, PGSIZE); // move the new page to the old page's address. if ((r = sys_page_map(sys_getenvid(), PFTEMP, sys_getenvid(), addr, PTE_U | PTE_W | PTE_P)) < 0) { panic("pgfault: sys_page_map %d", r); } if ((r = sys_page_unmap(sys_getenvid(), PFTEMP)) < 0) { panic("pgfault: sys_page_unmap %d", 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; pte_t pte; 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. if ((err & FEC_WR) != FEC_WR) { if (debug) cprintf("Error caught = %x\n", err); panic ("user panic in lib/fork.c - pgfault(): faulting access is not write\n"); } pte = vpt[VPN(addr)]; if ((pte & PTE_COW) != PTE_COW) panic ("user panic in lib/fork.c - pgfault(): faulting access is not to a COW page\n"); // 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_P | PTE_U | PTE_W)) < 0) panic ("user panic in lib/fork.c - pgfault(): sys_page_alloc: %e", r); memmove((void*)PFTEMP, (void*)ROUNDDOWN(addr,PGSIZE), PGSIZE); if ((r = sys_page_map(0, (void*)PFTEMP, 0, (void*)ROUNDDOWN(addr,PGSIZE), PTE_P | PTE_U | PTE_W)) < 0) panic ("user panic in lib/fork.c - pgfault(): sys_page_map: %e", r); if ((r = sys_page_unmap(0, (void*)PFTEMP)) < 0) panic ("user panic in lib/fork.c - pgfault(): sys_page_unmap: %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. pte_t pte = vpt[((uint64_t) addr / PGSIZE)]; if (!(err & FEC_WR)) panic("Faulting access write(FEC_WR) failed = 0x%x: err %x\n\n", (uint64_t) addr, err); if (!(pte & PTE_COW)) panic("Faulting access copy-on-write(PTE_COW) failed = 0x%x, env_id 0x%x\n", (uint64_t) addr, thisenv->env_id); // 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_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc failed: %e\n", r); memcpy(PFTEMP, ROUNDDOWN(addr, PGSIZE), PGSIZE); void *vaTemp = (void *) ROUNDDOWN((uint64_t) addr, PGSIZE); if ((r = sys_page_map(0, (void *)PFTEMP, 0, 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); //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 uvpt // (see <inc/memlayout.h>). // LAB 4: Your code here. // 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 (!((err & FEC_WR) && (uvpd[PDX(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_COW))) panic("not copy-on-write"); addr = ROUNDDOWN(addr, PGSIZE); if (sys_page_alloc(0, PFTEMP, PTE_W|PTE_U|PTE_P) < 0) panic("sys_page_alloc"); memcpy(PFTEMP, addr, PGSIZE); if (sys_page_map(0, PFTEMP, 0, addr, PTE_W|PTE_U|PTE_P) < 0) panic("sys_page_map"); if (sys_page_unmap(0, PFTEMP) < 0) panic("sys_page_unmap"); return; // panic("pgfault not implemented"); }
// Dispatches to the correct kernel function, passing the arguments. uint32_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. // LAB 3: Your code here. switch (syscallno){ case SYS_cputs: sys_cputs( (const char *)a1, a2); return 0; case SYS_cgetc: return sys_cgetc(); case SYS_getenvid: return sys_getenvid(); case SYS_env_destroy: return sys_env_destroy(a1); case SYS_yield: sys_yield(); return 0; case SYS_exofork: return sys_exofork(); case SYS_env_set_status: return sys_env_set_status(a1, a2); case SYS_page_alloc: return sys_page_alloc(a1, (void *)a2, a3); case SYS_page_map: return sys_page_map(a1, (void *)a2, a3, (void *)a4, a5); case SYS_env_set_trapframe: return sys_env_set_trapframe(a1, (struct Trapframe *)a2); case SYS_page_unmap: return sys_page_unmap(a1, (void *)a2); case SYS_env_set_pgfault_upcall: return sys_env_set_pgfault_upcall(a1, (void *)a2); case SYS_ipc_try_send: return sys_ipc_try_send(a1, a2, (void *)a3, a4); case SYS_ipc_recv: return sys_ipc_recv((void *)a1); default: panic("this syscall ( %d )is not yet implemented", syscallno); } }
void duppage(envid_t dstenv, void *addr) { int r; // This is NOT what you should do in your fork. // 这个实现太trick了: // 先在dstenv的addr上分配一页,然后将dstenv的addr所在的页面映射到 // 当前进程的UTEMP位置,最后将current的addr的内容copy到current的 // UTEMP, 因为经过sys_page_map()之后,current TEMP和dstenv的addr // 指向同一实际物理页面,这样就实现了把current'addr -> dstenv's addr // 的功能。最后还要对current's UTEMP进行umap。 if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc: %e", r); if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_map: %e", r); memmove(UTEMP, addr, PGSIZE); if ((r = sys_page_unmap(0, UTEMP)) < 0) panic("sys_page_unmap: %e", r); }
//new added sys_for_fork to //augment the system call interface //so that it is possible to send a batch of system calls at once //because switching into the kernel has non-trivial cost!!! static int sys_for_fork(envid_t envid, void * func, int status) { int r; int perm = PTE_W|PTE_P|PTE_U; void * va = (void*)(UXSTACKTOP - PGSIZE); if((r = sys_page_alloc(envid, va, perm)) < 0) return r; if ((r = sys_page_map(envid, va, curenv->env_id, UTEMP, perm)) < 0) panic("sys_page_map: %e", r); memmove(UTEMP, va, PGSIZE); if ((r = sys_page_unmap(curenv->env_id, UTEMP)) < 0) panic("sys_page_unmap: %e", r); if ((r = sys_env_set_pgfault_upcall(envid, func)) < 0) return r; if ((r = sys_env_set_status(envid, status)) < 0) return r; return 0; }
// dstenv is the child's env // addr is the va of the parent void duppage(envid_t dstenv, void *addr) { int r; // This is NOT what you should do in your fork. // allocate a page starting at addr in child's process space if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_alloc: %e", r); // srcenvid srcva dstenvid dstva if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0) panic("sys_page_map: %e", r); memmove(UTEMP, addr, PGSIZE); if ((r = sys_page_unmap(0, UTEMP)) < 0) panic("sys_page_unmap: %e", r); }
int // user call to lease self sys_migrate(void *thisenv) { envid_t jdos_client = 0; struct Env *e; int i, r; for (i = 0; i < NENV; i++) { if (envs[i].env_type == ENV_TYPE_JDOSC) { jdos_client = envs[i].env_id; break; } } // jdos client running? if (!jdos_client) return -E_BAD_ENV; if ((r = envid2env(jdos_client, &e, 0)) < 0) return r; // Mark leased and try to migrate curenv->env_status = ENV_SUSPENDED; sys_page_alloc(curenv->env_id, (void *) IPCSND, PTE_U|PTE_P|PTE_W); *((envid_t *) IPCSND) = curenv->env_id; *((void **)(IPCSND + sizeof(envid_t))) = thisenv; //can't write to page r = sys_ipc_try_send(jdos_client, CLIENT_LEASE_REQUEST, (void *) IPCSND, PTE_U|PTE_P); sys_page_unmap(curenv->env_id, (void *) IPCSND); // Failed to migrate, back to running! if (r < 0) { cprintf("==> sys_migrate: failed to send ipc %d\n", r); curenv->env_status = ENV_RUNNABLE; return r; } // Migrated! BOOM! 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 vpt // (see <inc/memlayout.h>). //cprintf("pgfault: do page fault here %x\n",utf->utf_eflags); // LAB 4: Your code here. if((err & FEC_WR) == 0) panic("pgfault: fault is not a write (err: %08x va: %08x ip: %08x)",err, addr, utf->utf_eip); if ((vpd[PDX(addr)] & PTE_P) == 0 || (vpt[PGNUM(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); if((r = sys_page_unmap(0,PFTEMP)) < 0) panic("pgfault: page unmapping failed : %e", r); //cprintf("pgfault: finish\n"); /* int gaga = 0; */ /* __asm__ volatile("movl %%esp, %0\n\t" */ /* :"=r"(gaga) */ /* ::); */ /* cprintf("gaga----------%x\n", gaga); */ //panic("pgfault not implemented"); }
// Test that the block cache works, by smashing the superblock and // reading it back. static void check_bc(void) { cprintf("Starting..\n"); struct Super backup; // back up super block memmove(&backup, diskaddr(1), sizeof(backup)); BC_DEBUG("Wrote superblock to disk ram block..\n"); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); // smash it strcpy(diskaddr(1), "OOPS!\n"); flush_block(diskaddr(1)); assert(va_is_mapped(diskaddr(1))); assert(!va_is_dirty(diskaddr(1))); cprintf("Smashed disk superblock..\n"); // clear it out sys_page_unmap(0, diskaddr(1)); assert(!va_is_mapped(diskaddr(1))); cprintf("Unmapped superblock va..\n"); // read it back in assert(strcmp(diskaddr(1), "OOPS!\n") == 0); cprintf("re-read superblock va..\n"); // fix it memmove(diskaddr(1), &backup, sizeof(backup)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); flush_block(diskaddr(1)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); BC_DEBUG("backup magic number : %08x\n", backup.s_magic); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); BC_DEBUG("expected magic value : %08x\n", FS_MAGIC); cprintf("Fixed superblock..\n"); cprintf("block cache is good\n"); }
void serve(void) { uint32_t req, whom; int perm, r; void *pg; while (1) { perm = 0; req = ipc_recv((int32_t *) &whom, fsreq, &perm); if (debug) cprintf("fs req %d from %08x [page %08x: %08x]\n", req, whom, vpt[VPN(fsreq)], fsreq); // All requests must contain an argument page if (!(perm & PTE_P)) { cprintf("Invalid request from %08x: no argument page\n", whom); continue; // just leave it hanging... } pg = NULL; if (req == FSREQ_OPEN) { //cprintf("\nserv.c 444444\n"); //cprintf("\nwhom : 0x%08x fsreq : 0x%08x pg : 0x%08x perm 0x%08x\n", whom, fsreq, &pg, &perm); r = serve_open(whom, (struct Fsreq_open*)fsreq, &pg, &perm); //cprintf("serveopen return addr %x \n", pg); //cprintf("\nserv.c 55555\n"); } else if (req < NHANDLERS && handlers[req]) { r = handlers[req](whom, fsreq); } else { cprintf("Invalid request code %d from %08x\n", whom, req); r = -E_INVAL; } ipc_send(whom, r, pg, perm); sys_page_unmap(0, fsreq); // cprintf("\nend of serve while loop in serv.c\n"); } }