|
@@ -13,12 +13,14 @@
|
|
|
#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;
|
|
|
- p->exitcode = exitcode;
|
|
|
+ p->exitcode = _MKWAIT_EXIT(exitcode);
|
|
|
DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);
|
|
|
KASSERT(curproc->p_addrspace != NULL);
|
|
|
|
|
@@ -42,11 +44,11 @@ void sys__exit(int exitcode)
|
|
|
listelete(p->kids);
|
|
|
|
|
|
// VFS fields
|
|
|
- if (p->p_cwd)
|
|
|
- {
|
|
|
- VOP_DECREF(p->p_cwd);
|
|
|
- p->p_cwd = NULL;
|
|
|
- }
|
|
|
+ if (p->p_cwd)
|
|
|
+ {
|
|
|
+ VOP_DECREF(p->p_cwd);
|
|
|
+ p->p_cwd = NULL;
|
|
|
+ }
|
|
|
|
|
|
as_deactivate();
|
|
|
as = curproc_setas(NULL);
|
|
@@ -57,7 +59,7 @@ void sys__exit(int exitcode)
|
|
|
proc_remthread(curthread);
|
|
|
|
|
|
threadarray_cleanup(&p->p_threads);
|
|
|
- spinlock_cleanup(&p->p_lock);
|
|
|
+ spinlock_cleanup(&p->p_lock);
|
|
|
|
|
|
lock_acquire(p->waitlock);
|
|
|
cv_broadcast(p->waiting, p->waitlock);
|
|
@@ -80,8 +82,7 @@ int sys_getpid(pid_t * retval)
|
|
|
|
|
|
int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval)
|
|
|
{
|
|
|
- (void)status;
|
|
|
- if (options != 0)
|
|
|
+ if (options != 0 || !(void *)(status))
|
|
|
{
|
|
|
return(EINVAL);
|
|
|
}
|
|
@@ -90,16 +91,19 @@ int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval)
|
|
|
struct proc * target = getChild(curproc, pid);
|
|
|
|
|
|
if (!(target)) return ECHILD;
|
|
|
- if (target->exitcode >= 0)
|
|
|
+ if (!(target->exitcode >= 0))
|
|
|
{
|
|
|
- *retval = target->exitcode;
|
|
|
- return 0;
|
|
|
+ lock_acquire(target->waitlock);
|
|
|
+ cv_wait(target->waiting, target->waitlock);
|
|
|
+ lock_release(target->waitlock);
|
|
|
}
|
|
|
-
|
|
|
- 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;
|
|
|
}
|
|
@@ -136,3 +140,212 @@ int sys_fork(struct trapframe * tf, int * retval)
|
|
|
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));
|
|
|
+ // 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;
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|