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; }
/** Parse an executable image in the kernel memory. * * If the image belongs to a program loader, it is registered as such, * (and *task is set to NULL). Otherwise a task is created from the * executable image. The task is returned in *task. * * @param[in] image_addr Address of an executable program image. * @param[in] name Name to set for the program's task. * @param[out] prg Buffer for storing program info. * If image_addr points to a loader image, * prg->task will be set to NULL and EOK * will be returned. * * @return EOK on success or negative error code. * */ int program_create_from_image(void *image_addr, char *name, program_t *prg) { as_t *as = as_create(0); if (!as) return ENOMEM; prg->loader_status = elf_load((elf_header_t *) image_addr, as, 0); if (prg->loader_status != EE_OK) { as_destroy(as); prg->task = NULL; prg->main_thread = NULL; if (prg->loader_status != EE_LOADER) return ENOTSUP; /* Register image as the program loader */ if (program_loader != NULL) return ELIMIT; program_loader = image_addr; printf("Program loader at %p\n", (void *) image_addr); return EOK; } return program_create(as, ((elf_header_t *) image_addr)->e_entry, name, prg); }
int main(int argc, const char *argv[]) { const int StacksNo = 2; Stack *stacks[StacksNo]; stacks[0] = ls_create(sizeof(int), 5); stacks[1] = as_create(sizeof(int), 5); int stackIt = 0; for (stackIt = 0; stackIt < StacksNo; ++stackIt) { Stack *s = stacks[stackIt]; int i = 0; for (i = 0; i < 8; ++i) { if (0 != s->push(s, &i)) { fprintf(stderr, "Error on pushing %d\n", i); } } int peekData; int data; while (0 != s->size(s)) { s->peek(s, &peekData); if (0 == s->pop(s, &data)) { printf("Popped %d, peeked %d\n", data, peekData); } else { fprintf(stderr, "Cannot get element\n"); } } } return 0; }
Datum adaptive_counter_update(PG_FUNCTION_ARGS) { bytea * data; AdaptiveCounter ac; /* is the counter created (if not, create it - error 1%, 10mil items) */ if (PG_ARGISNULL(0)) { ac = as_create(0.01, 4); data = (bytea*)palloc(ac->length + VARHDRSZ); SET_VARSIZE(data, ac->length); memcpy(VARDATA(data), ac, ac->length); elog(NOTICE, "Adaptive Counter: %d bytes", ac->length); } else { data = PG_GETARG_BYTEA_P(0); } ac = (AdaptiveCounter)VARDATA(data); /* get the new item */ text * item = PG_GETARG_TEXT_P(1); /* in-place update works only if executed as aggregate */ as_add_element(ac, VARDATA(item), VARSIZE(item) - VARHDRSZ); /* return the updated bytea */ PG_RETURN_BYTEA_P(data); }
/** Create a task from the program loader image. * * @param prg Buffer for storing program info. * @param name Name to set for the program's task. * * @return EOK on success or negative error code. * */ int program_create_loader(program_t *prg, char *name) { as_t *as = as_create(0); if (!as) return ENOMEM; void *loader = program_loader; if (!loader) { as_destroy(as); printf("Cannot spawn loader as none was registered\n"); return ENOENT; } prg->loader_status = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER); if (prg->loader_status != EE_OK) { as_destroy(as); printf("Cannot spawn loader (%s)\n", elf_error(prg->loader_status)); return ENOENT; } return program_create(as, ((elf_header_t *) program_loader)->e_entry, name, prg); }
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 ; }
/* * 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) { 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 thread. */ KASSERT(curthread->t_addrspace == NULL); /* Create a new address space. */ curthread->t_addrspace = as_create(); if (curthread->t_addrspace==NULL) { vfs_close(v); return ENOMEM; } curthread->t_filetable = filetable_create(); if(curthread->t_filetable == NULL){ return ENOMEM; } /* Activate it. */ as_activate(curthread->t_addrspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_addrspace */ 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(curthread->t_addrspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_addrspace */ 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; }
/* * 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) { struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Open the file. */ result = vfs_open(progname, O_RDONLY, &v); if (result) { return result; } /* We should be a new thread. */ assert(curthread->t_vmspace == NULL); /* Create a new address space. */ curthread->t_vmspace = as_create(); if (curthread->t_vmspace==NULL) { vfs_close(v); return ENOMEM; } //kprintf("\n in runprogram"); assignPid(); /* Activate it. */ as_activate(curthread->t_vmspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_vmspace */ 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(curthread->t_vmspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_vmspace */ return result; } /* Warp to user mode. */ md_usermode(0 /*argc*/, NULL /*userspace addr of argv*/, stackptr, entrypoint); /* md_usermode does not return */ panic("md_usermode returned\n"); return EINVAL; }
/* * as_copy: duplicate an address space. Creates a new address space and * copies each vm_object in the source address space into the new one. * Implements the VM system part of fork(). * * Synchronization: none. */ int as_copy(struct addrspace *as, struct addrspace **ret) { struct addrspace *newas; struct vm_object *vmo, *newvmo; int i, result; newas = as_create(); if (newas==NULL) { return ENOMEM; } /* * We assume that as belongs to curthread, and furthermore that * it's not shared with any other threads. (The latter restriction * is easily lifted; the former is not.) * * We assume that nothing is going to modify the source address * space except for the usual page evictions by other processes. */ assert(as==curthread->t_vmspace); /* copy the vmos */ for (i = 0; i < array_getnum(as->as_objects); i++) { vmo = array_getguy(as->as_objects, i); result = vm_object_copy(vmo, newas, &newvmo); if (result) { goto fail; } result = array_add(newas->as_objects, newvmo); if (result) { vm_object_destroy(newas, newvmo); goto fail; } } *ret = newas; return 0; fail: as_destroy(newas); return result; }
int as_copy(struct addrspace *old, struct addrspace **ret) { struct addrspace *newas; newas = as_create(); if (newas==NULL) { return ENOMEM; } /* * Write this. */ (void)old; *ret = newas; return 0; }
int as_copy(struct addrspace *old, struct addrspace **ret) { struct addrspace *newas; newas = as_create(); if (newas==NULL) { return ENOMEM; } /* * Write this. */ //dont worry until end, uses fork (void)old; *ret = newas; return 0; }
int as_copy(struct addrspace *old, struct addrspace **ret, pid_t pid) { struct addrspace *newas; struct page *newpage, *page; int i; int nindex, oindex; paddr_t nf, of; newas = as_create(); if (newas==NULL) { return ENOMEM; } for(i=0;i<array_getnum(old->pages);i++) { newpage = (struct page *) kmalloc(sizeof(struct page)); if (newpage==NULL) return ENOMEM; page = (struct page *) array_getguy(old->pages, i); memcpy(newpage, page, sizeof(struct page)); array_add(newas->pages, newpage); oindex = getindex(newpage->vaddr); of = FRAME(oindex); nindex = addpage(newpage->vaddr, pid, newpage->perms & P_R_B, newpage->perms & P_W_B, newpage->perms & P_X_B, PADDR_TO_KVADDR(of)); } *ret = newas; return 0; }
int sys_fork(struct trapframe *tf,struct addrspace *parent_addr_space){ //kprintf("\n in sys_fork"); struct thread *child_thread=NULL; struct thread *test; struct addrspace *parent_addr_space_copy; //create a new address space //kprintf("\n in sys_fork:creating new addr space"); parent_addr_space_copy=as_create(); if(parent_addr_space_copy==NULL) return ENOMEM; //make a copy of the parent's address space //kprintf("\n in sys_fork:copying to the addr space %x",parent_addr_space); as_copy(parent_addr_space,&parent_addr_space_copy); //kprintf("\n in sys_fork:copying to the addr space %x",*(parent_addr_space_copy)); //make a copy of the parent`s trapframe on kernel heap //kprintf("\n in sys_fork:copying trap frame"); struct trapframe *tf_temp=kmalloc(sizeof(struct trapframe)); if(tf_temp==NULL){ kfree(tf_temp); return ENOMEM; } memcpy(tf_temp,tf,sizeof(struct trapframe)); //call thread_fork //pass the trapframe and the address space of the parent to the child`s thread_fork //kprintf("\n in sys_fork:forking"); thread_fork("child thread",tf_temp,(unsigned long)parent_addr_space_copy,md_forkentry,&child_thread); //kprintf("\nchild_thread::%x",*(child_thread)); //copy other required stuff and return with child`s pid //test=(child_thread); return child_thread->pid; }
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(char* program, char** args) { int result; char name[strlen(program) + 1]; result = copyin((userptr_t) program, name, (strlen(program) + 1) * sizeof(char)); //kprintf("%s", name); int len_arg = 0; while(args[len_arg] != NULL) { len_arg++; } int length_every_arg[len_arg]; for(int i = 0; i < len_arg; i++) { length_every_arg[i] = strlen(args[i]); } char* kern_args[len_arg]; for(int i = 0; i < len_arg; i++) { kern_args[i] = kmalloc(sizeof(char) * length_every_arg[i] + 1); copyin((const_userptr_t)args[i], kern_args[i], (length_every_arg[i] + 1) * sizeof(char)); } /* for(int i = 0; i < len_arg; i++) { kprintf("{ _%d__%p__%p_",strlen(kern_args[i]), kern_args[i],args[i]); kprintf("%s", kern_args[i]); kprintf("}\n"); } */ ///////////////////////////////////////////////////// // this is "copied" from runprogram struct addrspace* old_as; struct vnode* v; vaddr_t entrypoint, stackptr; result = vfs_open(program, O_RDONLY, 0, &v); if(result) { return result; } as_deactivate(); old_as = curproc_setas(NULL); as_destroy(old_as); struct addrspace* new_as = as_create(); if(new_as == NULL) { vfs_close(v); return ENOMEM; } curproc_setas(new_as); as_activate(); result = load_elf(v, &entrypoint); if(result) { vfs_close(v); return result; } vfs_close(v); result = as_define_stack(new_as, &stackptr); if(result) { return result; } ////////////////////////////////////////////////////////// // kern_args // the addr of stackptr is 0x8000 0000 vaddr_t argv = stackptr; for(int i = 0; i < len_arg + 1; i++) { argv = argv - 4; } vaddr_t start = argv; vaddr_t temp = argv; copyout(NULL, (userptr_t)(stackptr - 4), 4); //starts from 1, because argv[0] is reserved for the program name for(int i = 0; i < len_arg; i++) { //question? why do I have to add 2 int m = sizeof(char) * (strlen(kern_args[i]) + 1); // kprintf("the value of m -> %d\n", m); argv = argv - m; copyout(kern_args[i], (userptr_t)argv, m); // kprintf("***(%d)%s(%p)\n***", m, (char* )argv, (void *) argv); copyout(&argv, (userptr_t)temp, sizeof(char* )); temp = temp + 4; } for(int i = 0; i < len_arg; i++) { kfree(kern_args[i]); } while(argv % 8 != 0) {argv--;} enter_new_process(len_arg, (userptr_t)start, (vaddr_t) argv, entrypoint); // enter_new_process(0, NULL, stackptr, entrypoint); panic("enter_new_process returned"); return EINVAL; }
int sys_execv(char* progname, char** args, int *retval, bool iskernel) { int result; int *args_len; size_t len; size_t total_len = 0; char *temp; char **kern_args; int nargs = 0; userptr_t *usr_argv = NULL; char *kern_progname = kmalloc(PATH_MAX); args_len = kmalloc(sizeof(int) * ARG_MAX); temp = kmalloc(sizeof(char) * ARG_MAX); if (kern_progname == NULL || args_len == NULL || temp == NULL){ *retval = -1; return ENOMEM; } if (args == NULL || progname == NULL) { *retval = -1; return EFAULT; } if (!iskernel) { result = copyinstr((userptr_t)args, temp, ARG_MAX, &len); if (result) { *retval = -1; return result; } } // Figure out nargs, and the length for each arg string while(args[nargs] != NULL) { if (iskernel) { len = strlen(args[nargs]) + 1; if (len == 1) { nargs--; break; } strcpy(temp, args[nargs]); } else { result = copyinstr((userptr_t)args[nargs], temp, ARG_MAX, &len); if (result) { *retval = -1; return result; } } args_len[nargs] = len; total_len += len; nargs += 1; } kfree(temp); if (total_len > ARG_MAX) { *retval = -1; return E2BIG; } kern_args = kmalloc(sizeof(char*) * nargs); // Go through args and copy everything over to kern_args using copyinstr for (int i = 0; i < nargs; i++) { kern_args[i] = kmalloc(sizeof(char) * args_len[i]); if (kern_args[i] == NULL) { *retval = -1; return ENOMEM; } if (iskernel) { strcpy(kern_args[i], args[i]); len = strlen(kern_args[i]); } else { copyinstr((userptr_t)args[i], kern_args[i], ARG_MAX, NULL); } } // This is from runprogram struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; if (iskernel) { strcpy(kern_progname, progname); len = strlen(kern_progname); } else { result = copyinstr((userptr_t)progname, kern_progname, PATH_MAX, NULL); } if (*kern_progname == 0) { *retval = -1; return EISDIR; } if (result) { kfree(kern_progname); *retval = -1; return result; } /* Open the file. */ result = vfs_open(kern_progname, O_RDONLY, 0, &v); if (result) { *retval = -1; return result; } // Blow up the current addrspace. TODO, this may be problematic if (!iskernel) { as_destroy(curproc->p_addrspace); curproc->p_addrspace = NULL; } /* We should be a new process. */ KASSERT(proc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as == NULL) { vfs_close(v); *retval = -1; return ENOMEM; } /* Switch to it and activate it. */ proc_setas(as); as_activate(); /* Intialize file table, not needed for execv */ if (iskernel) filetable_init(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ vfs_close(v); *retval = -1; 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 */ *retval = -1; return result; } // Clear space for arg pointers +1 for NULL terminator stackptr -= (sizeof(char*)) * (nargs + 1); // Convenience method for indexing usr_argv = (userptr_t*)stackptr; for(int i = 0; i < nargs; i++ ) { // Clear out space for an arg string stackptr -= sizeof(char) * (strlen(kern_args[i]) + 1); // Assign the string's pointer to usr_argv usr_argv[i] = (userptr_t)stackptr; // Copy over string copyout(kern_args[i], usr_argv[i], sizeof(char) * (strlen(kern_args[i]) + 1)); } // NULL terminate usr_argv usr_argv[nargs] = NULL; // Free memory for(int i = 0; i < nargs; i++) { kfree(kern_args[i]); } kfree(kern_args); /* Warp to user mode. */ enter_new_process(nargs /*argc*/, (userptr_t)usr_argv /*userspace addr of argv*/, NULL /*userspace addr of environment*/, stackptr, entrypoint); /* 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; }
int sys_execv( userptr_t upname, userptr_t uargs ) { struct addrspace *as_new = NULL; struct addrspace *as_old = NULL; struct vnode *vn = NULL; vaddr_t entry_ptr; vaddr_t stack_ptr; int err; char kpname[MAX_PROG_NAME]; int nargs; int buflen; KASSERT( curthread != NULL ); KASSERT( curthread->td_proc != NULL ); (void)uargs; //lock the execv args lock_acquire( lk_exec ); //copy the old addrspace just in case. as_old = curthread->t_addrspace; //copyin the program name. err = copyinstr( upname, kpname, sizeof( kpname ), NULL ); if( err ) { lock_release( lk_exec ); return err; } //try to open the given executable. err = vfs_open( kpname, O_RDONLY, 0, &vn ); if( err ) { lock_release( lk_exec ); return err; } //copy the arguments into the kernel buffer. err = copy_args( uargs, &nargs, &buflen ); if( err ) { lock_release( lk_exec ); vfs_close( vn ); return err; } //create the new addrspace. as_new = as_create(); if( as_new == NULL ) { lock_release( lk_exec ); vfs_close( vn ); return ENOMEM; } //activate the new addrspace. as_activate( as_new ); //temporarily switch the addrspaces. curthread->t_addrspace = as_new; //load the elf executable. err = load_elf( vn, &entry_ptr ); if( err ) { curthread->t_addrspace = as_old; as_activate( as_old ); as_destroy( as_new ); vfs_close( vn ); lock_release( lk_exec ); return err; } //create a stack for the new addrspace. err = as_define_stack( as_new, &stack_ptr ); if( err ) { curthread->t_addrspace = as_old; as_activate( as_old ); as_destroy( as_new ); vfs_close( vn ); lock_release( lk_exec ); return err; } //adjust the stackptr to reflect the change stack_ptr -= buflen; err = adjust_kargbuf( nargs, stack_ptr ); if( err ) { curthread->t_addrspace = as_old; as_activate( as_old ); as_destroy( as_new ); vfs_close( vn ); lock_release( lk_exec ); return err; } //copy the arguments into the new user stack. err = copyout( kargbuf, (userptr_t)stack_ptr, buflen ); if( err ) { curthread->t_addrspace = as_old; as_activate( as_old ); as_destroy( as_new ); vfs_close( vn ); lock_release( lk_exec ); return err; } //reelase lk_exec lock_release( lk_exec ); //no need for it anymore. vfs_close( vn ); //we are good to go. as_destroy( as_old ); //off we go to userland. enter_new_process( nargs-1, (userptr_t)stack_ptr, stack_ptr, entry_ptr ); panic( "execv: we should not be here." ); 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 **argv, unsigned long argc) { struct vnode *v; vaddr_t entrypoint, stackptr; int result; pid_t pidRetVal; /* Open the file. */ result = vfs_open(progname, O_RDONLY, &v); if (result) { return result; } /* We should be a new thread. */ assert(curthread->t_vmspace == NULL); /* Create filetable for process*/ curthread->ft = create_process_filetable(); if(curthread->ft == NULL) { vfs_close(v); return ENOMEM; } /* Initialize STDIN, STDOUT, STDERR */ struct ft_node* standardIn = create_ft_node(); struct ft_node* standardOut = create_ft_node(); struct ft_node* standardErr = create_ft_node(); char console1[] = "con:"; result = vfs_open(console1, O_RDONLY, &standardIn->v); if(result) { kprintf("Cannot open STDIN\n"); vfs_close(v); return result; } standardIn->mode = O_RDONLY; array_add(curthread->ft->file_descriptors, standardIn); char console2[] = "con:"; result = vfs_open(console2, O_WRONLY, &standardOut->v); if(result) { kprintf("Cannot open STDOUT\n"); vfs_close(v); return result; } standardOut->mode = O_WRONLY; array_add(curthread->ft->file_descriptors, standardOut); char console3[] = "con:"; result = vfs_open(console3, O_WRONLY, &standardErr->v); if(result) { kprintf("Cannot open STDERR\n"); vfs_close(v); return result; } standardErr->mode = O_WRONLY; array_add(curthread->ft->file_descriptors, standardErr); /* Allocate initial PID for this first program */ result = allocate_pid(&pidRetVal); if(result) { kprintf("Could not allocate PID\n"); vfs_close(v); return result; } curthread->PID = pidRetVal; ((struct p_node *)array_getguy(pid_table, curthread->PID))->is_interested = 0; /* Create a new address space. */ curthread->t_vmspace = as_create(); if (curthread->t_vmspace==NULL) { vfs_close(v); return ENOMEM; } /* Activate it. */ as_activate(curthread->t_vmspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_vmspace */ vfs_close(v); return result; } //kprintf("finished loadelf in runprog\n"); /* Done with the file now. */ vfs_close(v); /* Define the user stack in the address space */ result = as_define_stack(curthread->t_vmspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_vmspace */ return result; } vaddr_t stackptrv[argc+1]; int i; size_t actual; for(i = argc-1; i >= 0; i--) { int len = strlen(argv[i]); len++; int padding = len % 4; stackptr -= len + (4 - padding); result = copyoutstr(argv[i], (userptr_t)stackptr, len, &actual); if(result) { return result; } stackptrv[i] = stackptr; } stackptrv[argc] = 0; for(i = argc; i >= 0; i--) { stackptr -= sizeof(vaddr_t); result = copyout(&stackptrv[i], (userptr_t)stackptr, sizeof(vaddr_t)); if(result) { return result; } } //kprintf("Before usernmode\n"); /* Warp to user mode. */ md_usermode(argc /*argc*/, (userptr_t)stackptr /*userspace addr of argv*/, stackptr, entrypoint); /* md_usermode does not return */ panic("md_usermode returned\n"); return EINVAL; }
int sys_execv(const_userptr_t path, const_userptr_t argv) { int err; struct process *proc = curthread->t_proc; char *kpath = kmalloc(PATH_MAX); if (kpath == NULL) return ENOMEM; // copy in path size_t path_len; if ((err = copyinstr(path, kpath, PATH_MAX, &path_len))) { kfree(kpath); return err; } // give the process a new name char *old_name = proc->ps_name; proc->ps_name = kstrdup(kpath); if (proc->ps_name == NULL) { proc->ps_name = old_name; kfree(kpath); return ENOMEM; } // copy in args size_t argc; size_t total_len; char **kargv = kmalloc((ARGNUM_MAX + 1) * sizeof(char *)); err = copyinargs(argv, kargv, &argc, &total_len); if (err) { kfree(proc->ps_name); proc->ps_name = old_name; kfree(kpath); return err; } // Open the file. struct vnode *v; err = vfs_open(kpath, O_RDONLY, 0, &v); kfree(kpath); if (err) { free_kargv(kargv); kfree(proc->ps_name); proc->ps_name = old_name; return err; } // set up new address space struct addrspace *old_as = curthread->t_proc->ps_addrspace; struct addrspace *as = as_create(); if (as == NULL) { vfs_close(v); free_kargv(kargv); kfree(proc->ps_name); proc->ps_name = old_name; return ENOMEM; } proc->ps_addrspace = as; // Activate the new address space as_activate(as); vaddr_t entrypoint; err = load_elf(v, &entrypoint); if (err) { proc->ps_addrspace = old_as; as_activate(old_as); as_destroy(as); vfs_close(v); free_kargv(kargv); kfree(proc->ps_name); proc->ps_name = old_name; return err; } // close the file now, since we will not be returning // here from user mode. vfs_close(v); // set up user stack vaddr_t stackptr; err = as_define_stack(as, &stackptr); if (err) { proc->ps_addrspace = old_as; as_activate(old_as); as_destroy(as); free_kargv(kargv); kfree(proc->ps_name); proc->ps_name = old_name; return err; } // copy arguments at base of stack stackptr -= total_len; stackptr -= (argc + 1) * sizeof(userptr_t); err = copyoutargs((userptr_t)stackptr, kargv, argc, total_len); if (err) { proc->ps_addrspace = old_as; as_activate(old_as); as_destroy(as); free_kargv(kargv); kfree(proc->ps_name); proc->ps_name = old_name; return err; } // destroy old address space and free memory // that we will no longer need as_destroy(old_as); kfree(old_name); // Warp to user mode enter_new_process(argc, (userptr_t)stackptr, stackptr, entrypoint); // 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, 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; }
int as_copy(struct addrspace *old, struct addrspace **ret) { int spl = splhigh(); struct addrspace *newas; newas = as_create(); if (newas == NULL) { return ENOMEM; } /******************** copy internal fields ***************/ // first all regions unsigned int i; for (i = 0; i < array_getnum(old->as_regions); i++) { struct as_region* temp = kmalloc(sizeof(struct as_region)); *temp = *((struct as_region*)array_getguy(old->as_regions, i)); array_add(newas->as_regions, temp); } newas->heap_start = old->heap_start; newas->heap_end = old->heap_end; newas->temp_text_permis = old->temp_text_permis; newas->temp_bss_permis = old->temp_bss_permis; // then both the first and second page table for (i = 0; i < FIRST_LEVEL_PT_SIZE; i++) { if(old->as_master_pagetable[i] != NULL) { newas->as_master_pagetable[i] = (struct as_pagetable*)kmalloc(sizeof(struct as_pagetable)); // what the f**k am i doing? // the right thing to do here is to go through all PTEs of the old addrspace, if there's a // valid PTE, meaning there's a page, be it PRESENT or SWAPPED, belonging to this addrspace. struct as_pagetable *src_pt = old->as_master_pagetable[i]; struct as_pagetable *dest_pt = newas->as_master_pagetable[i]; unsigned int j = 0; for (; j < SECOND_LEVEL_PT_SIZE; j++) { dest_pt->PTE[j] = 0; if(src_pt->PTE[j] & PTE_PRESENT) { // this source page is PRESENT in memory, we just allocate a page for // the destination addrspace and copy src->dest and update PTE paddr_t src_paddr = (src_pt->PTE[j] & PAGE_FRAME); vaddr_t dest_vaddr = (i << 22) + (j << 12); // allocate a page for the destination addrspace, while making sure // that both the source and destination page are in memory paddr_t dest_paddr = alloc_page_userspace_with_avoidance(dest_vaddr, src_paddr); // sanity check // do the copy :) memmove((void *) PADDR_TO_KVADDR(dest_paddr), (const void*)PADDR_TO_KVADDR(src_paddr), PAGE_SIZE) ; // update the PTE of the destination pagetable // dest_pt->PTE[j] &= CLEAR_PAGE_FRAME; dest_pt->PTE[j] |= dest_paddr; dest_pt->PTE[j] |= PTE_PRESENT; } else if (src_pt->PTE[j] & PTE_SWAPPED){ // this source page is SWAPPED, we load it back to mem :) vaddr_t src_vaddr = (i << 22) + (j << 12); vaddr_t dest_vaddr = src_vaddr; paddr_t src_paddr = load_swapped_page(old, src_vaddr); // now allocate a user page, but becareful not to swap out the // source page we just brought in... paddr_t dest_paddr = alloc_page_userspace_with_avoidance(dest_vaddr, src_paddr); // do the copy memmove((void *) PADDR_TO_KVADDR(dest_paddr), (const void*)PADDR_TO_KVADDR(src_paddr), PAGE_SIZE) ; // update the PTE of the destination pagetable // dest_pt->PTE[j] &= CLEAR_PAGE_FRAME; dest_pt->PTE[j] |= dest_paddr; dest_pt->PTE[j] |= PTE_PRESENT; } else { // this source page is neither PRESENT nor SWAPPED, meaning this // page does not exist, we've got nothing to do in this case, nice :) dest_pt->PTE[j] = 0; } } } else { newas->as_master_pagetable[i] = NULL; } } *ret = newas; splx(spl); return 0; }
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 and start running it in usermode * in a new thread. * This is essentially an amalgam of fork() and execv(). */ int runprogram(int nargs, char **args, struct process **created_proc) { if (nargs > ARGNUM_MAX) return E2BIG; struct vnode *v; int result; struct process *proc; // copy the string, since vfs_open() will modify it char *progname = kstrdup(args[0]); if (progname == NULL) return ENOMEM; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } // We no longer need the duplicate program name kfree(progname); // set up new process structure proc = process_create(args[0]); if (proc == NULL) { vfs_close(v); return ENOMEM; } // Get a PID for the process. ENPROC is // the error code for "no more processes allowed // in the system." pid_t pid = process_identify(proc); if (pid == 0) { process_cleanup(proc); vfs_close(v); return ENPROC; } // Create a new file descriptor table proc->ps_fdt = fdt_create(); if (proc->ps_fdt == NULL) { process_destroy(pid); vfs_close(v); return ENOMEM; } // Open FDs for stdin, stdout, and stderr result = setup_inouterr(proc->ps_fdt); if (result) { process_destroy(pid); vfs_close(v); return result; } // Create a new address space proc->ps_addrspace = as_create(); if (proc->ps_addrspace==NULL) { process_destroy(pid); vfs_close(v); return ENOMEM; } struct new_process_context *ctxt = kmalloc(sizeof(struct new_process_context)); if (ctxt == NULL) { as_activate(NULL); process_destroy(pid); return ENOMEM; } ctxt->nargs = nargs; ctxt->args = args; ctxt->proc = proc; ctxt->executable = v; // Start a new thread to warp to user mode result = thread_fork("user process", run_process, ctxt, 0, NULL); if (result) { kfree(ctxt); as_activate(NULL); process_destroy(pid); return result; } // pass process to caller and return *created_proc = proc; return 0; }
int sys_execv(char* progname, char** args){ struct vnode *v; vaddr_t stackptr, entrypoint; int result; int string_size = 0; //s_size int kargc = 0; //kargc int err; char ** kernel_args; //kargs size_t check; //tt //CHECKS BEFORE WE BEGIN!! if(args == NULL) return EFAULT; if(progname == NULL) return ENOEXEC; struct addrspace* temp =(struct addrspace*)kmalloc(sizeof(struct addrspace)); if(temp == NULL) return ENOMEM; while(args[kargc] != NULL){ kargc++; } //Copy the address space to the one on the kernel heap. err = as_copy(curthread->t_vmspace, &(temp)); //If there is an error on copy. if(err){ kfree(temp); return ENOMEM; } //make a copy of the kernel args on the heap. kernel_args = (char **)kmalloc((kargc)*sizeof(char*)); if(kernel_args == NULL){ kfree(kernel_args); return ENOMEM; } int i,j; //Transfer the items passed in to the kernel heap array. for(i = 0; i<kargc; i++){ string_size = strlen(args[i]); kernel_args[i] =(char *)kmalloc(string_size * sizeof(char)); //If there is not enough memory... if(kernel_args[i]== NULL){ kfree(temp); for(j =0; j<i; j++){ kfree(kernel_args[j]); } kfree(kernel_args); return ENOMEM; } //If we get here, we have successfully copied the arguments. Copy in now. err = copyinstr(args[i], kernel_args[i], string_size+1, &check); //Check if copyinstr Success/Fail if(err){ for(i = 0; i<kargc; i++){ kfree(kernel_args[i]); } kfree(temp); kfree(kernel_args); return err; } } kernel_args[kargc]= NULL; //NOW, WE FOLLOW THE SAME PROCEDURE AS RUNPROGRAM!! /* Open the file. */ result = vfs_open(progname, O_RDONLY, &v); if (result) { kfree(temp); for(i = 0; i<kargc; i++) kfree(kernel_args[i]); kfree(kernel_args); return result; } //Destroy the old address space, and setup the new one! as_destroy(curthread->t_vmspace); curthread->t_vmspace = NULL; //Setup new vmspace. curthread->t_vmspace = as_create(); if (curthread->t_vmspace==NULL) { curthread->t_vmspace = temp; for(i = 0; i<kargc; i++) kfree(kernel_args[i]); kfree(kernel_args); vfs_close(v); return ENOMEM; } /* Activate vmspace */ as_activate(curthread->t_vmspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { as_destroy(curthread->t_vmspace); curthread->t_vmspace = temp; for(i = 0; i<kargc; i++) kfree(kernel_args[i]); kfree(kernel_args); vfs_close(v); return result; } /* Done with the file now. */ vfs_close(v); //We now prepare the user stack by placing the arguments on it, like we did in runprogram. result = as_define_stack(curthread->t_vmspace, &stackptr); //If error: if (result) { as_destroy(curthread->t_vmspace); curthread->t_vmspace = temp; for(i = 0; i<kargc; i++) kfree(kernel_args[i]); kfree(kernel_args); return result; } // new addr space user stack vaddr_t new_args[kargc]; int padding; /*place all the strings on the stack*/ for(i = (kargc-1); i>=0 ; i--){ string_size = strlen(kernel_args[i]); padding = ((string_size / 4 ) + 1)*4; stackptr = stackptr - padding; //Do a copyout and check if success/fail err = copyoutstr(kernel_args[i], stackptr, string_size+1, &check); if(err){ return err; } //Success! new_args[i] = stackptr; } new_args[kargc] = NULL; for(i = kargc-1; i>=0 ; i--){ stackptr= stackptr- 4; err = copyout(&(new_args[i]), stackptr, 4); if(err){ return err; } } for(i =0; i<kargc; i++){ kfree(kernel_args[i]); } kfree(temp); kfree(kernel_args); /* Warp to user mode. */ md_usermode(kargc, stackptr, stackptr, entrypoint); }
/* * 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, int argc, char** args) { 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 thread. */ KASSERT(curthread->t_addrspace == NULL); /* Create a new address space. */ curthread->t_addrspace = as_create(); if (curthread->t_addrspace==NULL) { vfs_close(v); return ENOMEM; } /* Activate it. */ as_activate(curthread->t_addrspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_addrspace */ 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(curthread->t_addrspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_addrspace */ return result; } /* Initialize an array of pointers that stores the pointer to the * string arguments in the user stack */ char** argv = (char **)kmalloc((argc + 1) * sizeof(char*)); if (argv == NULL) { return ENOMEM; } argv[argc] = 0; int i; size_t actual; int total = 0; /* Copy string arguments from kernel memory onto the user stack, * and store the user pointer to the argument in argv */ for (i = argc - 1; i >= 0; i--) { int len = strlen(args[i]) + 1; total = total + len; stackptr = stackptr - len; copyoutstr(args[i], (userptr_t)stackptr, len, &actual); argv[i] = (char *)stackptr; } /* Add any necessary padding to the user stack */ int padding = 4 - (total % 4); if (padding) { stackptr = stackptr - padding; } /* Copy the array of user pointers argv onto the user stack */ for (i = argc; i >= 0; i--) { stackptr = stackptr - 4; copyout(&argv[i], (userptr_t)stackptr, 4); } kfree(argv); /* Warp to user mode. */ enter_new_process(argc, (userptr_t)stackptr /*userspace addr of argv*/, stackptr, entrypoint); /* 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, int argc) { struct vnode *v; vaddr_t entrypoint, stackptr; int result; // Variables for argument passing int i, pad; size_t offset, get; userptr_t userdest; size_t got[argc]; userptr_t user_argv[argc]; // Count length of each arg i = 0; for (i=0; i<argc; i++){ got[i] = strlen(args[i]) + 1; // Need +1 to account for /0 } /* We enforce that the kernel is only allowed to start ONE user process * directly through runprogram with PID_MIN as its pid. Thereafter any * new user process needs to be forked from existing ones. */ KASSERT(process_table[PID_MIN] == NULL); curthread->pid = PID_MIN; stdio_init(); /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new thread. */ KASSERT(curthread->t_addrspace == NULL); /* Create a new address space. */ curthread->t_addrspace = as_create(); if (curthread->t_addrspace==NULL) { vfs_close(v); return ENOMEM; } /* Activate it. */ as_activate(curthread->t_addrspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_addrspace */ 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(curthread->t_addrspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_addrspace */ return result; } // Copy args to new addrspace offset = 0; for (i=argc-1; i>-1; i--){ pad = (4 - (got[i]%4) ) % 4; // Word align offset += pad; offset += got[i]; user_argv[i] = (userptr_t)(stackptr - offset); result = copyoutstr((const char*)args[i], user_argv[i], got[i], &get); if (result){ return result; } } // Copy pointers to argv userdest = user_argv[0] - 4 * (argc+1); stackptr = (vaddr_t)userdest; // Set stack pointer for (i=0; i<argc; i++){ result = copyout((const void *)&user_argv[i], userdest, 4); if (result){ return result; } userdest += 4; } /* Warp to user mode. */ enter_new_process(argc, (userptr_t)stackptr, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
int main (int argc, char* argv[]) { /* --- main function */ int i, k = 0; /* loop variables, buffer */ char *s; /* to traverse options */ char **optarg = NULL; /* option argument */ char *fn_bc = NULL; /* name of classifier file */ char *fn_out = NULL; /* name of output file */ char *blank = NULL; /* blank */ char *fldsep = NULL; /* field separator */ char *recsep = NULL; /* record separator */ int flags = AS_ATT; /* table file write flags */ double lcorr = -DBL_MAX; /* Laplace correction value */ int dwnull = 0; /* distribute weight of null values */ int maxllh = 0; /* max. likelihood est. of variance */ int tplcnt = 1000; /* number of tuples to generate */ long seed; /* seed for random number generator */ int mode; /* classifier setup mode */ prgname = argv[0]; /* get program name for error msgs. */ seed = (long)time(NULL); /* and get a default seed value */ /* --- print startup/usage message --- */ if (argc > 1) { /* if arguments are given */ fprintf(stderr, "%s - %s\n", argv[0], DESCRIPTION); fprintf(stderr, VERSION); } /* print a startup message */ else { /* if no argument given */ printf("usage: %s [options] bcfile " "[-d|-h hdrfile] tabfile\n", argv[0]); printf("%s\n", DESCRIPTION); printf("%s\n", VERSION); printf("-n# number of tuples to generate " "(default: %d)\n", tplcnt); printf("-s# seed for random number generator " "(default: time)\n"); printf("-L# Laplace correction " "(default: as specified in classifier)\n"); printf("-v/V (do not) distribute tuple weight " "for null values\n"); printf("-m/M (do not) use maximum likelihood estimate " "for the variance\n"); printf("-a align fields (default: do not align)\n"); printf("-w do not write field names to the output file\n"); printf("-b/f/r# blank character, field and record separator\n" " (default: \" \", \" \", \"\\n\")\n"); printf("bcfile file containing classifier description\n"); printf("tabfile table file to write\n"); return 0; /* print a usage message */ } /* and abort the program */ /* --- evaluate arguments --- */ for (i = 1; i < argc; i++) { /* traverse arguments */ s = argv[i]; /* get option argument */ if (optarg) { *optarg = s; optarg = NULL; continue; } if ((*s == '-') && *++s) { /* -- if argument is an option */ while (*s) { /* traverse options */ switch (*s++) { /* evaluate option */ case 'n': tplcnt = (int)strtol(s, &s, 0); break; case 's': seed = strtol(s, &s, 0); break; case 'L': lcorr = strtod(s, &s); break; case 'v': dwnull = NBC_ALL; break; case 'V': dwnull |= NBC_DWNULL|NBC_ALL; break; case 'm': maxllh = NBC_ALL; break; case 'M': maxllh |= NBC_MAXLLH|NBC_ALL; break; case 'a': flags |= AS_ALIGN; break; case 'w': flags &= ~AS_ATT; break; case 'b': optarg = ␣ break; case 'f': optarg = &fldsep; break; case 'r': optarg = &recsep; break; default : error(E_OPTION, *--s); break; } /* set option variables */ if (!*s) break; /* if at end of string, abort loop */ if (optarg) { *optarg = s; optarg = NULL; break; } } } /* get option argument */ else { /* if argument is no option */ switch (k++) { /* evaluate non-option */ case 0: fn_bc = s; break; case 1: fn_out = s; break; default: error(E_ARGCNT); break; } /* note filenames */ } } if (optarg) error(E_OPTARG); /* check the option argument */ if (k != 2) error(E_ARGCNT); /* and the number of arguments */ if ((lcorr < 0) && (lcorr > -DBL_MAX)) error(E_NEGLC); /* check the Laplace correction */ if ((flags & AS_ATT) && (flags & AS_ALIGN)) flags |= AS_ALNHDR; /* set align to header flag */ /* --- read Bayes classifier --- */ scan = sc_create(fn_bc); /* create a scanner */ if (!scan) error((!fn_bc || !*fn_bc) ? E_NOMEM : E_FOPEN, fn_bc); attset = as_create("domains", att_delete); if (!attset) error(E_NOMEM); /* create an attribute set */ fprintf(stderr, "\nreading %s ... ", sc_fname(scan)); if ((sc_nexter(scan) < 0) /* start scanning (get first token) */ || (as_parse(attset, scan, AT_ALL) != 0) || (as_attcnt(attset) <= 0)) /* parse attribute set */ error(E_PARSE, sc_fname(scan)); if ((sc_token(scan) == T_ID) /* determine classifier type */ && (strcmp(sc_value(scan), "fbc") == 0)) fbc = fbc_parse(attset, scan); else nbc = nbc_parse(attset, scan); if ((!fbc && !nbc) /* parse the Bayes classifier */ || !sc_eof(scan)) /* and check for end of file */ error(E_PARSE, sc_fname(scan)); sc_delete(scan); scan = NULL; /* delete the scanner */ fprintf(stderr, "[%d attribute(s)] done.\n", as_attcnt(attset)); if ((lcorr >= 0) || dwnull || maxllh) { if (lcorr < 0) /* get the classifier's parameters */ lcorr = (fbc) ? fbc_lcorr(fbc) : nbc_lcorr(nbc); mode = (fbc) ? fbc_mode(fbc) : nbc_mode(nbc); if (dwnull) mode = (mode & ~NBC_DWNULL) | dwnull; if (maxllh) mode = (mode & ~NBC_MAXLLH) | maxllh; /* adapt the estimation parameters */ if (fbc) fbc_setup(fbc, mode, lcorr); else nbc_setup(nbc, mode, lcorr); } /* set up the classifier anew */ /* --- generate database --- */ if (fn_out && *fn_out) /* if an output file name is given, */ out = fopen(fn_out, "w"); /* open output file for writing */ else { /* if no output file name is given, */ out = stdout; fn_out = "<stdout>"; } /* write to std. output */ fprintf(stderr, "writing %s ... ", fn_out); if (!out) error(E_FOPEN, fn_out); if ((flags & AS_ATT) /* if to write a table header */ && (as_write(attset, out, flags) != 0)) error(E_FWRITE, fn_out); /* write the attributes names */ flags = AS_INST | (flags & ~AS_ATT); dseed(seed); /* init. random number generator */ for (i = tplcnt; --i >= 0;) { /* generate random tuples */ if (fbc) fbc_rand(fbc, drand); /* instantiate the */ else nbc_rand(nbc, drand); /* attribute set */ if (as_write(attset, out, flags) != 0) error(E_FWRITE,fn_out); /* write the generated tuple */ } /* to the output file */ if (out != stdout) { /* if not written to stdout */ i = fclose(out); out = NULL;/* close the output file */ if (i != 0) error(E_FWRITE, fn_out); } /* print a success message */ fprintf(stderr, "[%d tuple(s)] done.\n", tplcnt); /* --- clean up --- */ #ifndef NDEBUG if (fbc) fbc_delete(fbc, 1); /* delete full Bayes classifier */ if (nbc) nbc_delete(nbc, 1); /* or naive Bayes classifier */ #endif /* and underlying attribute set */ #ifdef STORAGE showmem("at end of program"); /* check memory usage */ #endif return 0; /* return 'ok' */ } /* main() */
/* * 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 long nargs) { struct vnode *v; vaddr_t entrypoint, stackptr; int result; /*Initialize Console*/ char *consolein; char *consoleout; char *consoleerr; consolein = kstrdup("con:"); consoleout = kstrdup("con:"); consoleerr = kstrdup("con:"); curthread->t_fdtable[0] = (struct fdesc*) kmalloc(sizeof(struct fdesc)); if (vfs_open(consolein, O_RDONLY, 0664, &(curthread->t_fdtable[0]->vn))) { return EINVAL; } curthread->t_fdtable[0]->name = consolein; curthread->t_fdtable[0]->flag = O_RDONLY; curthread->t_fdtable[0]->ref_count = 1; curthread->t_fdtable[0]->filelock = lock_create("STDIN"); kfree(consolein); curthread->t_fdtable[1] = (struct fdesc*) kmalloc(sizeof(struct fdesc)); if (vfs_open(consoleout, O_WRONLY, 0664, &(curthread->t_fdtable[1]->vn))) { return EINVAL; } curthread->t_fdtable[1]->name = consoleout; curthread->t_fdtable[1]->flag = O_WRONLY; curthread->t_fdtable[1]->ref_count = 1; curthread->t_fdtable[1]->filelock = lock_create("STDOUT"); kfree(consoleout); curthread->t_fdtable[2] = (struct fdesc*) kmalloc(sizeof(struct fdesc)); if (vfs_open(consoleerr, O_WRONLY, 0664, &(curthread->t_fdtable[2]->vn))) { return EINVAL; } curthread->t_fdtable[2]->name = consoleerr; curthread->t_fdtable[2]->flag = O_WRONLY; curthread->t_fdtable[2]->ref_count = 1; curthread->t_fdtable[2]->filelock = lock_create("STDERR"); kfree(consoleerr); /*Console Initialized*/ /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new thread. */ KASSERT(curthread->t_addrspace == NULL); /* Create a new address space. */ curthread->t_addrspace = as_create(); if (curthread->t_addrspace == NULL ) { vfs_close(v); return ENOMEM; } /* Activate it. */ as_activate(curthread->t_addrspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* thread_exit destroys curthread->t_addrspace */ 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(curthread->t_addrspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_addrspace */ return result; } int argc = (signed) nargs; int err; char** argv; //kmalloc argv with size of char* times nargs+1 argv = kmalloc((nargs + 1) * sizeof(userptr_t)); size_t len; for (int i = 0; i < argc; i++) { len = strlen(args[i]) + 1; len = (len + 4 - 1) & ~(size_t) (4 - 1); stackptr -= len; if ((err = copyout(args[i], (userptr_t) stackptr, len)) != 0) { kprintf("error copyout"); } argv[i] = (char*) stackptr; } argv[nargs] = NULL; stackptr -= (nargs + 1) * sizeof(userptr_t); if ((err = copyout(argv, (userptr_t) stackptr, (nargs + 1) * sizeof(char*)))) { kprintf("error copying"); } /* Warp to user mode. */ enter_new_process(argc, (userptr_t) stackptr /*userspace addr of argv*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
int sys_execv(const char* program, char** args, int* errno) { int ret; // simple error check // ************* if (program == NULL) { *errno = EFAULT; return -1; } // ************ // copies progname into kernel buffer // *************** char* fname = (char*)kmalloc(PATH_MAX); ret = copyinstr((userptr_t)program, fname, PATH_MAX, NULL); if (ret != 0) { *errno = EFAULT; return -1; } // opens executable // *************** struct vnode* v; ret = vfs_open(fname, O_RDONLY, &v); if (ret != 0) { *errno = ret; return -1; } // ************** // gets argc // ************** int i = 0; while (args[i] != NULL) { i++; } int argc = i; // ************* // copies all arguments into kernel buffer // ***************** char** argv; argv= (char**)kmalloc(PATH_MAX); ret = copyin(args, argv, sizeof(userptr_t)); if (ret != 0) { *errno = EFAULT; return -1; } for(i = 0; i < argc; i++) { argv[i]=(char*)kmalloc(PATH_MAX); ret = copyinstr((userptr_t)args[i],argv[i], PATH_MAX, NULL); if (ret != 0) { *errno = EFAULT; return -1; } } argv[argc] = NULL; // ******************* // error check // ************ if (curthread->t_vmspace != NULL) { as_destroy(curthread->t_vmspace); curthread->t_vmspace = NULL; } // ************** // creates new address space and loads elf into it // ************** curthread->t_vmspace = as_create(); if (curthread->t_vmspace == NULL) { vfs_close(v); *errno = ENOMEM; return -1; } vaddr_t entrypoint,stackptr; as_activate(curthread->t_vmspace); ret = load_elf(v,&entrypoint); if (ret != 0){ vfs_close(v); *errno = ret; return -1; } vfs_close(v); ret = as_define_stack(curthread->t_vmspace,&stackptr); if (ret != 0) { *errno = ret; return -1; } // ******************** // copies arguments into userstack and increments stack ptr // ************** unsigned int pstack[argc]; for (i = argc-1; i >= 0; i--) { int len = strlen(argv[i]) + 1; stackptr -= len; stackptr -= stackptr%4; ret = copyoutstr(argv[i], (userptr_t)stackptr, PATH_MAX, NULL); if (ret != 0) { *errno = EFAULT; return -1; } pstack[i] = stackptr; } pstack[argc] = (int)NULL; for (i = argc-1; i >= 0; i--) { stackptr -= 4; ret = copyout(&pstack[i], (userptr_t)stackptr, sizeof(pstack[i])); if (ret != 0) { *errno = EFAULT; return -1; } } // free unused memory for (i = 0; i < argc; i++) { kfree(argv[i]); } kfree(argv); kfree(fname); // ******************* // enters usermode, should not return // ******************* md_usermode(argc, (userptr_t)stackptr, stackptr, entrypoint); // ****************** // if usermode returns, that is an error // ********** *errno = EINVAL; return -1; // ************ }