void sys__exit(int exitcode) { struct addrspace* as; struct proc* p = curproc; DEBUG(DB_EXEC, "sys_exit(): process %u exiting with code %d\n",p->p_pid,exitcode); KASSERT(p->p_addrspace != NULL); as_deactivate(); as = proc_setas(NULL); as_destroy(as); proc_remthread(curthread); p->p_exitstatus = _MKWAIT_EXIT(exitcode); p->p_exitable = true; lock_acquire(p->p_waitpid_lk); cv_broadcast(p->p_waitpid_cv, p->p_waitpid_lk); lock_release(p->p_waitpid_lk); proc_destroy(p); thread_exit(); panic("sys__exit(): unexpected return from thread_exit()\n"); }
/* * Enter user mode for a newly forked process. * * This function is provided as a reminder. You need to write * both it and the code that calls it. * * Thus, you can trash it and do things another way if you prefer. */ void enter_forked_process(void* ptr, unsigned long args) { //panic("test"); //while(1) {} struct trapframe childtf; bzero(&childtf, sizeof(childtf)); childtf = *(struct trapframe *) ptr; childtf.tf_v0 = 0; childtf.tf_a3 = 0; childtf.tf_epc += 4; kfree(ptr); // load and activate the address space struct addrspace* as = (struct addrspace *) args; proc_setas(as); as_activate(); mips_usermode(&childtf); }
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; }
/* * Destroy a proc structure. * * Note: nothing currently calls this. Your wait/exit code will * probably want to do so. */ void proc_destroy(struct proc *proc) { /* * You probably want to destroy and null out much of the * process (particularly the address space) at exit time if * your wait/exit design calls for the process structure to * hang around beyond process exit. Some wait/exit designs * do, some don't. */ KASSERT(proc != NULL); KASSERT(proc != kproc); /* * We don't take p_lock in here because we must have the only * reference to this structure. (Otherwise it would be * incorrect to destroy it.) */ /* VFS fields */ if (proc->p_cwd) { VOP_DECREF(proc->p_cwd); proc->p_cwd = NULL; } if (proc->p_filetable) { filetable_destroy(proc->p_filetable); proc->p_filetable = NULL; } /* VM fields */ if (proc->p_addrspace) { /* * If p is the current process, remove it safely from * p_addrspace before destroying it. This makes sure * we don't try to activate the address space while * it's being destroyed. * * Also explicitly deactivate, because setting the * address space to NULL won't necessarily do that. * * (When the address space is NULL, it means the * process is kernel-only; in that case it is normally * ok if the MMU and MMU- related data structures * still refer to the address space of the last * process that had one. Then you save work if that * process is the next one to run, which isn't * uncommon. However, here we're going to destroy the * address space, so we need to make sure that nothing * in the VM system still refers to it.) * * The call to as_deactivate() must come after we * clear the address space, or a timer interrupt might * reactivate the old address space again behind our * back. * * If p is not the current process, still remove it * from p_addrspace before destroying it as a * precaution. Note that if p is not the current * process, in order to be here p must either have * never run (e.g. cleaning up after fork failed) or * have finished running and exited. It is quite * incorrect to destroy the proc structure of some * random other process while it's still running... */ struct addrspace *as; if (proc == curproc) { as = proc_setas(NULL); as_deactivate(); } else { as = proc->p_addrspace; proc->p_addrspace = NULL; } as_destroy(as); } threadarray_cleanup(&proc->p_threads); spinlock_cleanup(&proc->p_lock); kfree(proc->p_name); kfree(proc); }
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(proc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as == NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ proc_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; } struct vnode* v1; struct vnode* v2; struct vnode* v3; const char* name = "con:"; char *con_name = kstrdup(name); char *con_name2 = kstrdup(name); char *con_name3 = kstrdup(name); /*char con_name[5]; char con_name2[5]; char con_name3[5]; strcpy(con_name,name); strcpy(con_name2,name); strcpy(con_name3,name); */ result = vfs_open(con_name, O_RDONLY, 0664, &v1); if(result) { return result; } result = vfs_open(con_name2, O_WRONLY, 0664, &v2); if(result) { return result; } result = vfs_open(con_name3, O_WRONLY, 0664, &v3); if(result) { return result; } kfree(con_name); kfree(con_name2); kfree(con_name3); struct file_handle* fh1 = file_handle_create(); fh1->file = v1; fh1->openflags = O_RDONLY; fh1->ref_count = 1; strcpy(fh1->file_name,"con:"); curproc->t_file_table[0] = fh1; struct file_handle* fh2 = file_handle_create(); fh2->file = v2; fh2->openflags = O_WRONLY; fh2->ref_count = 1; strcpy(fh2->file_name, "con:"); curproc->t_file_table[1] = fh2; struct file_handle* fh3 = file_handle_create(); fh3->file = v3; fh3->openflags = O_WRONLY; fh3->ref_count = 1; strcpy(fh3->file_name, "con:"); curproc->t_file_table[2] = fh3; /* Warp to user mode. */ //kprintf("[run program] releasing semaphore \n"); enter_new_process(0 /*argc*/, 0 /*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; }
/* * 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 addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /** Initialize the file descriptors for console**/ if (curthread->t_fdtable[0] == NULL) { result = init_file_descriptor(); if (result ) { // file descriptors not initialized kprintf_n("init_file_descriptor failed"); return result; } } /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* We should be a new process. */ KASSERT(proc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as == NULL) { vfs_close(v); return ENOMEM; } /* Switch to it and activate it. */ proc_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*/, NULL /*userspace addr of environment*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); return EINVAL; }
int sys_execv(char *progname, char **args, int *err) { struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Validations */ if (progname == NULL) { *err = EFAULT; return -1; } if (args == NULL || (int *)args == (int *)0x40000000 || (int *)args == (int *)0x80000000) { *err = EFAULT; return -1; } /* Count number of arguments and total size of input */ int args_count = 0; for (;args_count < ARG_MAX && args[args_count] != NULL; args_count++); if (args_count > ARG_MAX) { *err = E2BIG; return -1; } /* Copy File name */ char *progname_copy = (char *) kmalloc(sizeof(char) * NAME_MAX); size_t actual = 0; result = copyinstr((userptr_t)progname, progname_copy, NAME_MAX, &actual); if (result) { kfree(progname_copy); *err = result; return -1; } if (strlen(progname_copy) == 0) { kfree(progname_copy); *err = EINVAL; return -1; } /* Allocate Kernel Memory for arguments */ char **args_copy = (char **) kmalloc(sizeof(char *) * args_count); int c_args_count = 0, arg_size = 0, padded_size = 0; for (;c_args_count < args_count; c_args_count++) { if ((int *)args[c_args_count] == (int *)0x40000000 || (int *)args[c_args_count] == (int *)0x80000000) { kfree(progname_copy); *err = EFAULT; return -1; } } c_args_count = 0; /* Calculate total length accounting for padding */ for (;c_args_count < args_count; c_args_count++) { arg_size = strlen(args[c_args_count]) + 1; args_copy[c_args_count] = (char *) kmalloc(sizeof(char) * arg_size); copyinstr((userptr_t)args[c_args_count], args_copy[c_args_count], arg_size, &actual); padded_size += arg_size; if (padded_size % 4) { padded_size += (4 - (padded_size % 4)) % 4; } } /* Open the file. */ result = vfs_open(progname_copy, O_RDONLY, 0, &v); if (result) { kfree(progname_copy); *err = result; return -1; } /* Destroy the current process's address space to create a new one. */ as = curproc->p_addrspace; curproc->p_addrspace = NULL; as_destroy(as); /* We should be a new process. */ KASSERT(proc_getas() == NULL); /* Create a new address space. */ as = as_create(); if (as == NULL) { kfree(progname_copy); vfs_close(v); *err = ENOMEM; return -1; } /* Switch to it and activate it. */ proc_setas(as); as_activate(); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { /* p_addrspace will go away when curproc is destroyed */ kfree(progname_copy); vfs_close(v); *err = result; return -1; } /* 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 */ kfree(progname_copy); *err = result; return -1; } stackptr -= padded_size; char **arg_address = (char **) kmalloc(sizeof(char *) * args_count + 1); /* Copy arguments into user stack */ for(int i = 0; i < args_count; i++) { arg_size = strlen(args_copy[i]) + 1; if (arg_size % 4) { arg_size += (4 - arg_size % 4) % 4; } /* Store address of arguments */ arg_address[i] = (char *)stackptr; copyoutstr(args_copy[i], (userptr_t)stackptr, arg_size, &actual); stackptr += arg_size; } /* Add Null Pointer at the end */ arg_address[args_count] = 0; stackptr -= padded_size; stackptr -= (args_count + 1) * sizeof(char *); /* Copy address locations into user stack*/ for (int i = 0; i < args_count + 1; i++) { copyout((arg_address + i), (userptr_t)stackptr, sizeof(char *)); stackptr += sizeof(char *); } /* Reset pointer to start of the stack */ stackptr -= ((args_count + 1) * sizeof(char *)); kfree(progname_copy); c_args_count = 0; for (;c_args_count < args_count; c_args_count++) { kfree(args_copy[c_args_count]); } kfree(args_copy); kfree(arg_address); /* Warp to user mode. */ enter_new_process(args_count /*argc*/, (userptr_t) stackptr /*userspace addr of argv*/, (userptr_t) stackptr /*userspace addr of environment*/, stackptr, entrypoint); /* enter_new_process does not return. */ panic("enter_new_process returned\n"); *err = EINVAL; return -1; }
int sys_execv(userptr_t progname, userptr_t *arguments) { struct proc *proc = curproc; struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; //kprintf("****EXECV]***** process-%d trying to exec", proc->pid); //lock_acquire(execlock); //kprintf("****EXECV]***** process-%d acquired exec lock", proc->pid); if(progname == NULL || progname == (void *)0x80000000 || progname == (void *)0x40000000) { return EFAULT; } if(arguments == NULL || arguments == (void *)0x80000000 || arguments == (void *)0x40000000) { return EFAULT; } /* This process should have an address space copied during fork */ KASSERT(proc != NULL); char *_progname; size_t size; int i=0, count=0; _progname = (char *) kmalloc(sizeof(char)*PATH_MAX); result = copyinstr(progname, _progname, PATH_MAX, &size); if(result) { kfree(_progname); return EFAULT; } if(strlen(_progname) == 0) { kfree(_progname); return EINVAL; } if(swapping_started == true) { } kfree(_progname); char *args = (char *) kmalloc(sizeof(char)*ARG_MAX); result = copyinstr((const_userptr_t)arguments, args, ARG_MAX, &size); if(result) { kfree(args); return EFAULT; } /* Copy the user arguments on to the kernel */ int offset = 0; while((char *) arguments[count] != NULL) { result = copyinstr((const_userptr_t) arguments[count], args+offset, ARG_MAX, &size); if(result) { kfree(args); return EFAULT; } offset += size; count++; } /* Open the file */ result = vfs_open((char *)progname, O_RDONLY, 0, &v); if(result) { kfree(args); return result; } /* Destroy the current address space and Create a new address space */ as_destroy(proc->p_addrspace); proc->p_addrspace = NULL; KASSERT(proc_getas() == NULL); as = as_create(); if(as == NULL) { kfree(args); vfs_close(v); return ENOMEM; } /* Switch to it and activate it */ proc_setas(as); as_activate(); /* Load the executable. */ // kprintf("free pages available before load_elf : %d \n", coremap_free_bytes()/4096); result = load_elf(v, &entrypoint); if(result) { kfree(args); 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) { kfree(args); return result; } i = 0; int prevlen = 0, cur = 0; char **stkargs=(char**) kmalloc(sizeof(char*)*(count+1)); while(i < offset) { int len=0, olen; for(len=0; args[i] != '\0'; len++, i++); olen = len; len = len + (4 - len%4); char *arg = kmalloc(len); //arg = kstrdup(args+prevlen); //kprintf("%s\n", arg); int j = prevlen; for(int k=0; k<len; k++) { if(k >= olen) arg[k] = '\0'; else arg[k] = args[j++]; } //kprintf("%s\n", arg); stackptr -= len; result = copyout((const void *)arg, (userptr_t)stackptr, (size_t)len); if(result) { kfree(args); kfree(stkargs); return result; } kfree(arg); stkargs[cur++] = (char *)stackptr; prevlen += olen + 1; i++; } stkargs[cur] = NULL; kfree(args); for(i=(cur) ; i>=0; i--) { stackptr = stackptr - sizeof(char *); //kprintf("copying arg %d at [%p]\n", i, *(stkargs+i)); result = copyout((const void *)(stkargs+i), (userptr_t) stackptr, (sizeof(char *))); if(result) { kfree(stkargs); return result; } prevlen += 4; } kfree(stkargs); //unsigned int free = coremap_free_bytes(); // unsigned int free_pages = free/4096; // kprintf("free pages available : %d \n", free_pages); //lock_release(execlock); //kprintf("****EXECV]***** process-%d released exec lock", proc->pid); enter_new_process(count, (userptr_t) stackptr, NULL, stackptr, entrypoint); panic("enter_new_process returned\n"); return EINVAL; }