proc_syscalls.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. #include <types.h>
  2. #include <kern/errno.h>
  3. #include <kern/unistd.h>
  4. #include <kern/wait.h>
  5. #include <mips/trapframe.h>
  6. #include <lib.h>
  7. #include <vfs.h>
  8. #include <vnode.h>
  9. #include <syscall.h>
  10. #include <current.h>
  11. #include <proc.h>
  12. #include <thread.h>
  13. #include <addrspace.h>
  14. #include <copyinout.h>
  15. #include <synch.h>
  16. #include <kern/fcntl.h>
  17. void sys__exit(int exitcode)
  18. {
  19. struct addrspace * as;
  20. struct proc * p = curproc;
  21. if (exitcode == -2) p->exitcode = _MKWAIT_SIG(129); // not sure what error code is normally, but this is unix std
  22. else p->exitcode = _MKWAIT_EXIT(exitcode);
  23. DEBUG(DB_SYSCALL,"Syscall: _exit(%d)\n",exitcode);
  24. KASSERT(curproc->p_addrspace != NULL);
  25. lock_acquire(proclock);
  26. int x = listpop(p->kids);
  27. while (x)
  28. {
  29. if(processes->pids[x])
  30. {
  31. processes->pids[x]->parent = NULL;
  32. if (processes->pids[x]->exitcode >= 0)
  33. {
  34. lock_release(proclock);
  35. proc_destroy(processes->pids[x]);
  36. lock_acquire(proclock);
  37. }
  38. }
  39. x = listpop(p->kids);
  40. }
  41. lock_release(proclock);
  42. listelete(p->kids);
  43. // VFS fields
  44. if (p->p_cwd)
  45. {
  46. VOP_DECREF(p->p_cwd);
  47. p->p_cwd = NULL;
  48. }
  49. as_deactivate();
  50. as = curproc_setas(NULL);
  51. as_destroy(as);
  52. /* detach this thread from its process */
  53. /* note: curproc cannot be used after this call */
  54. proc_remthread(curthread);
  55. threadarray_cleanup(&p->p_threads);
  56. spinlock_cleanup(&p->p_lock);
  57. lock_acquire(p->waitlock);
  58. cv_broadcast(p->waiting, p->waitlock);
  59. lock_release(p->waitlock);
  60. if (!(p->parent) || p->parent->exitcode >= 0 || p->parent == kproc) proc_destroy(p);
  61. thread_exit();
  62. /* thread_exit() does not return, so we should never get here */
  63. panic("return from thread_exit in sys_exit\n");
  64. }
  65. // basically, return an error code, and put the actual result in retval
  66. int sys_getpid(pid_t * retval)
  67. {
  68. if (!(curproc)) return 1;
  69. *retval = curproc->pid;
  70. return(0);
  71. }
  72. int sys_waitpid(pid_t pid, userptr_t status, int options, pid_t * retval)
  73. {
  74. if (options != 0 || !(void *)(status))
  75. {
  76. return(EINVAL);
  77. }
  78. if (pid < PID_MIN || pid > PID_MAX) return ESRCH;
  79. struct proc * target = getChild(curproc, pid);
  80. if (!(target)) return ECHILD;
  81. if (!(target->exitcode >= 0))
  82. {
  83. lock_acquire(target->waitlock);
  84. cv_wait(target->waiting, target->waitlock);
  85. lock_release(target->waitlock);
  86. }
  87. int exitstatus = target->exitcode;
  88. *retval = target->exitcode;
  89. int result = copyout((void *)&exitstatus, status, sizeof(int));
  90. if (result)
  91. {
  92. return result;
  93. }
  94. proc_destroy(target);
  95. return 0;
  96. }
  97. int sys_fork(struct trapframe * tf, int * retval)
  98. {
  99. // create new process' memory space
  100. struct proc * child = proc_create_runprogram("childproc");
  101. if ((!child)) return ENOMEM;
  102. struct trapframe * new_tf = kmalloc(sizeof(*tf));
  103. struct addrspace * new_as;
  104. as_copy(curproc_getas(), &new_as);
  105. if (!(new_as) || !(new_tf))
  106. {
  107. proc_destroy(child);
  108. kfree(new_as);
  109. kfree(new_tf);
  110. return ENOMEM;
  111. }
  112. // set PIDs, etc. copy data in to the new space
  113. child->p_addrspace = new_as;
  114. child->parent = curproc;
  115. add_child(curproc, child->pid);
  116. *new_tf = *tf;
  117. // start new thread
  118. thread_fork("childproc", child, enter_forked_process, new_tf, 0);
  119. // return correct values
  120. if (curproc->pid == child->pid) *retval = 0;
  121. else *retval = child->pid;
  122. return 0;
  123. }
  124. // this function takes an argc, argv, and puts argv into the userptr argvaddr, on the stack stackptr
  125. int copyArgs(int argc, char ** argv, userptr_t * argvAddr, vaddr_t * stackptr)
  126. {
  127. vaddr_t stack = *stackptr; // for ease of referencing
  128. char ** newArgv = kmalloc(sizeof(char *) * (argc + 1)); // need argc + 1 space since we want a final address to be null
  129. size_t wasteOfSpace;
  130. int errcode;
  131. for(int i = 0; i < argc; ++i)
  132. {
  133. int arglen = strlen(*(argv + i)) + 1; // length of char array for this arg
  134. stack -= ROUNDUP(arglen, 8); // make the stack bigger by this length, but rounded to 8 cause bytes
  135. 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
  136. if(errcode)
  137. {
  138. kfree(newArgv);
  139. return errcode; // if an error, fuck life
  140. }
  141. *(newArgv + i) = (char *)stack; // our argv kernel array is going to contain the user space address
  142. }
  143. *(newArgv + argc) = NULL; // set final address to NULL
  144. 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
  145. {
  146. stack -= sizeof(char *); // move the stack pointer back one pointer worth of space
  147. 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.
  148. if(errcode)
  149. {
  150. kfree(newArgv);
  151. return errcode; // cry. just cry. then return your error.
  152. }
  153. }
  154. *argvAddr = (userptr_t)stack; // set the argv array in userland to start at where we put it (current stackptr location)
  155. 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)
  156. else stack -= 4;
  157. *stackptr = stack; // set the real stack pointer to the one we've been fucking with
  158. kfree(newArgv); // all data copied over, can free our temp array now
  159. return 0; // return no error
  160. }
  161. static void freeArgv(char ** argv, int len)
  162. {
  163. for (int i = 0; i <= len; ++i)
  164. {
  165. kfree(argv[i]);
  166. }
  167. }
  168. // args is an array of null terminated strings, with the last element being a null pointer so we don't overflow if iterating
  169. // since this is a userptr type, we need to use copyin and copyout to get data properly
  170. // hopefully the path in program is actually a full filepath
  171. int sys_execv(const char * program, userptr_t args)
  172. {
  173. userptr_t temp = args;
  174. int argcount = 0;
  175. int errcode; // why don't we have errno!!! my beautful one-liners!!!
  176. // see how long args is
  177. while (1)
  178. {
  179. void * temp2 = kmalloc(sizeof(temp));
  180. errcode = copyin(temp, temp2, sizeof(temp2));
  181. if (errcode) return errcode;
  182. if (!(*(char **)temp2)) break;
  183. temp += sizeof(temp);
  184. kfree(temp2);
  185. ++argcount;
  186. }
  187. // allocate space for argv
  188. char ** argv = kmalloc(argcount * sizeof(char *));
  189. if (!argv) return ENOMEM;
  190. // get kernel copy of args in argv
  191. temp = args;
  192. for (int i = 0; i < argcount; ++i)
  193. {
  194. char * useraddr = kmalloc(sizeof(temp));
  195. if (!(useraddr))
  196. {
  197. kfree(argv);
  198. return ENOMEM;
  199. }
  200. // useraddr is now the address of the string in userland
  201. errcode = copyin(temp, useraddr, sizeof(temp));
  202. if (errcode)
  203. {
  204. kfree(argv);
  205. return errcode;
  206. }
  207. // change argv[i] to be a string of length enough
  208. int strLen = strlen(*(char **)useraddr) + 1;
  209. kfree(useraddr);
  210. size_t wasteOfSpace;
  211. argv[i] = kmalloc(strLen * sizeof(char));
  212. if (!(argv[i]))
  213. {
  214. freeArgv(argv, i);
  215. kfree(argv);
  216. return ENOMEM;
  217. }
  218. errcode = copyinstr((userptr_t)*(char **)temp, argv[i], strLen, &wasteOfSpace);
  219. if (errcode)
  220. {
  221. freeArgv(argv, i);
  222. kfree(argv);
  223. return errcode;
  224. }
  225. temp += sizeof(temp);
  226. }
  227. // allocate space for filepath
  228. char * filepath = kmalloc((strlen(program) + 1) * sizeof(char));
  229. if (!(filepath))
  230. {
  231. freeArgv(argv, argcount - 1);
  232. kfree(argv);
  233. return ENOMEM;
  234. }
  235. // get kernel copy of filepath
  236. size_t useless;
  237. errcode = copyinstr((const_userptr_t)program, filepath, strlen(program) + 1, &useless);
  238. if (errcode)
  239. {
  240. freeArgv(argv, argcount - 1);
  241. kfree(argv);
  242. kfree(filepath);
  243. return errcode;
  244. }
  245. // open program file
  246. struct vnode * v;
  247. errcode = vfs_open(filepath, O_RDONLY, 0, &v);
  248. if (errcode)
  249. {
  250. freeArgv(argv, argcount - 1);
  251. kfree(argv);
  252. kfree(filepath);
  253. return errcode;
  254. }
  255. // create new address space
  256. struct addrspace * as = as_create();
  257. if (!(as))
  258. {
  259. vfs_close(v);
  260. freeArgv(argv, argcount - 1);
  261. kfree(argv);
  262. kfree(filepath);
  263. return ENOMEM;
  264. }
  265. // Switch to the new as and activate. keep old in case we fail later
  266. struct addrspace * oldas = curproc_getas();
  267. curproc_setas(as);
  268. as_activate();
  269. vaddr_t entrypoint;
  270. // Load santa's favourite slave
  271. errcode = load_elf(v, &entrypoint);
  272. if (errcode)
  273. {
  274. vfs_close(v);
  275. freeArgv(argv, argcount - 1);
  276. kfree(argv);
  277. kfree(filepath);
  278. curproc_setas(oldas);
  279. as_destroy(as);
  280. return errcode;
  281. }
  282. // close the file now that we're done
  283. vfs_close(v);
  284. // create the new stack
  285. vaddr_t newstack;
  286. errcode = as_define_stack(as, &newstack);
  287. if (errcode)
  288. {
  289. freeArgv(argv, argcount - 1);
  290. kfree(argv);
  291. kfree(filepath);
  292. curproc_setas(oldas);
  293. as_destroy(as);
  294. return errcode;
  295. }
  296. // put args into the stack
  297. userptr_t userV;
  298. errcode = copyArgs(argcount, argv, &userV, &newstack);
  299. if (errcode)
  300. {
  301. freeArgv(argv, argcount - 1);
  302. kfree(argv);
  303. kfree(filepath);
  304. curproc_setas(oldas);
  305. as_destroy(as);
  306. return errcode;
  307. }
  308. // delete old addrspace, enter new process
  309. as_destroy(oldas);
  310. kfree(filepath);
  311. freeArgv(argv, argcount - 1);
  312. kfree(argv);
  313. enter_new_process(argcount, userV, newstack, entrypoint);
  314. panic("Enter new process returned!\n");
  315. return EINVAL;
  316. }