/* * 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); }
// man page // int execv(const char *program, char **args); int sys_execv(char *progname, char **argv){ struct addrspace *as; struct vnode *v; vaddr_t entrypoint, stackptr; int result; unsigned long argc = 0; /* Open the file. */ result = vfs_open(progname, O_RDONLY, 0, &v); if (result) { return result; } /* Destroy the current address space */ as_deactivate(); as = curproc_setas(NULL); as_destroy(as); /* 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; } // we need to figure out what argc would be for(unsigned long i = 0; argv[i] != NULL; i++){ argc = i + 1; } #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; (void)progname; (void)argv; }
int sys___execv(char * p_name,char **ar ) { struct vnode *p_vnode; vaddr_t stackptr; vaddr_t entrypoint; int result; size_t copied_length; char *kname; if(p_name==NULL) return EFAULT; if(ar==NULL) return EFAULT; if(p_name == '\0') return ENOEXEC; kname = (char *) kmalloc(sizeof(p_name)); result = copyinstr((const_userptr_t)p_name,kname,NAME_MAX,&copied_length); if(copied_length == 1) { kfree(kname); return EINVAL; } if(result) { kfree(kname); return result; } char **karguments1 = kmalloc(100*sizeof(char*)); result = copyin((const_userptr_t) ar,karguments1,(100*sizeof(char*))); if(result) { kfree(karguments1); kfree(kname); return result; } else kfree(karguments1); char **arguments_kernel =(char **) kmalloc(sizeof(char**)); result = copyin((const_userptr_t) ar,arguments_kernel,(sizeof(char**))); if(result) { kfree(kname); kfree(arguments_kernel); return result; } char **karguments = (char **) kmalloc(sizeof(char **)); int counter=0; size_t actual_lenght1; while(!(ar[counter]==NULL)) { int string_length = strlen(ar[counter])+1; karguments[counter] = (char *) kmalloc(sizeof(char) * string_length); result = copyinstr((const_userptr_t) ar[counter],karguments[counter],string_length,&actual_lenght1); if(result) { kfree(kname); kfree(arguments_kernel); return result; } counter++; } karguments[counter] = NULL; result = vfs_open(kname, O_RDONLY, 0, &p_vnode); if (result) { return result; } as_destroy(curthread->t_addrspace); //Create a new address space. curthread->t_addrspace = as_create(); if (curthread->t_addrspace==NULL) { vfs_close(p_vnode); return ENOMEM; } //Activate it. as_activate(curthread->t_addrspace); /* Load the executable. */ result = load_elf(p_vnode, &entrypoint); if (result) { /* thread_exit destroys curthread->t_addrspace */ vfs_close(p_vnode); return result; } /* Done with the file now. */ vfs_close(p_vnode); //Get the pointer to the stack starting result = as_define_stack(curthread->t_addrspace, &stackptr); if (result) { /* thread_exit destroys curthread->t_addrspace */ return result; } //Now copy the arguments int count =0; char **karray= kmalloc(sizeof(char**)); size_t final_stack=0; while(karguments[count] != NULL) { int string_length = strlen(karguments[count])+1; char *k_des= karguments[count]; int new_length = string_length; if((string_length) % 4 != 0) { while(new_length%4 !=0) { new_length++; } for(int i=string_length;i<=new_length;i++) { k_des[i]= '\0'; } } //Argument aligned by 4 size_t final_length= (size_t)new_length; if(count==0) { final_stack= stackptr- final_length; } else { final_stack= (size_t)karray[count-1]- final_length; } size_t actual_length1; result= copyoutstr(k_des, (userptr_t) (final_stack), final_length, &actual_length1); if(result) { return result; } karray[count]= (char*)(final_stack); count++; } //End of While karray[count]= (char*)NULL; int value= count+1; int arr_length = (value+1)*sizeof(char*); final_stack= (size_t)karray[count-1]- arr_length; result= copyout(karray, (userptr_t) (final_stack),arr_length); if(result) { return result; } /* Warp to user mode. */ enter_new_process(count /*argc*/, (userptr_t)(final_stack) /*userspace addr of argv*/, final_stack, entrypoint); return 0; }
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(userptr_t progname, userptr_t args){ /*This function implements the execv functionality*/ size_t get, offset; struct vnode *v; vaddr_t entrypoint, stackptr; userptr_t userdest; int i=0, append_zero, argc=0, result, part=0; char *buf_mem; int n=0; struct addrspace *old_addr = curthread->t_vmspace; char **usr_args = (char**)args; buf_mem = (void *) kmalloc(sizeof(void *)); result = copyin((const_userptr_t)args,buf_mem,4); if (result){ kfree(buf_mem); return result; } lock_acquire(execv_lock); kfree(buf_mem); while(usr_args[argc] != NULL){ argc++; } size_t len_string[argc]; userptr_t user_argv[argc]; char *args_buf = kmalloc(PAGE_SIZE*sizeof(char)); // Check user pointer buf_mem = (char *)kmalloc(1024*sizeof(char)); if (buf_mem == NULL){ result = ENOMEM; kfree(args_buf); } result = copyinstr((const_userptr_t)progname,buf_mem,1024,&get); if (result){ kfree(buf_mem); } //Implementation from runprogram from here /* Open the file. */ result = vfs_open((char *)progname, O_RDONLY, &v); if (result) { kfree(buf_mem); } // Keep old addrspace in case of failure struct addrspace *new_addr = as_create(); if (new_addr == NULL){ result = ENOMEM; vfs_close(v); } while (usr_args[i] != NULL){ result = copyinstr((const_userptr_t)usr_args[i], &args_buf[part], PAGE_SIZE, &len_string[i]); if (result){ as_destroy(new_addr); } part += len_string[i]; i++; } /* Swap addrspace and Activate it*/ curthread->t_vmspace = new_addr; as_activate(curthread->t_vmspace); /* Load the executable. */ result = load_elf(v, &entrypoint); if (result) { curthread->t_vmspace = old_addr; as_activate(curthread->t_vmspace); } /* Define the user stack in the address space */ result = as_define_stack(curthread->t_vmspace, &stackptr); if (result) { curthread->t_vmspace = old_addr; as_activate(curthread->t_vmspace); } // Copy args to new addrspace offset = 0; for (i=argc-1; i>-1; i--){ part -= len_string[i]; // readjust inherited part index append_zero = (4 - (len_string[i]%4) ) % 4; // Word align offset += append_zero; offset += len_string[i]; user_argv[i] = (userptr_t)(stackptr - offset); result = copyoutstr((const char*)&args_buf[part], user_argv[i], len_string[i], &get); if (result){ curthread->t_vmspace = old_addr; as_activate(curthread->t_vmspace); } } // 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) curthread->t_vmspace = old_addr; as_activate(curthread->t_vmspace); userdest += 4; } // Wrap up kfree(args_buf); vfs_close(v); /* Warp to user mode. */ md_usermode(argc, (userptr_t)stackptr, stackptr, entrypoint); lock_release(execv_lock); 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 nargs) { struct vnode *v; vaddr_t entrypoint, stackptr, arguments[nargs+1], exactnewstackptr; int result, i; size_t len, offset = 0; /* 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. */ struct addrspace * old_vmspace = curthread->t_vmspace; 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 */ curthread->t_vmspace = old_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 */ curthread->t_vmspace = old_vmspace; return result; } if(old_vmspace){ as_destroy(old_vmspace); } for (i = 0; i < nargs; i++) { len = strlen(args[i]) + 1; offset += len; arguments[i] = stackptr - offset; copyout((void *)args[i], (userptr_t) arguments[i], (size_t) len); } arguments[nargs] = 0; offset += sizeof(vaddr_t) * (nargs+1); exactnewstackptr = stackptr - offset; stackptr = exactnewstackptr - exactnewstackptr%4; copyout((void *) arguments, (userptr_t) stackptr, (size_t) sizeof(vaddr_t) * (nargs+1)); md_usermode(nargs, (userptr_t) stackptr, stackptr, entrypoint); panic("md_usermode returned\n"); return EINVAL; }
int sys_execv(const char *prog, char **userArgs) { struct vnode *v; vaddr_t entrypoint, stackptr; int res = 0; int length = 0; int index = 0; lock_acquire(allProcLock); char *progname; size_t size; progname = (char *) kmalloc(sizeof(char) * PATH_MAX); res = copyinstr((const_userptr_t) prog, progname, PATH_MAX, &size); char **args = (char **) kmalloc(sizeof(char **)); res = copyin((const_userptr_t)userArgs, args, sizeof(char **)); while (userArgs[index] != NULL) { args[index] = (char *) kmalloc(sizeof(char) * PATH_MAX); res = copyinstr((const_userptr_t) userArgs[index], args[index], PATH_MAX, &size); index++; } args[index] = NULL; index = 0; res = vfs_open(progname, O_RDONLY, 0, &v); struct addrspace *temp; temp = curproc->p_addrspace; if(curproc->p_addrspace != NULL){ as_destroy(curproc->p_addrspace); curproc->p_addrspace = NULL; } KASSERT(curproc->p_addrspace == NULL); if((curproc->p_addrspace = as_create()) == NULL){ kfree(progname); kfree(args); vfs_close(v); return ENOMEM; } as_activate(); res = load_elf(v, &entrypoint); vfs_close(v); res = as_define_stack(curproc->p_addrspace, &stackptr); while(args[index] != NULL) { char * arg; length = strlen(args[index]) + 1; int orignalLength = length; if(length % 4 != 0) { length = length + (4 - length % 4); } arg = kmalloc(sizeof(length)); arg = kstrdup(args[index]); for(int i = 0; i < length; i++){ if(i >= orignalLength){ arg[i] = '\0'; } else{ arg[i] = args[index][i]; } } stackptr -= length; res = copyout((const void *) arg, (userptr_t) stackptr, (size_t) length); kfree(arg); args[index] = (char *) stackptr; index++; } if(args[index] == NULL){ stackptr -= 4 * sizeof(char); } for(int i = (index - 1); i >= 0; i--) { stackptr = stackptr - sizeof(char*); res = copyout((const void *) (args + i), (userptr_t) stackptr, sizeof(char*)); } kfree(progname); kfree(args); lock_release(allProcLock); enter_new_process(index, (userptr_t) stackptr, stackptr, entrypoint); return EINVAL; }
int execv(const char *program, char **args) { // kprintf("\n\n execv testing \n\n") ; if (program == NULL ) { return EFAULT ; } //char * kernel_pgm = (char *)kmalloc(sizeof(char *)) ; char * kernel_pgm = (char *)kmalloc(__PATH_MAX) ; size_t bytes_copied ; int result = copyinstr((const userptr_t)program,kernel_pgm,__PATH_MAX,&bytes_copied) ; if (result ) { return result ; } if (strlen(kernel_pgm) == 0) { return EINVAL ; } if (strlen(kernel_pgm) >= __PATH_MAX) { return ENAMETOOLONG ; } int argc = 0 ; if (args == NULL) { return EFAULT ; } char *temp1 = (char *)kmalloc(ARG_MAX*sizeof(char)) ; result = copyinstr((const userptr_t)args,temp1,ARG_MAX*sizeof(char),&bytes_copied) ; if(result){ return result; } kfree(temp1); while(args[argc]!=NULL) //while (true) { char *temp = (char *)kmalloc(ARG_MAX*sizeof(char)) ; result = copyinstr((const userptr_t)args[argc],temp,ARG_MAX*sizeof(char),&bytes_copied) ; if (result) { kfree(temp); return EFAULT ;//break ; } argc++ ; kfree(temp) ; } char **temp = (char **)kmalloc(argc*sizeof(char *)) ; int i = 0 ; while(i<argc) { temp[i] = (char *)kmalloc(ARG_MAX*sizeof(char)) ; result = copyinstr((const userptr_t)args[i],temp[i],ARG_MAX*sizeof(char),&bytes_copied) ; if (result) { return result ; } i++ ; } struct vnode *v; vaddr_t entrypoint, stackptr; result = vfs_open(kernel_pgm, O_RDONLY, 0, &v); if (result) { return result; } struct addrspace *addrspace_copy=curthread->t_addrspace; if(curthread->t_addrspace != NULL){ as_destroy(curthread->t_addrspace); curthread->t_addrspace = NULL; } //struct addrspace *addrspace_copy=curthread->t_addrspace; curthread->t_addrspace = as_create(); if (curthread->t_addrspace==NULL) { vfs_close(v); curthread->t_addrspace = addrspace_copy; return ENOMEM; } as_activate(curthread->t_addrspace); result = load_elf(v, &entrypoint); if (result) { vfs_close(v); return result; } vfs_close(v); result = as_define_stack(curthread->t_addrspace, &stackptr); if (result) { return result; } i = i -1 ; vaddr_t index[25] ; int k = 0 ; while(i>= 0) { int length = strlen(temp[i]) ; int num0 = (4 - (length % 4)) ; int j = 0 ; char *temp1 = (char *)kmalloc((length+num0)*sizeof(char)) ; strcpy(temp1,temp[i]) ; while(j<num0) { strcat(temp1,"\0") ; j++ ; } stackptr = stackptr - ((length+num0)*sizeof(char)) ; result = copyoutstr(temp1,(userptr_t) stackptr,(length+num0)*sizeof(char),&bytes_copied) ; if (result) { return result ; } index[k] = (vaddr_t )stackptr; k++ ; i-- ; kfree(temp1) ; } i = 0 ; stackptr = stackptr - sizeof(int) ; stackptr = stackptr - sizeof(int) ; k-- ; while(i<=k) { result = copyout(&index[i],(userptr_t) stackptr,sizeof(int)) ; if (result) { return result ; } i++ ; if (i<=k){ stackptr = stackptr - sizeof(int) ; } } kfree(temp) ; kfree(kernel_pgm) ; enter_new_process(argc,(userptr_t) stackptr , stackptr, entrypoint); 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(const char *progname, char**args) { kprintf("hello world"); struct vnode *v; vaddr_t entrypoint, stackptr; int result; int argc = getargc(args); /* Copy the arguments into the kernel buffer */ char** kbuffer = kmalloc(argc*sizeof(char*)); int i; for (i=0; i<argc; i++) { kbuffer[i] = kmalloc(strlen(args[i])*sizeof(char*)+1); copyinstr(args[i], kbuffer[i], strlen(args[i])*sizeof(char*)+1, NULL); } args = kbuffer; /* Open the file. */ result = vfs_open(progname, O_RDONLY, &v); if (result) { return result; } /* This is not the first process, we have to make sure the previous process address space is not NULL. */ assert(curthread->t_vmspace != NULL); /* Destroy the old process address space */ as_destroy(curthread->t_vmspace); /* 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; } /* Done with the file now. */ vfs_close(v); /* Free the current process user stack */ kfree(curthread->t_stack); /* 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; } /* copy arguments to user space */ char **args_u; /* user space arguments.(array of ptrs to string arguments.*/ /* string length of the arguments */ size_t argstrlen = getlen(argc, args); /* address space for the string arguments value. */ char* arg_str = (char *) stackptr - argstrlen; /* address space for the pointers to string arguments. */ args_u = (char **) arg_str - (argc + 1) * sizeof (char**); /* adjust the address so that its divisable by 4 */ args_u = (int) args_u - (int) args_u % 4; /* copy the arguments to the user address space */ int len; for (i = 0; i < argc; i++) { /* copy a single argument to the user address space */ copyoutstr(args[i], (userptr_t) arg_str, strlen(args[i]) + 1, &len); /* set the user argument to the current argument string pointer */ args_u[i] = arg_str; /* increment the argument pointer to the next argument */ arg_str += (strlen(args[i]) + 1) * sizeof (char); } /* set the n+1th argument to be NULL */ args_u[argc] = NULL; /* set the stackptr to the starting point of args_u and adjust the stack pointer */ stackptr = args_u - sizeof (char**) - ((int)args_u%8); /* Warp to user mode. */ md_usermode(argc, (userptr_t) args_u, stackptr, entrypoint); /*********************** end of A2 stuff *****************/ /* md_usermode does not return */ panic("md_usermode returned\n"); return EINVAL; }
int sys_execv(const char *prog_path, char **args) { int spl = splhigh(); // the prog_path is in user space, we need to copy it into kernel space if(prog_path == NULL) { return EINVAL; } // frist the program path char* program = (char *) kmalloc(MAX_PATH_LEN * sizeof(char)); int size; int result = copyinstr((const_userptr_t) prog_path, program, MAX_PATH_LEN, &size); if(result) { kfree(program); return EFAULT; } // arguments char** argv = (char**) kmalloc(sizeof(char**)); // char** argv; result = copyin((const_userptr_t)args, argv, sizeof(char **)); if(result) { kfree(program); kfree(argv); return EFAULT; } // count the number of arguments int i = 0; while(args[i] != NULL){ argv[i] = (char*) kmalloc(sizeof(char) * MAX_ARG_LEN); if(copyinstr((const_userptr_t) args[i], argv[i], MAX_ARG_LEN, &size) != 0) { return EFAULT; } i++; } argv[i] = NULL; // runprogram_exev_syscall(program, argv, i); /*********************** runprogram starts*****************/ struct vnode *v; vaddr_t entrypoint, stackptr; result = vfs_open(program, O_RDONLY, &v); if (result) { return result; } // destroy the old addrspace if(curthread->t_vmspace != NULL){ as_destroy(curthread->t_vmspace); curthread->t_vmspace = NULL; } 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; } // Activate it. as_activate(curthread->t_vmspace); // Load the executable. result = load_elf(v, &entrypoint); // Load an ELF executable user program into the current address space and // returns the entry point (initial PC) for the program in ENTRYPOINT. if (result) { vfs_close(v); return result; } vfs_close(v); result = as_define_stack(curthread->t_vmspace, &stackptr); if (result) { // thread_exit destroys curthread->t_vmspace return result; } int narg = i - 1; int j; for(j = 0; j < narg; ++j){ int len = 1 + strlen(argv[j]); len = ROUNDUP(len, 8); stackptr -= len; result = copyoutstr(argv[j],(userptr_t)stackptr, len, &len); if(result){ return result; } argv[j] = (char*)stackptr; } argv[i] = NULL; size_t arg_size = (narg + 1) * sizeof(char*); arg_size = ROUNDUP(arg_size, 8); // align the stackptr to 8 byte aligned stackptr -= arg_size; // stackptr -= stackptr % 8; copyout(argv, stackptr, (narg + 1) * 4); md_usermode(i, stackptr, stackptr, entrypoint); panic("md_usermode returned\n"); return EINVAL; }
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; }
/* * runprogram is run from menu, and its arguments * are passed by thread_fork (a ptr & a int) * so we need to construct a struct to store progname and args */ int runprogram(struct runprogram_info *prog_info) { char *progname = prog_info->progname; struct vnode *v; vaddr_t entrypoint, stackptr; int result; /* Open the file. */ result = vfs_open(progname, O_RDONLY, &v); if (result) { return result; } /* * if runprogram is called by sys_execv, it is for sure that * curthread has its own user addr_space already. * we need to destroy it. * if runprogram is called by menu, there is no addrspace created. */ // =========================================== struct addrspace *old_as = curthread->t_vmspace; if (old_as != NULL) { as_destroy(old_as); curthread->t_vmspace = NULL; } // =========================================== /* 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; } /* Activate it. */ as_activate(curthread->t_vmspace); /* Load the executable. */ // entrypoint is set by load_elf result = load_elf(v, &entrypoint); // =========================================== /* * in dumbvm, we only need to set up the addrspace for stack * now, we need to load stack (set up page table, without dealing with the content) */ // =========================================== if (result) { /* thread_exit destroys curthread->t_vmspace */ // which means runprogram is called by some other function, // and when it returns, thread_exit will be called outside runprogram // that's why runprom should not return 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; } // ============================================ size_t len; void *ks_start = setup_args_mem(prog_info, &stackptr, &len); int err = copyout(ks_start, stackptr, len); if (err != 0) { panic("runprogram: copyout err!\n"); } /* int i; for (i = 0; i < len/4; i++) { //i in terms of word //kfree will free 4 bytes at a time? kfree((int *)((int *)ks_start+i)); } */ kfree(ks_start); //kprintf("copyout result: %d\n", err); // ============================================ /* Warp to user mode. */ int nargc = prog_info->argc; kfree(prog_info); //cmd_coremapstats(1, NULL); md_usermode(nargc /*argc*/, stackptr /*userspace addr of argv*/, stackptr, entrypoint); /* md_usermode does not return */ panic("md_usermode returned\n"); return EINVAL; }
/* * Function called when user-level code hits a fatal fault. */ static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) { int sig = 0; KASSERT(code < NTRAPCODES); switch (code) { case EX_IRQ: case EX_IBE: case EX_DBE: case EX_SYS: /* should not be seen */ KASSERT(0); sig = SIGABRT; break; case EX_MOD: case EX_TLBL: case EX_TLBS: sig = SIGSEGV; break; case EX_ADEL: case EX_ADES: sig = SIGBUS; break; case EX_BP: sig = SIGTRAP; break; case EX_RI: sig = SIGILL; break; case EX_CPU: sig = SIGSEGV; break; case EX_OVF: sig = SIGFPE; break; } /* * You will probably want to change this. */ #if OPT_A3 //supposed to be similar to sys_exit (void)epc; (void)vaddr; struct addrspace *as; struct proc *p = curproc; as_deactivate(); as = curproc_setas(NULL); as_destroy(as); proc_remthread(curthread); proc_destroy(p); thread_exit(); panic("Should not have returned here!\n"); #else kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code, sig, trapcodenames[code], epc, vaddr); panic("I don't know how to handle this\n"); #endif }
int as_copy(struct addrspace *old, struct addrspace **ret) { struct addrspace *newas; newas = as_create(); if (newas==NULL) { return ENOMEM; } // kprintf(" **** inside as copy **** \n"); // spinlock_acquire(newas->as_splock); // spinlock_acquire(old->as_splock); if(use_small_lock == true && swapping_started == true) { lock_acquire(newas->as_lock); lock_acquire(old->as_lock); } else if(use_big_lock == true && swapping_started == true) lock_acquire(as_lock); struct as_region* r_old = old->as_region_list; while(r_old != NULL) { struct as_region* r_new = (struct as_region*)kmalloc(sizeof(struct as_region)); if(r_new == NULL) { if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } //spinlock_release(old->as_splock); //spinlock_release(newas->as_splock); as_destroy(newas); return ENOMEM; } r_new->region_base = r_old->region_base; r_new->region_npages = r_old->region_npages; r_new->can_read = r_old->can_read; r_new->can_write = r_old->can_write; r_new->can_execute = r_old->can_execute; int ret = region_list_add_node(&newas->as_region_list,r_new); if(ret == -1) { if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); as_destroy(newas); return ENOMEM; } r_old = r_old->next; } struct page_table_entry* p_old = old->as_page_list; while(p_old != NULL) { struct page_table_entry* p_new = (struct page_table_entry*)kmalloc(sizeof(struct page_table_entry)); if(p_new == NULL) { if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); as_destroy(newas); return ENOMEM; } p_new->vaddr = p_old->vaddr; p_new->swap_pos = -1; KASSERT(p_old->page_state != SWAPPING); while(p_old->page_state == SWAPPING) { thread_yield(); } // if(!spinlock_do_i_hold) // KASSERT(p_old->page_state != SWAPPING); if(p_old->page_state == MAPPED) { if(use_page_lock == true && swapping_started == true) lock_acquire(coremap[(p_old->paddr)/PAGE_SIZE].page_lock); if(p_old->page_state == MAPPED) { paddr_t paddr = get_user_page(p_old->vaddr, false, newas); KASSERT(p_old->page_state == MAPPED); // int spl = splhigh(); if(use_small_lock == true && swapping_started == true) { if(lock_do_i_hold(newas->as_lock) == false) lock_acquire(newas->as_lock); if(lock_do_i_hold(old->as_lock) == false) lock_acquire(newas->as_lock); } else if(use_big_lock == true && swapping_started == true) { if(lock_do_i_hold(as_lock) == false) lock_acquire(as_lock); } if(paddr == 0) { if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); as_destroy(newas); return ENOMEM; } uint32_t old_index = p_old->paddr/PAGE_SIZE; KASSERT(coremap[old_index].is_victim == false); KASSERT(coremap[paddr/PAGE_SIZE].is_victim == false); memmove((void*)PADDR_TO_KVADDR(paddr), (const void *)PADDR_TO_KVADDR(p_old->paddr), //use this? or PADDR_TO_KVADDR like dumbvm does?. But why does dumbvm do that in the first place. PAGE_SIZE); // i know why, cannot call functions on user memory addresses. So convert it into a kv address. // the function will translate it into a physical address again and free it. ugly Hack. but no other way. p_new->paddr = paddr; p_new->page_state = MAPPED; // splx(spl); int ret = page_list_add_node(&newas->as_page_list,p_new); if(ret == -1) { if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); as_destroy(newas); return ENOMEM; } if(use_page_lock == true && swapping_started == true) { if(lock_do_i_hold(coremap[paddr/PAGE_SIZE].page_lock) == true) lock_release(coremap[paddr/PAGE_SIZE].page_lock); if(lock_do_i_hold(coremap[(p_old->paddr/PAGE_SIZE)].page_lock) == true) lock_release(coremap[(p_old->paddr/PAGE_SIZE)].page_lock); } } } if(p_old->page_state == SWAPPED) { // this page is in disk, so we need to create a copy of that page somewhere in disk and then update the page table entry of the new process. // going with the disk->memory->disk approach suggested in a recitation video by jinghao shi. // Allocate a buffer at vm_bootstrap of size 4k (1 page). Use this buffer to temporarily copy data from disk to here and then to disk again // then clear the buffer. This buffer is a shared resource, so we need a lock around it. // kprintf("in as_copy swap code \n"); // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); swap_in(p_old->vaddr,old,copy_buffer_vaddr, p_old->swap_pos); // kprintf("completed swap in \n"); int pos = mark_swap_pos(p_new->vaddr, newas); KASSERT(pos != -1); int err = write_to_disk(KVADDR_TO_PADDR(copy_buffer_vaddr)/PAGE_SIZE, pos); // kprintf("completed writing to disk \n"); KASSERT(err == 0); // spinlock_acquire(newas->as_splock); // spinlock_acquire(old->as_splock); // as_zero_region(KVADDR_TO_PADDR(copy_buffer_vaddr),1); p_new->page_state = SWAPPED; p_new->swap_pos = pos; p_new->paddr = 0; if(use_page_lock == true && swapping_started == true) { if(lock_do_i_hold(coremap[(p_old->paddr/PAGE_SIZE)].page_lock) == true) lock_release(coremap[(p_old->paddr/PAGE_SIZE)].page_lock); } } p_old = p_old->next; } newas->as_heap_start = old->as_heap_start; newas->as_heap_end = old->as_heap_end; *ret = newas; if(use_big_lock == true && swapping_started == true) lock_release(as_lock); else if(use_small_lock == true && swapping_started == true) { lock_release(old->as_lock); lock_release(newas->as_lock); } // kprintf("exiting as copy \n"); // spinlock_release(old->as_splock); // spinlock_release(newas->as_splock); return 0; }
/* * Function called when user-level code hits a fatal fault. */ static void kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) { int sig = 0; KASSERT(code < NTRAPCODES); switch (code) { case EX_IRQ: case EX_IBE: case EX_DBE: case EX_SYS: /* should not be seen */ KASSERT(0); sig = SIGABRT; break; case EX_MOD: case EX_TLBL: case EX_TLBS: sig = SIGSEGV; break; case EX_ADEL: case EX_ADES: sig = SIGBUS; break; case EX_BP: sig = SIGTRAP; break; case EX_RI: sig = SIGILL; break; case EX_CPU: sig = SIGSEGV; break; case EX_OVF: sig = SIGFPE; break; } /* * You will probably want to change this. */ #if OPT_A3 (void)epc; (void)vaddr; struct addrspace *as; struct proc *p = curproc; int parentLocation = locatePid(p->p_pid); struct procStruct *parentProcStr = array_get(procStructArray, parentLocation); parentProcStr->exitcode = _MKWAIT_SIG(sig); cleanChildren(parentLocation); V(parentProcStr->proc_sem); KASSERT(curproc->p_addrspace != NULL); as_deactivate(); /* * clear p_addrspace before calling as_destroy. Otherwise if * as_destroy sleeps (which is quite possible) when we * come back we'll be calling as_activate on a * half-destroyed address space. This tends to be * messily fatal. */ as = curproc_setas(NULL); as_destroy(as); /* detach this thread from its process */ /* note: curproc cannot be used after this call */ proc_remthread(curthread); /* if this is the last user process in the system, proc_destroy() will wake up the kernel menu thread */ proc_destroy(p); thread_exit(); /* thread_exit() does not return, so we should never get here */ panic("return from thread_exit in sys_exit\n"); #else kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", code, sig, trapcodenames[code], epc, vaddr); panic("I don't know how to handle this\n"); #endif }
int sys_fork(struct trapframe* tf, pid_t* retval) { DEBUG(DB_EXEC,"sys_fork(): entering\n"); KASSERT(curproc != NULL); KASSERT(sizeof(struct trapframe)==(37*4)); char* child_name = kmalloc(sizeof(char)* NAME_MAX); strcpy(child_name, curproc->p_name); strcat(child_name, "_c"); // create PCB for child struct proc* child_proc = NULL; proc_fork(&child_proc); if (child_proc == NULL) { return ENOMEM; } strcpy(child_proc->p_name, child_name); KASSERT(child_proc->p_pid > 0); // copy address space and registers from this process to child struct addrspace* child_as = kmalloc(sizeof(struct addrspace)); if (child_as == NULL) { kfree(child_name); proc_destroy(child_proc); return ENOMEM; } struct trapframe* child_tf = kmalloc(sizeof(struct trapframe)); if (child_tf == NULL) { kfree(child_name); as_destroy(child_as); proc_destroy(child_proc); return ENOMEM; } DEBUG(DB_EXEC,"sys_fork(): copying address space...\n"); // copy the address space just created into the child process's // PCB structure int result = as_copy(curproc->p_addrspace, &child_as); if (result) { kfree(child_name); as_destroy(child_as); proc_destroy(child_proc); return result; } child_proc->p_addrspace = child_as; DEBUG(DB_EXEC,"sys_fork(): copying trapframe space...\n"); // copy this process's trapframe to the child process memcpy(child_tf, tf, sizeof(struct trapframe)); DEBUG(DB_EXEC, "sys_fork(): copying filetable...\n"); filetable_copy(curproc->p_filetable,&child_proc->p_filetable); DEBUG(DB_EXEC,"sys_fork(): assigning child process's parent as this process...\n"); // assign child processes parent as this process child_proc->p_parent = curproc; DEBUG(DB_EXEC,"sys_fork(): adding child to children procarray...\n"); result = procarray_add(&curproc->p_children, child_proc, NULL); if (result) { DEBUG(DB_EXEC, "sys_fork(): failed to add child process to proc_table...\n"); } DEBUG(DB_EXEC,"sys_fork(): allocating data...\n"); void **data = kmalloc(2*sizeof(void*)); data[0] = (void*)child_tf; data[1] = (void*)child_as; result = thread_fork(child_name, child_proc, &enter_forked_process, data, 0); if (result) { kfree(child_name); kfree(child_tf); as_destroy(child_as); proc_destroy(child_proc); return ENOMEM; } *retval = child_proc->p_pid; DEBUG(DB_EXEC, "sys_fork(): thread_fork returned: curproc=%u, child_proc=%u\n",curproc->p_pid,child_proc->p_pid); return 0; }