syscall.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #include <asm/port_io.h>
  2. #include <asm/sys.h>
  3. #include <assert.h>
  4. #include <bits/ioctl.h>
  5. #include <kernel/errno.h>
  6. #include <kernel/interrupt.h>
  7. #include <kernel/log.hpp>
  8. #include <kernel/mem.h>
  9. #include <kernel/mm.hpp>
  10. #include <kernel/process.hpp>
  11. #include <kernel/syscall.hpp>
  12. #include <kernel/tty.hpp>
  13. #include <kernel/vfs.hpp>
  14. #include <stdint.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <types/allocator.hpp>
  18. #include <types/elf.hpp>
  19. #include <types/lock.hpp>
  20. #include <types/status.h>
  21. #define SYSCALL_HANDLERS_SIZE (128)
  22. syscall_handler syscall_handlers[SYSCALL_HANDLERS_SIZE];
  23. extern "C" void _syscall_stub_fork_return(void);
  24. int _syscall_fork(interrupt_stack* data)
  25. {
  26. auto* newproc = &procs->emplace(*current_process)->second;
  27. auto* newthd = &newproc->thds.Emplace(*current_thread, newproc);
  28. readythds->push(newthd);
  29. // create fake interrupt stack
  30. push_stack(&newthd->esp, data->ss);
  31. push_stack(&newthd->esp, data->esp);
  32. push_stack(&newthd->esp, data->eflags);
  33. push_stack(&newthd->esp, data->cs);
  34. push_stack(&newthd->esp, (uint32_t)data->v_eip);
  35. // eax
  36. push_stack(&newthd->esp, 0);
  37. push_stack(&newthd->esp, data->s_regs.ecx);
  38. // edx
  39. push_stack(&newthd->esp, 0);
  40. push_stack(&newthd->esp, data->s_regs.ebx);
  41. push_stack(&newthd->esp, data->s_regs.esp);
  42. push_stack(&newthd->esp, data->s_regs.ebp);
  43. push_stack(&newthd->esp, data->s_regs.esi);
  44. push_stack(&newthd->esp, data->s_regs.edi);
  45. // ctx_switch stack
  46. // return address
  47. push_stack(&newthd->esp, (uint32_t)_syscall_stub_fork_return);
  48. // ebx
  49. push_stack(&newthd->esp, 0);
  50. // edi
  51. push_stack(&newthd->esp, 0);
  52. // esi
  53. push_stack(&newthd->esp, 0);
  54. // ebp
  55. push_stack(&newthd->esp, 0);
  56. // eflags
  57. push_stack(&newthd->esp, 0);
  58. return newproc->pid;
  59. }
  60. int _syscall_write(interrupt_stack* data)
  61. {
  62. int fd = data->s_regs.edi;
  63. const char* buf = reinterpret_cast<const char*>(data->s_regs.esi);
  64. size_t n = data->s_regs.edx;
  65. auto* file = current_process->files[fd];
  66. if (!file || !file->flags.write)
  67. return -EBADF;
  68. switch (file->type) {
  69. case fs::file::types::ind: {
  70. if (file->ptr.ind->flags.in.directory)
  71. return -EBADF;
  72. int n_wrote = fs::vfs_write(file->ptr.ind, buf, file->cursor, n);
  73. if (n_wrote >= 0)
  74. file->cursor += n_wrote;
  75. return n_wrote;
  76. }
  77. case fs::file::types::pipe:
  78. return file->ptr.pp->write(buf, n);
  79. case fs::file::types::socket:
  80. // TODO
  81. return -EINVAL;
  82. default:
  83. assert(false);
  84. }
  85. }
  86. int _syscall_read(interrupt_stack* data)
  87. {
  88. int fd = data->s_regs.edi;
  89. char* buf = reinterpret_cast<char*>(data->s_regs.esi);
  90. size_t n = data->s_regs.edx;
  91. auto* file = current_process->files[fd];
  92. if (!file || !file->flags.read)
  93. return -EBADF;
  94. switch (file->type) {
  95. case fs::file::types::ind: {
  96. if (file->ptr.ind->flags.in.directory)
  97. return -EBADF;
  98. // TODO: copy to user function !IMPORTANT
  99. int n_wrote = fs::vfs_read(file->ptr.ind, buf, n, file->cursor, n);
  100. if (n_wrote >= 0)
  101. file->cursor += n_wrote;
  102. return n_wrote;
  103. }
  104. case fs::file::types::pipe:
  105. return file->ptr.pp->read(buf, n);
  106. case fs::file::types::socket:
  107. // TODO
  108. return -EINVAL;
  109. default:
  110. assert(false);
  111. }
  112. }
  113. // TODO: sleep seconds
  114. int _syscall_sleep(interrupt_stack*)
  115. {
  116. current_thread->attr.ready = 0;
  117. current_thread->attr.wait = 1;
  118. schedule();
  119. return 0;
  120. }
  121. int _syscall_chdir(interrupt_stack* data)
  122. {
  123. const char* path = reinterpret_cast<const char*>(data->s_regs.edi);
  124. auto* dir = fs::vfs_open(path);
  125. if (!dir)
  126. return -ENOENT;
  127. if (!dir->ind->flags.in.directory)
  128. return -ENOTDIR;
  129. current_process->pwd = path;
  130. return 0;
  131. }
  132. // syscall_exec(const char* exec, const char** argv)
  133. // @param exec: the path of program to execute
  134. // @param argv: arguments end with nullptr
  135. // @param envp: environment variables end with nullptr
  136. int _syscall_execve(interrupt_stack* data)
  137. {
  138. const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
  139. char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
  140. char* const* envp = reinterpret_cast<char* const*>(data->s_regs.edx);
  141. types::elf::elf32_load_data d;
  142. d.argv = argv;
  143. d.envp = envp;
  144. d.exec = exec;
  145. d.system = false;
  146. int ret = types::elf::elf32_load(&d);
  147. if (ret != GB_OK)
  148. return -d.errcode;
  149. data->v_eip = d.eip;
  150. data->esp = (uint32_t)d.sp;
  151. return 0;
  152. }
  153. // @param exit_code
  154. int NORETURN _syscall_exit(interrupt_stack* data)
  155. {
  156. uint32_t exit_code = data->s_regs.edi;
  157. // TODO: terminating a thread only
  158. if (current_thread->owner->thds.size() != 1) {
  159. assert(false);
  160. }
  161. // terminating a whole process:
  162. procs->kill(current_process->pid, exit_code);
  163. // switch to new process and continue
  164. schedule_noreturn();
  165. }
  166. // @param address of exit code: int*
  167. // @return pid of the exited process
  168. int _syscall_wait(interrupt_stack* data)
  169. {
  170. auto* arg1 = reinterpret_cast<int*>(data->s_regs.edi);
  171. auto& cv = current_process->cv_wait;
  172. auto& mtx = cv.mtx();
  173. types::lock_guard lck(mtx);
  174. auto& waitlist = current_process->waitlist;
  175. while (waitlist.empty()) {
  176. if (!procs->has_child(current_process->pid))
  177. return -ECHILD;
  178. if (!cv.wait(mtx))
  179. return -EINTR;
  180. }
  181. auto iter = waitlist.begin();
  182. assert(iter != waitlist.end());
  183. auto& obj = *iter;
  184. pid_t pid = obj.pid;
  185. // TODO: copy_to_user check privilege
  186. *arg1 = obj.code;
  187. procs->remove(pid);
  188. waitlist.erase(iter);
  189. return pid;
  190. }
  191. int _syscall_getdents(interrupt_stack* data)
  192. {
  193. int fd = data->s_regs.edi;
  194. auto* buf = (char*)(data->s_regs.esi);
  195. size_t cnt = data->s_regs.edx;
  196. auto* dir = current_process->files[fd];
  197. if (dir->type != fs::file::types::ind || !dir->ptr.ind->flags.in.directory)
  198. return -ENOTDIR;
  199. size_t orig_cnt = cnt;
  200. int nread = dir->ptr.ind->fs->inode_readdir(dir->ptr.ind, dir->cursor,
  201. [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
  202. if (!len)
  203. len = strlen(fn);
  204. size_t reclen = sizeof(fs::user_dirent) + 1 + len;
  205. if (cnt < reclen)
  206. return GB_FAILED;
  207. auto* dirp = (fs::user_dirent*)buf;
  208. dirp->d_ino = ino;
  209. dirp->d_reclen = reclen;
  210. // TODO: show offset
  211. // dirp->d_off = 0;
  212. // TODO: use copy_to_user
  213. memcpy(dirp->d_name, fn, len);
  214. buf[reclen - 2] = 0;
  215. buf[reclen - 1] = type;
  216. buf += reclen;
  217. cnt -= reclen;
  218. return GB_OK;
  219. });
  220. if (nread > 0)
  221. dir->cursor += nread;
  222. return orig_cnt - cnt;
  223. }
  224. int _syscall_open(interrupt_stack* data)
  225. {
  226. auto* path = (const char*)data->s_regs.edi;
  227. uint32_t flags = data->s_regs.esi;
  228. return current_process->files.open(path, flags);
  229. }
  230. int _syscall_getcwd(interrupt_stack* data)
  231. {
  232. char* buf = reinterpret_cast<char*>(data->s_regs.edi);
  233. size_t bufsize = reinterpret_cast<size_t>(data->s_regs.esi);
  234. // TODO: use copy_to_user
  235. strncpy(buf, current_process->pwd.c_str(), bufsize);
  236. buf[bufsize - 1] = 0;
  237. return (uint32_t)buf;
  238. }
  239. int _syscall_setsid(interrupt_stack*)
  240. {
  241. if (current_process->pid == current_process->pgid)
  242. return -EPERM;
  243. current_process->sid = current_process->pid;
  244. current_process->pgid = current_process->pid;
  245. // TODO: get tty* from fd or block device id
  246. console->set_pgrp(current_process->pid);
  247. current_process->control_tty = console;
  248. return current_process->pid;
  249. }
  250. int _syscall_getsid(interrupt_stack* data)
  251. {
  252. pid_t pid = data->s_regs.edi;
  253. if (!procs->try_find(pid))
  254. return -ESRCH;
  255. auto& proc = procs->find(pid);
  256. if (proc.sid != current_process->sid)
  257. return -EPERM;
  258. return proc.sid;
  259. }
  260. int _syscall_close(interrupt_stack* data)
  261. {
  262. int fd = data->s_regs.edi;
  263. current_process->files.close(fd);
  264. return 0;
  265. }
  266. int _syscall_dup(interrupt_stack* data)
  267. {
  268. int old_fd = data->s_regs.edi;
  269. return current_process->files.dup(old_fd);
  270. }
  271. int _syscall_dup2(interrupt_stack* data)
  272. {
  273. int old_fd = data->s_regs.edi;
  274. int new_fd = data->s_regs.esi;
  275. return current_process->files.dup2(old_fd, new_fd);
  276. }
  277. int _syscall_pipe(interrupt_stack* data)
  278. {
  279. auto& pipefd = *(int(*)[2])data->s_regs.edi;
  280. return current_process->files.pipe(pipefd);
  281. }
  282. int _syscall_setpgid(interrupt_stack* data)
  283. {
  284. pid_t pid = data->s_regs.edi;
  285. pid_t pgid = data->s_regs.esi;
  286. if (pgid < 0)
  287. return -EINVAL;
  288. if (pid == 0)
  289. pid = current_process->pid;
  290. if (pgid == 0)
  291. pgid = pid;
  292. if (!procs->try_find(pid))
  293. return -ESRCH;
  294. auto& proc = procs->find(pid);
  295. // TODO: check whether pgid and the original
  296. // pgid is in the same session
  297. proc.pgid = pgid;
  298. return 0;
  299. }
  300. int _syscall_ioctl(interrupt_stack* data)
  301. {
  302. int fd = data->s_regs.edi;
  303. unsigned long request = data->s_regs.esi;
  304. // TODO: check fd type and get tty* from fd
  305. //
  306. // we use a trick for now, check whether
  307. // the file that fd points to is a pipe or
  308. // not. and we suppose that stdin will be
  309. // either a tty or a pipe.
  310. auto* file = current_process->files[fd];
  311. if (!file || file->type != fs::file::types::ind)
  312. return -ENOTTY;
  313. switch (request) {
  314. case TIOCGPGRP: {
  315. auto* pgid = (pid_t*)data->s_regs.edx;
  316. tty* ctrl_tty = current_process->control_tty;
  317. // TODO: copy_to_user
  318. *pgid = ctrl_tty->get_pgrp();
  319. break;
  320. }
  321. case TIOCSPGRP: {
  322. // TODO: copy_from_user
  323. pid_t pgid = *(const pid_t*)data->s_regs.edx;
  324. tty* ctrl_tty = current_process->control_tty;
  325. ctrl_tty->set_pgrp(pgid);
  326. break;
  327. }
  328. default:
  329. return -EINVAL;
  330. }
  331. return 0;
  332. }
  333. int _syscall_getpid(interrupt_stack*)
  334. {
  335. return current_process->pid;
  336. }
  337. int _syscall_getppid(interrupt_stack*)
  338. {
  339. return current_process->ppid;
  340. }
  341. extern "C" void syscall_entry(interrupt_stack* data)
  342. {
  343. int syscall_no = data->s_regs.eax;
  344. if (syscall_no >= SYSCALL_HANDLERS_SIZE)
  345. kill_current(-1);
  346. int ret = syscall_handlers[syscall_no](data);
  347. data->s_regs.eax = ret;
  348. check_signal();
  349. }
  350. SECTION(".text.kinit")
  351. void init_syscall(void)
  352. {
  353. memset(syscall_handlers, 0x00, sizeof(syscall_handlers));
  354. syscall_handlers[0] = _syscall_read;
  355. syscall_handlers[1] = _syscall_write;
  356. syscall_handlers[2] = _syscall_open;
  357. syscall_handlers[3] = _syscall_close;
  358. syscall_handlers[16] = _syscall_ioctl;
  359. syscall_handlers[22] = _syscall_pipe;
  360. syscall_handlers[32] = _syscall_dup;
  361. syscall_handlers[33] = _syscall_dup2;
  362. syscall_handlers[35] = _syscall_sleep;
  363. syscall_handlers[39] = _syscall_getpid;
  364. syscall_handlers[57] = _syscall_fork;
  365. syscall_handlers[59] = _syscall_execve;
  366. syscall_handlers[60] = _syscall_exit;
  367. syscall_handlers[61] = _syscall_wait;
  368. syscall_handlers[78] = _syscall_getdents;
  369. syscall_handlers[79] = _syscall_getcwd;
  370. syscall_handlers[80] = _syscall_chdir;
  371. syscall_handlers[109] = _syscall_setpgid;
  372. syscall_handlers[110] = _syscall_getppid;
  373. syscall_handlers[112] = _syscall_setsid;
  374. syscall_handlers[124] = _syscall_getsid;
  375. }