123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- #include <types.h>
- #include <kern/errno.h>
- #include <kern/unistd.h>
- #include <kern/wait.h>
- #include <mips/trapframe.h>
- #include <lib.h>
- #include <vfs.h>
- #include <vnode.h>
- #include <syscall.h>
- #include <current.h>
- #include <proc.h>
- #include <thread.h>
- #include <addrspace.h>
- #include <copyinout.h>
- #include <synch.h>
- #include <kern/fcntl.h>
- void sys__exit(int exitcode)
- {
- struct addrspace * as;
- struct proc * p = curproc;
- if (exitcode == -2) p->exitcode = _MKWAIT_SIG(129); // not sure what error code is normally, but this is unix std
- else p->exitcode = _MKWAIT_EXIT(exitcode);
- DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);
- KASSERT(curproc->p_addrspace != NULL);
-
- lock_acquire(proclock);
- int x = listpop(p->kids);
- while (x)
- {
- if(processes->pids[x])
- {
- processes->pids[x]->parent = NULL;
- if (processes->pids[x]->exitcode >= 0)
- {
- lock_release(proclock);
- proc_destroy(processes->pids[x]);
- lock_acquire(proclock);
- }
- }
- x = listpop(p->kids);
- }
- lock_release(proclock);
- listelete(p->kids);
-
- // VFS fields
- if (p->p_cwd)
- {
- VOP_DECREF(p->p_cwd);
- p->p_cwd = NULL;
- }
-
- as_deactivate();
- as = curproc_setas(NULL);
- as_destroy(as);
- /* detach this thread from its process */
- /* note: curproc cannot be used after this call */
- proc_remthread(curthread);
- threadarray_cleanup(&p->p_threads);
- spinlock_cleanup(&p->p_lock);
- lock_acquire(p->waitlock);
- cv_broadcast(p->waiting, p->waitlock);
- lock_release(p->waitlock);
- if (!(p->parent) || p->parent->exitcode >= 0 || p->parent == kproc) 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");
- }
- // basically, return an error code, and put the actual result in retval
- int sys_getpid(pid_t * retval)
- {
- if (!(curproc)) return 1;
- *retval = curproc->pid;
- return(0);
- }
- int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval)
- {
- if (options != 0 || !(void *)(status))
- {
- return(EINVAL);
- }
-
- if (pid < PID_MIN || pid > PID_MAX) return ESRCH;
- struct proc * target = getChild(curproc, pid);
-
- if (!(target)) return ECHILD;
- if (!(target->exitcode >= 0))
- {
- lock_acquire(target->waitlock);
- cv_wait(target->waiting, target->waitlock);
- lock_release(target->waitlock);
- }
- int exitstatus = target->exitcode;
- *retval = target->exitcode;
- int result = copyout((void *)&exitstatus, status, sizeof(int));
- if (result)
- {
- return result;
- }
- proc_destroy(target);
- return 0;
- }
- int sys_fork(struct trapframe * tf, int * retval)
- {
- // create new process' memory space
- struct proc * child = proc_create_runprogram("childproc");
- if ((!child)) return ENOMEM;
-
- struct trapframe * new_tf = kmalloc(sizeof(*tf));
- struct addrspace * new_as;
- as_copy(curproc_getas(), &new_as);
-
- if (!(new_as) || !(new_tf))
- {
- proc_destroy(child);
- kfree(new_as);
- kfree(new_tf);
- return ENOMEM;
- }
-
- // set PIDs, etc. copy data in to the new space
- child->p_addrspace = new_as;
- child->parent = curproc;
- add_child(curproc, child->pid);
- *new_tf = *tf;
-
- // start new thread
- thread_fork("childproc", child, enter_forked_process, new_tf, 0);
-
- // return correct values
- if (curproc->pid == child->pid) *retval = 0;
- else *retval = child->pid;
- return 0;
- }
- // this function takes an argc, argv, and puts argv into the userptr argvaddr, on the stack stackptr
- int copyArgs(int argc, char ** argv, userptr_t * argvAddr, vaddr_t * stackptr)
- {
- vaddr_t stack = *stackptr; // for ease of referencing
- char ** newArgv = kmalloc(sizeof(char *) * (argc + 1)); // need argc + 1 space since we want a final address to be null
- size_t wasteOfSpace;
- int errcode;
-
- for(int i = 0; i < argc; ++i)
- {
- int arglen = strlen(*(argv + i)) + 1; // length of char array for this arg
- stack -= ROUNDUP(arglen, 8); // make the stack bigger by this length, but rounded to 8 cause bytes
- errcode = copyoutstr(*(argv + i), (userptr_t)stack, arglen, &wasteOfSpace); // take the string in argv at i, put it at the stack position we calculated just before as the start for a string of our length
- if(errcode)
- {
- kfree(newArgv);
- return errcode; // if an error, fuck life
- }
- *(newArgv + i) = (char *)stack; // our argv kernel array is going to contain the user space address
- }
-
- *(newArgv + argc) = NULL; // set final address to NULL
-
- for(int i = 0; i <= argc; ++i) // after we store the array contents, we want to store the array of pointers to those contents. which is "before" in the stack becuase fuck you, that's why
- {
- stack -= sizeof(char *); // move the stack pointer back one pointer worth of space
- errcode = copyout(newArgv + (argc - i), (userptr_t)stack, sizeof(char *)); // copy the pointers in reverse order into the stack, since we are going backwards in the stack.
- if(errcode)
- {
- kfree(newArgv);
- return errcode; // cry. just cry. then return your error.
- }
- }
- *argvAddr = (userptr_t)stack; // set the argv array in userland to start at where we put it (current stackptr location)
- if (stack % 8 == 0) stack -= 8; // move the stack pointer back the minimum amount (if we are at an 8 byte address already, a full 8 bytes. otherwise we must be at a 4 byte address, so just half that)
- else stack -= 4;
- *stackptr = stack; // set the real stack pointer to the one we've been fucking with
- kfree(newArgv); // all data copied over, can free our temp array now
- return 0; // return no error
- }
- static void freeArgv(char ** argv, int len)
- {
- for (int i = 0; i <= len; ++i)
- {
- kfree(argv[i]);
- }
- }
- // args is an array of null terminated strings, with the last element being a null pointer so we don't overflow if iterating
- // since this is a userptr type, we need to use copyin and copyout to get data properly
- // hopefully the path in program is actually a full filepath
- int sys_execv(const char * program, userptr_t args)
- {
- userptr_t temp = args;
- int argcount = 0;
- int errcode; // why don't we have errno!!! my beautful one-liners!!!
-
- // see how long args is
- while (1)
- {
- void * temp2 = kmalloc(sizeof(temp));
- errcode = copyin(temp, temp2, sizeof(temp2));
- if (errcode) return errcode;
- if (!(*(char **)temp2)) break;
- temp += sizeof(temp);
- kfree(temp2);
- ++argcount;
- }
- // allocate space for argv
- char ** argv = kmalloc(argcount * sizeof(char *));
- if (!argv) return ENOMEM;
-
- // get kernel copy of args in argv
- temp = args;
- for (int i = 0; i < argcount; ++i)
- {
- char * useraddr = kmalloc(sizeof(temp));
- if (!(useraddr))
- {
- kfree(argv);
- return ENOMEM;
- }
- // useraddr is now the address of the string in userland
- errcode = copyin(temp, useraddr, sizeof(temp));
- if (errcode)
- {
- kfree(argv);
- return errcode;
- }
- // change argv[i] to be a string of length enough
- int strLen = strlen(*(char **)useraddr) + 1;
- kfree(useraddr);
- size_t wasteOfSpace;
- argv[i] = kmalloc(strLen * sizeof(char));
- if (!(argv[i]))
- {
- freeArgv(argv, i);
- kfree(argv);
- return ENOMEM;
- }
-
- errcode = copyinstr((userptr_t)*(char **)temp, argv[i], strLen, &wasteOfSpace);
- if (errcode)
- {
- freeArgv(argv, i);
- kfree(argv);
- return errcode;
- }
- temp += sizeof(temp);
- }
- // allocate space for filepath
- char * filepath = kmalloc((strlen(program) + 1) * sizeof(char));
- if (!(filepath))
- {
- freeArgv(argv, argcount - 1);
- kfree(argv);
- return ENOMEM;
- }
-
- // get kernel copy of filepath
- size_t useless;
- errcode = copyinstr((const_userptr_t)program, filepath, strlen(program) + 1, &useless);
- if (errcode)
- {
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- return errcode;
- }
-
- // open program file
- struct vnode * v;
- errcode = vfs_open(filepath, O_RDONLY, 0, &v);
- if (errcode)
- {
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- return errcode;
- }
-
- // create new address space
- struct addrspace * as = as_create();
- if (!(as))
- {
- vfs_close(v);
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- return ENOMEM;
- }
- // Switch to the new as and activate. keep old in case we fail later
- struct addrspace * oldas = curproc_getas();
- curproc_setas(as);
- as_activate();
- vaddr_t entrypoint;
- // Load santa's favourite slave
- errcode = load_elf(v, &entrypoint);
- if (errcode)
- {
- vfs_close(v);
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- curproc_setas(oldas);
- as_destroy(as);
- return errcode;
- }
- // close the file now that we're done
- vfs_close(v);
-
- // create the new stack
- vaddr_t newstack;
- errcode = as_define_stack(as, &newstack);
- if (errcode)
- {
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- curproc_setas(oldas);
- as_destroy(as);
- return errcode;
- }
- // put args into the stack
- userptr_t userV;
- errcode = copyArgs(argcount, argv, &userV, &newstack);
- if (errcode)
- {
- freeArgv(argv, argcount - 1);
- kfree(argv);
- kfree(filepath);
- curproc_setas(oldas);
- as_destroy(as);
- return errcode;
- }
-
- // delete old addrspace, enter new process
- as_destroy(oldas);
- kfree(filepath);
- freeArgv(argv, argcount - 1);
- kfree(argv);
- enter_new_process(argcount, userV, newstack, entrypoint);
- panic("Enter new process returned!\n");
- return EINVAL;
- }
|