int sys_fork(struct trapframe* tf, pid_t* retval) { int errcheck; //this is to check if there's error in some funcitons //first creating a new proc struct proc* child = proc_create_runprogram("child123"); //proctable_insert(child); if(child == NULL) { return ENOMEM; } curproc->child_pid = child->pid; curproc->child = child; /////////////// child->parent = curproc; ////////////// //now, copying the address space struct addrspace* newas; errcheck = as_copy(curproc_getas(), &newas); if(errcheck != 0) { //there's an error return errcheck; } child->p_addrspace = newas; //now copying the trapframe to the child struct trapframe* newtf = kmalloc(sizeof(struct trapframe)); if(newtf == NULL) { return ENOMEM; } *newtf = *tf; //now, do the thread_fork errcheck = thread_fork("child2", child, enter_forked_process, newtf, 0); if(errcheck != 0) { return errcheck; } *retval = child->pid; return(0); }
int sys_read(int fd, void *buf, size_t buflen) { struct fd* tmp; if (!buf || buf == NULL || !valid_address_check(curproc->p_addrspace, (vaddr_t)buf)){ // else if invalid buffer errno = EFAULT; return -1; } if (fd < 0 || fd >= MAX_fd_table){ // if fd < 0 || fd > MAX_fd_table or errno = EBADF; return -1; } else if (fd == STDOUT_FILENO || fd == STDERR_FILENO){ // fd == STDOUT_FILENO || STDERR_FILENO errno = EIO; return -1; } else if (fd >= 3 && fd < MAX_fd_table){ tmp = curproc->fd_table[fd]; if (tmp == NULL || (tmp->file_flag & O_WRONLY)){ // or if file is not readable errno = EBADF; // error return -1; } } struct uio u; struct iovec iov; struct addrspace *as ; as = as_create(); iov.iov_ubase = buf; iov.iov_len = buflen; u.uio_iov = &iov; u.uio_iovcnt = 1; u.uio_offset = tmp->offset; u.uio_resid = buflen; u.uio_segflg = UIO_USERSPACE; u.uio_rw = UIO_READ; u.uio_space = curproc_getas(); if (fd == STDIN_FILENO){ struct vnode *vn; char *console = NULL; // console string ("con:") console = kstrdup("con:"); // set to console vfs_open(console,O_RDONLY,0,&vn); // open the console vnode kfree(console); // free the console int result = VOP_READ(vn,&u); if(result < 0){ errno = EIO; //A hardware I/O error occurred writing the data return -1; } } else{ int retval = VOP_READ(tmp->file, &u); if (retval < 0){ errno = EIO; return -1; } } return buflen - u.uio_resid ; }
int runprogram(char *progname) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(curproc_getas() == NULL); /* Create a new address space. */ #if OPT_A3 as = as_create(progname); #else as = as_create(); #endif if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } /* Warp to user mode. */ enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
/* Duplicates the currently running process The two copies are identical except for the child having a new pid */ int sys_fork(struct trapframe *tf, int32_t *retval) { // Prevent interrupts so address space doesn't change before getting // copied int spl = splhigh(); // Store trapframe on the heap for copying to child // thread later struct trapframe *child_tf; child_tf = kmalloc(sizeof(tf)); if (child_tf == NULL) { splx(spl); return ENOMEM; } //memcpy(child_tf, tf, sizeof(tf)); child_tf = tf; // Copy parent address space struct addrspace *original_as; struct addrspace *new_as; original_as = curproc_getas(); int result = as_copy(original_as, &new_as); if (result) { splx(spl); return ENOMEM; } // Create new process struct proc *new_proc = proc_create(curproc->p_name); // Copy process fdlist for (int i = 0; i < __OPEN_MAX; i++) { if (curproc->p_fdlist[i] != NULL) { new_proc->p_fdlist[i] = curproc->p_fdlist[i]; // Increment reference count new_proc->p_fdlist[i]->fd_vfile->vn_refcount++; } } //Child process needs to have parent pid attached to it set_parent(curproc->pid, new_proc->pid); // Fork new thread, attach to new proc result = thread_fork("Child process", new_proc, enter_forked_process, (void *)child_tf, (unsigned long)new_as); if (result) { kfree(child_tf); splx(spl); return result; // Error code will be returned from thread_fork } // Set retval to child process pid *retval = new_proc->pid; splx(spl); return 0; }
void as_activate(void) { struct addrspace *as; as = curproc_getas(); if (as == NULL) { /* * Kernel thread without an address space; leave the * prior address space in place. */ return; } /* * Write this. */ }
/* * Load an ELF executable user program into the current address space. * * Returns the entry point (initial PC) for the program in ENTRYPOINT. */ int load_elf(struct vnode *v, vaddr_t *entrypoint) { Elf_Ehdr eh; /* Executable header */ Elf_Phdr ph; /* "Program header" = segment header */ int result, i; struct iovec iov; struct uio ku; struct addrspace *as; as = curproc_getas(); /* * Read the executable header from offset 0 in the file. */ uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ); result = VOP_READ(v, &ku); if (result) { return result; } if (ku.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on header - file truncated?\n"); return ENOEXEC; } /* * Check to make sure it's a 32-bit ELF-version-1 executable * for our processor type. If it's not, we can't run it. * * Ignore EI_OSABI and EI_ABIVERSION - properly, we should * define our own, but that would require tinkering with the * linker to have it emit our magic numbers instead of the * default ones. (If the linker even supports these fields, * which were not in the original elf spec.) */ if (eh.e_ident[EI_MAG0] != ELFMAG0 || eh.e_ident[EI_MAG1] != ELFMAG1 || eh.e_ident[EI_MAG2] != ELFMAG2 || eh.e_ident[EI_MAG3] != ELFMAG3 || eh.e_ident[EI_CLASS] != ELFCLASS32 || eh.e_ident[EI_DATA] != ELFDATA2MSB || eh.e_ident[EI_VERSION] != EV_CURRENT || eh.e_version != EV_CURRENT || eh.e_type!=ET_EXEC || eh.e_machine!=EM_MACHINE) { return ENOEXEC; } /* * Go through the list of segments and set up the address space. * * Ordinarily there will be one code segment, one read-only * data segment, and one data/bss segment, but there might * conceivably be more. You don't need to support such files * if it's unduly awkward to do so. * * Note that the expression eh.e_phoff + i*eh.e_phentsize is * mandated by the ELF standard - we use sizeof(ph) to load, * because that's the structure we know, but the file on disk * might have a larger structure, so we must use e_phentsize * to find where the phdr starts. */ for (i=0; i<eh.e_phnum; i++) { off_t offset = eh.e_phoff + i*eh.e_phentsize; uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ); result = VOP_READ(v, &ku); if (result) { return result; } if (ku.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on phdr - file truncated?\n"); return ENOEXEC; } switch (ph.p_type) { case PT_NULL: /* skip */ continue; case PT_PHDR: /* skip */ continue; case PT_MIPS_REGINFO: /* skip */ continue; case PT_LOAD: break; default: kprintf("loadelf: unknown segment type %d\n", ph.p_type); return ENOEXEC; } result = as_define_region(as, ph.p_vaddr, ph.p_memsz, ph.p_flags & PF_R, ph.p_flags & PF_W, ph.p_flags & PF_X); if (result) { return result; } } result = as_prepare_load(as); if (result) { return result; } /* * Now actually load each segment. */ for (i=0; i<eh.e_phnum; i++) { off_t offset = eh.e_phoff + i*eh.e_phentsize; uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ); result = VOP_READ(v, &ku); if (result) { return result; } if (ku.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on phdr - file truncated?\n"); return ENOEXEC; } switch (ph.p_type) { case PT_NULL: /* skip */ continue; case PT_PHDR: /* skip */ continue; case PT_MIPS_REGINFO: /* skip */ continue; case PT_LOAD: break; default: kprintf("loadelf: unknown segment type %d\n", ph.p_type); return ENOEXEC; } result = load_segment(as, v, ph.p_offset, ph.p_vaddr, ph.p_memsz, ph.p_filesz, ph.p_flags & PF_X); if (result) { return result; } } result = as_complete_load(as); if (result) { return result; } *entrypoint = eh.e_entry; return 0; }
runprogram(char *progname) #endif { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(curproc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } #if OPT_A2 // How much space do we need for args in stack? // We need space for each pointer (4argc) // We need space for each character, including NULL termination, plus // padding to make multiples of 4 int stringSpace = 0; for (unsigned long i = 0; i < argc; i++) { stringSpace += strlen(argv[i]) + 1; } // Align stack pointer to an 8-byte alignment while ((stackptr - (4*argc) - stringSpace) % 8 != 0) { stackptr--; } // Use a vaddr array to track the addresses the strings end up in // One bigger than argc to also have the pointer to the final NULL // value vaddr_t stringAddr[argc+1]; // Copy argument strings onto stack // Array must end with NULL pointer, so do that first stackptr -= 4; copyout((void *)NULL, (userptr_t)stackptr, (size_t)4); stringAddr[argc] = stackptr; for (int i = argc-1; i >= 0; i--) { stackptr -= strlen(argv[i]) + 1; while (stackptr % 4 != 0) stackptr--; copyoutstr(argv[i], (userptr_t)stackptr, (size_t)strlen(argv[i]), NULL); stringAddr[i] = stackptr; } // Now use the stored addresses of the string to add the appropriate // pointers to the stack for (int i = argc; i >= 0; i--) { stackptr -= sizeof(vaddr_t); copyout(&stringAddr[i], (userptr_t)stackptr, sizeof(vaddr_t)); } /* Warp to user mode. */ enter_new_process(argc /*argc*/, (userptr_t)stackptr /*userspace addr of argv*/, stackptr, entrypoint); #else /* Warp to user mode. */ enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/, stackptr, entrypoint); #endif /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
int sys_execv(userptr_t progname_ptr, userptr_t args_ptr){ char* prog_name = kmalloc(PATH_MAX); size_t prog_name_len; if((char*)progname_ptr == NULL || (char**)args_ptr == NULL){ return EFAULT; } int argc = 0; char** args_ptrs = kmalloc(ARG_MAX); while(1){ char* arg = NULL; copyin(args_ptr+argc*sizeof(char*), &arg, sizeof(char*)); args_ptrs[argc] = arg; if(arg != NULL){ argc++; }else{ break; } } if(argc> 64){ return E2BIG; } int result_prog_name = copyinstr(progname_ptr,prog_name,PATH_MAX, &prog_name_len); if(result_prog_name != 0){ return result_prog_name; } char* argv = kmalloc(ARG_MAX); size_t * arg_offsets = kmalloc(argc * sizeof(size_t)); int offset = 0; for(int i = 0; i < argc; i++){ //char* arg = kmalloc(ARG_MAX); size_t arg_len; int result = copyinstr((userptr_t)args_ptrs[i], argv+offset, ARG_MAX - offset, &arg_len ); if(result != 0){ return result; } arg_offsets[i] = offset; offset += ROUNDUP(arg_len+1,8); //argv[i] = arg; } // prog_name (char*) AND argv (char*) struct addrspace *curproc_as = curproc_getas(); struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; vaddr_t cur_ptr; int result; /* Open the file. */ result = vfs_open(prog_name, O_RDONLY, 0, &v); if (result) { return result; } /* Create a new address space. */ as = as_create(); if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); // Have both argc and prog_name ready for runprogram cur_ptr = stackptr; cur_ptr -= offset; result = copyout(argv, (userptr_t)cur_ptr, offset); if(result != 0){ return result; } userptr_t * arg_offsets_up = kmalloc(sizeof(userptr_t) * (argc+1)); for(int i = 0; i < argc; i++){ userptr_t ptr = (userptr_t)cur_ptr + arg_offsets[i]; arg_offsets_up[i] = ptr; } arg_offsets_up[argc] = NULL; cur_ptr -= sizeof(userptr_t) * (argc+1); result = copyout(arg_offsets_up, (userptr_t)cur_ptr, sizeof(userptr_t) * (argc+1) ); if(result != 0){ return result; } as_destroy(curproc_as); kfree(arg_offsets); kfree(arg_offsets_up); kfree(argv); kfree(args_ptrs); kfree(prog_name); enter_new_process(argc /*argc*/, (userptr_t)cur_ptr /*userspace addr of argv*/, cur_ptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; //return 0; }
/* * Load program "progname" and start running it in usermode. * Does not return except on error. * * Calls vfs_open on progname and thus may destroy it. */ int runprogram(char *progname, char **args, unsigned int nargs) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; int argc = nargs; char **argv = (char **)kmalloc((argc + 1) * sizeof(char *)); if(argv == NULL) { return ENOMEM; } for(int i = 0; i < argc; ++i) { argv[i] = args[i]; } argv[argc] = NULL; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(curproc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } /*------copy args to user stack-----------*/ vaddr_t *argPtrs = (vaddr_t *)kmalloc((argc + 1) * sizeof(vaddr_t)); if(argPtrs == NULL) { for(int i = 0; i < argc; ++i) { kfree(argv[i]); } kfree(argv); as_deactivate(); as = curproc_setas(NULL); as_destroy(as); return ENOMEM; } for(int i = argc-1; i >= 0; --i) { //arg length with null size_t curArgLen = strlen(argv[i]) + 1; size_t argLen = ROUNDUP(curArgLen,4); stackptr -= (argLen * sizeof(char)); //kprintf("copying arg: %s to addr: %p\n", temp, (void *)stackptr); //copy to stack result = copyout((void *) argv[i], (userptr_t)stackptr, curArgLen); if(result) { kfree(argPtrs); for(int i = 0; i < argc; ++i) { kfree(argv[i]); } kfree(argv); as_deactivate(); as = curproc_setas(NULL); as_destroy(as); return result; } argPtrs[i] = stackptr; } argPtrs[argc] = (vaddr_t)NULL; //copy arg pointers for(int i = argc; i >= 0; --i) { stackptr -= sizeof(vaddr_t); result = copyout((void *) &argPtrs[i], ((userptr_t)stackptr),sizeof(vaddr_t)); if(result) { kfree(argPtrs); for(int i = 0; i < argc; ++i) { kfree(argv[i]); } kfree(argv); as_deactivate(); as = curproc_setas(NULL); as_destroy(as); return result; } } kfree(argPtrs); vaddr_t baseAddress = USERSTACK; vaddr_t argvPtr = stackptr; vaddr_t offset = ROUNDUP(USERSTACK - stackptr,8); stackptr = baseAddress - offset; /* for(vaddr_t i = baseAddress; i >= stackptr; --i) { char *temp; temp = (char *)i; //kprintf("%p: %c\n",(void *)i,*temp); kprintf("%p: %x\n", (void *)i, *temp & 0xff); } */ /*-done-copy args to user stack-----------*/ /* Warp to user mode. */ enter_new_process(argc /*argc*/, (userptr_t)argvPtr /*userspace addr of argv*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
runprogram(char *progname) #endif { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; //kprintf("bla0\n"); /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } //kprintf("bla1\n"); /* We should be a new process. */ KASSERT(curproc_getas() == NULL); //kprintf("bla2\n"); /* Create a new address space. */ as = as_create(); if (as ==NULL) { vfs_close(v); return ENOMEM; } //kprintf("bla3\n"); /* Switch to it and activate it. */ curproc_setas(as); as_activate(); //kprintf("bla4\n"); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } //kprintf("bla5\n"); /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } #if OPT_A2 //kprintf("bla6\n"); if(args == NULL){ return EFAULT; } // copy args to user size_t len = sizeof(char *) * (num + 1); char **copyargs = kmalloc(len); for(unsigned long int i = 0; i < num; i++){ len = strlen(args[i]) + 1; stackptr = stackptr - ROUNDUP(len, 8);//? limit or valid stackptr //new result = copyoutstr(args[i], (userptr_t)stackptr, len, NULL);//new if(result){ kfree(copyargs); return result; } copyargs[i] = (char *)stackptr; } copyargs[num] = NULL; // copy arr len = sizeof(char *) * (num + 1); stackptr = stackptr - ROUNDUP(len, 8); result = copyout(copyargs, (userptr_t)stackptr, len); kfree(copyargs); if(result){ return result; } userptr_t stackk = (userptr_t)stackptr; enter_new_process(num /*argc*/, stackk /*userspace addr of argv*/, stackptr, entrypoint); #else /* Warp to user mode. */ enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/, stackptr, entrypoint); #endif /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
/* * Load program "progname" and start running it in usermode. * Does not return except on error. * * Calls vfs_open on progname and thus may destroy it. */ int runprogram(char *progname, char** args, size_t nargs) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; int argc = 0; while(args[argc] != NULL) { argc++; } /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(curproc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } #if OPT_A2 while(stackptr %8 != 0) stackptr--; vaddr_t argptr[argc + 1]; for (int i = argc - 1; i >= 0; i--) { stackptr -= strlen(args[i]) + 1; result = copyoutstr(args[i], (userptr_t) stackptr, strlen(args[i]) + 1, NULL); if(result) return result; argptr[i] = stackptr; } while(stackptr % 4 != 0) stackptr--; //int hack = (int) nargs; argptr[nargs] = 0; for (int i = argc; i >= 0; i--) { stackptr -= ROUNDUP(sizeof(vaddr_t), 4); result = copyout(&argptr[i], (userptr_t) stackptr, sizeof(vaddr_t)); if(result) return result; } #endif /* Warp to user mode. */ enter_new_process(nargs /*argc*/, (userptr_t) stackptr /*userspace addr of argv*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
paddr_t coremap_getFrames(unsigned long n, bool swappable, int seg_type) { paddr_t paddr; paddr = 0; // requesting too many pages if(n*PAGE_SIZE + lo_paddr > hi_paddr) { paddr = 0; } (void) seg_type; struct coremap_entry ** coremap = get_global_coremap(); // grab lock for synchronization lock_acquire(coremap_lk); for(unsigned int i = 0; i < max_pages; i++) { if(!coremap[i]->cm_occupied) { // set in page table global_coremap[i]; bool lengthFree = true; // try and find n continous frames for(unsigned int j = i + 1; (j < i + n) && (j < max_pages); j++) { // if its not n continous frames if(coremap[j]->cm_occupied) { lengthFree = false; break; } } // after found n continous frames, allocate them if(lengthFree && (i + n < max_pages)) { paddr = coremap[i]->cm_paddr; for(unsigned int j = i; j < i + n; j++) { coremap[j]->cm_occupied = true; coremap[j]->cm_length = n - (j - i); coremap[j]->cm_proc = curproc; coremap[j]->cm_swappable = swappable; coremap[j]->seg_type = seg_type; } lock_release(coremap_lk); return paddr; } } } // if paddr = 0 at this point, we want to evict something // from physical memory struct addrspace *as; as = curproc_getas(); if(as == NULL) { // debug // printCoremap(); } // else the coremap is full struct pt_entry* pte; if(paddr == 0){ // find a page victim pte = Pvictim(as, seg_type); // claim it coremap[pte->cm_index]->cm_proc = curproc; coremap[pte->cm_index]->cm_swappable = swappable; paddr = coremap[pte->cm_index]->cm_paddr; lock_release(coremap_lk); // write it to the swapfile write_to_swap(pte); } return paddr; }
int sys_write(int fd, const void *buf, size_t nbytes) { if (!buf || buf == NULL || !valid_address_check(curproc->p_addrspace, (vaddr_t)buf)){ // invalid buffer OR buffer out of range errno = EFAULT; return -1; } if(fd < 0 || fd >= MAX_fd_table){ errno = EBADF; return -1; } else if (fd == STDIN_FILENO){ // fd == STDIN_FILENO errno = EIO; return -1; } else if (fd >= 3 && fd < MAX_fd_table){ // have valid fd struct fd* tmp = curproc->fd_table[fd]; // if (tmp == NULL || (tmp->file_flag & O_RDONLY)){ // but have no file at fd OR file at fd is RDONLY if (tmp == NULL){ errno = EBADF; return -1; } switch(tmp->file_flag & O_ACCMODE){ case O_WRONLY: break; case O_RDWR: break; default: errno = EBADF; return -1; } } struct vnode *vn; // creating vnode (temp) struct uio u; struct iovec iov; struct addrspace *as; as = as_create(); iov.iov_ubase = (void *)buf; iov.iov_len = nbytes; u.uio_iov = &iov; u.uio_resid = nbytes; u.uio_rw = UIO_WRITE; u.uio_segflg = UIO_USERSPACE; u.uio_space = curproc_getas(); if(fd == STDOUT_FILENO || fd == STDERR_FILENO){ char *console = NULL; // console string ("con:") console = kstrdup("con:"); // set to console vfs_open(console,O_WRONLY,0,&vn); // open the console vnode kfree(console); // free the console int result = VOP_WRITE(vn,&u); if(result < 0){ errno = EIO; //A hardware I/O error occurred writing the data return -1; } } else{ u.uio_offset = curproc->fd_table[fd]->offset; VOP_WRITE(curproc->fd_table[fd]->file, &u); if(u.uio_resid){ errno = ENOSPC; //There is no free space remaining on the filesystem containing the file return -1; } curproc->fd_table[fd]->offset += nbytes - u.uio_resid; curproc->fd_table[fd]->buflen += nbytes - u.uio_resid; //update buflength of fd } return nbytes - u.uio_resid; }
int runprogram(char *progname, unsigned long argc, char **argv) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(curproc_getas() == NULL); /* Create a new address space. */ #if OPT_A3 as = as_create(progname); #else as = as_create(); #endif if (as ==NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ curproc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(as, &stackptr); // find the stack pointer if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } //add stuff stackptr = stackptr - (argc + 1)*sizeof(vaddr_t); //subtract number of arguments + 1 (space for pointers) unsigned long i; unsigned int len; unsigned int len2; char **buf = (char **)stackptr; // argv for(i=0; i<argc; i++){ len = (strlen(argv[i])+1)*(sizeof(char)); // first str length + null char stackptr = stackptr - len; // adjust stack pointer for length of str buf[i] = (char*)stackptr; // assign pointer to argv[i] copyoutstr((void *)argv[i],(userptr_t)buf[i],len,&len2); // copy to userstack } unsigned int remainder = stackptr % 8; if(remainder != 0){ stackptr = stackptr - remainder; } // pass arguments to user program /* Warp to user mode. */ enter_new_process(argc, (userptr_t)buf /*userspace addr of argv*/, stackptr, entrypoint); // stores into trap->a0 as argc // stores trap->a1 as argv // sets stack pointer /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
int sys_execv(userptr_t progname, userptr_t args) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; char * path = kmalloc(PATH_MAX); as = curproc_getas(); if (as != NULL && !valid_address_check(as, (vaddr_t)args)) { // out of vaddr boundary for this proc errno = EFAULT; return -1; } if (as != NULL && !valid_address_check(as, (vaddr_t)progname)) { // out of vaddr boundary for this proc errno = EFAULT; return -1; } result = copyinstr(progname, path, PATH_MAX, NULL); if(result) { return result; } if(*path == '\0') { errno = EISDIR; return -1; } // Open the executable, create a new address space and load the elf into it result = vfs_open((char *)path, O_RDONLY, 0, &v); if (result) { return result; } // KASSERT(curproc_getas() == NULL); as = as_create(); if (as == NULL) { vfs_close(v); return ENOMEM; } curproc_setas(as); as_activate(); result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); return result; } vfs_close(v); result = as_define_stack(as, &stackptr); // stackptr set if (result) { /* p_addrspace will go away when curproc is destroyed */ return result; } kfree(path); userptr_t karg, uargs, argbase; char * buffer, * bufend; buffer = kmalloc(sizeof(ARG_MAX)); if(buffer == NULL) { errno = ENOMEM; return -1; } bufend = buffer; size_t resid, bufsize; size_t alen; size_t *offsets = kmalloc(NARG_MAX * sizeof(size_t)); if(offsets == NULL) { errno = ENOMEM; return -1; } int size = 0; userptr_t arg; resid = bufsize = ARG_MAX; for(int i = 0 ; i < NARG_MAX ; i++) { // copyin from user. copyin(args, &karg, sizeof(userptr_t)); // copy the pointer. if(karg == NULL) break; // if NULL, break. copyinstr(karg, bufend, resid, &alen); offsets[i] = bufsize - resid; bufend += alen; resid -= alen; args += sizeof(userptr_t); size++; } size_t buflen = bufend - buffer; // length of buffer. vaddr_t stack = stackptr - buflen; // current stack position. stack -= (stack & (sizeof(void *) - 1)); // alignment argbase = (userptr_t)stack; // argbase. copyout(buffer, argbase, buflen); // copy the arguments into stack. stack -= (size + 1)*sizeof(userptr_t); // go to array pointer (bottom of stack). uargs = (userptr_t)stack; // got stack. for(int i = 0 ; i < size ; i++) { // copy the elements arg = argbase + offsets[i]; copyout(&arg, uargs, sizeof(userptr_t)); uargs += sizeof(userptr_t); // 4 } arg = NULL; copyout(&arg, uargs, sizeof(userptr_t)); // copy the NULL pointer. kfree(buffer); kfree(offsets); enter_new_process(size /*argc*/, (userptr_t)stack /*userspace addr of argv*/, stack, entrypoint); return 0; }