In this PR, we introduce a few new system calls to handle basic userspace multiprocessing techniques, like fork and exec.
fork creates a duplicate of the process that called it, and resumes the child at the same point as the parent, with the only difference being the return value of fork. This allows a child to know it's a child, and the parent to know it's apparently a parent, and alter control flow accordingly.
exec replaces the process that called it with a new one. The stack, program itself, and any allocated memory are removed and the stack, program, etc of a new executable are loaded in it's place. This allows, for example, the child of a fork to replace itself with any process. This gives the parent the ability to "run" any process while staying running itself.
waitpid alter's a process' state to SLEEPING, meaning the scheduler will no longer schedule it. This sleeping process is added to a waiting list on the process with the given PID; when that process exits, every process on the waiting list will have it's state set to RUNNING. This allows for a process to wait for another.
With these three system calls, a basic shell can be implemented, and from there we can begin to do crazy, whacky, userspace things
TODO:
exec has a lot of debug output because without it there is some sort of race condition or something and it crashes with a #PF or #GP; obviously, this needs fixed.