syscall.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include <asm/port_io.h>
  2. #include <asm/sys.h>
  3. #include <assert.h>
  4. #include <kernel/errno.h>
  5. #include <kernel/interrupt.h>
  6. #include <kernel/log.hpp>
  7. #include <kernel/mem.h>
  8. #include <kernel/mm.hpp>
  9. #include <kernel/process.hpp>
  10. #include <kernel/syscall.hpp>
  11. #include <kernel/tty.hpp>
  12. #include <kernel/vfs.hpp>
  13. #include <stdint.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <types/allocator.hpp>
  17. #include <types/elf.hpp>
  18. #include <types/status.h>
  19. #define SYSCALL_HANDLERS_SIZE (16)
  20. syscall_handler syscall_handlers[SYSCALL_HANDLERS_SIZE];
  21. extern "C" void _syscall_stub_fork_return(void);
  22. int _syscall_fork(interrupt_stack* data)
  23. {
  24. auto* newproc = &procs->emplace(*current_process)->value;
  25. auto* newthd = &newproc->thds.Emplace(*current_thread, newproc);
  26. readythds->push(newthd);
  27. // create fake interrupt stack
  28. push_stack(&newthd->esp, data->ss);
  29. push_stack(&newthd->esp, data->esp);
  30. push_stack(&newthd->esp, data->eflags);
  31. push_stack(&newthd->esp, data->cs);
  32. push_stack(&newthd->esp, (uint32_t)data->v_eip);
  33. // eax
  34. push_stack(&newthd->esp, 0);
  35. push_stack(&newthd->esp, data->s_regs.ecx);
  36. // edx
  37. push_stack(&newthd->esp, 0);
  38. push_stack(&newthd->esp, data->s_regs.ebx);
  39. push_stack(&newthd->esp, data->s_regs.esp);
  40. push_stack(&newthd->esp, data->s_regs.ebp);
  41. push_stack(&newthd->esp, data->s_regs.esi);
  42. push_stack(&newthd->esp, data->s_regs.edi);
  43. // ctx_switch stack
  44. // return address
  45. push_stack(&newthd->esp, (uint32_t)_syscall_stub_fork_return);
  46. // ebx
  47. push_stack(&newthd->esp, 0);
  48. // edi
  49. push_stack(&newthd->esp, 0);
  50. // esi
  51. push_stack(&newthd->esp, 0);
  52. // ebp
  53. push_stack(&newthd->esp, 0);
  54. // eflags
  55. push_stack(&newthd->esp, 0);
  56. return newproc->pid;
  57. }
  58. int _syscall_write(interrupt_stack* data)
  59. {
  60. int fd = data->s_regs.edi;
  61. const char* buf = reinterpret_cast<const char*>(data->s_regs.esi);
  62. size_t n = data->s_regs.edx;
  63. auto* file = current_process->files[fd];
  64. if (!file)
  65. return -EBADF;
  66. if (file->type == fs::file::types::directory)
  67. return -EBADF;
  68. int n_wrote = fs::vfs_write(file->ind, buf, file->cursor, n);
  69. file->cursor += n_wrote;
  70. return n_wrote;
  71. }
  72. int _syscall_read(interrupt_stack* data)
  73. {
  74. int fd = data->s_regs.edi;
  75. char* buf = reinterpret_cast<char*>(data->s_regs.esi);
  76. size_t n = data->s_regs.edx;
  77. auto* file = current_process->files[fd];
  78. if (!file)
  79. return -EBADF;
  80. if (file->type == fs::file::types::directory)
  81. return -EBADF;
  82. // TODO: copy to user function !IMPORTANT
  83. int n_wrote = fs::vfs_read(file->ind, buf, n, file->cursor, n);
  84. if (n_wrote >= 0)
  85. file->cursor += n_wrote;
  86. return n_wrote;
  87. }
  88. int _syscall_sleep(interrupt_stack* data)
  89. {
  90. current_thread->attr.ready = 0;
  91. current_thread->attr.wait = 1;
  92. schedule();
  93. return 0;
  94. }
  95. int _syscall_chdir(interrupt_stack* data)
  96. {
  97. const char* path = reinterpret_cast<const char*>(data->s_regs.edi);
  98. auto* dir = fs::vfs_open(path);
  99. if (!dir)
  100. return -ENOENT;
  101. if (!dir->ind->flags.in.directory)
  102. return -ENOTDIR;
  103. current_process->pwd = path;
  104. return 0;
  105. }
  106. // syscall_exec(const char* exec, const char** argv)
  107. // @param exec: the path of program to execute
  108. // @param argv: arguments end with nullptr
  109. // @param envp: environment variables end with nullptr
  110. int _syscall_exec(interrupt_stack* data)
  111. {
  112. const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
  113. char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
  114. char* const* envp = reinterpret_cast<char* const*>(data->s_regs.edx);
  115. types::elf::elf32_load_data d;
  116. d.argv = argv;
  117. d.envp = envp;
  118. d.exec = exec;
  119. d.system = false;
  120. int ret = types::elf::elf32_load(&d);
  121. if (ret != GB_OK)
  122. return -d.errcode;
  123. data->v_eip = d.eip;
  124. data->esp = (uint32_t)d.sp;
  125. return 0;
  126. }
  127. // @param exit_code
  128. int _syscall_exit(interrupt_stack* data)
  129. {
  130. uint32_t exit_code = data->s_regs.edi;
  131. // TODO: terminating a thread only
  132. if (current_thread->owner->thds.size() != 1) {
  133. assert(false);
  134. }
  135. // terminating a whole process:
  136. procs->kill(current_process->pid, exit_code);
  137. // switch to new process and continue
  138. schedule();
  139. // we should not return to here
  140. assert(false);
  141. return -1;
  142. }
  143. // @param address of exit code: int*
  144. // @return pid of the exited process
  145. int _syscall_wait(interrupt_stack* data)
  146. {
  147. auto* arg1 = reinterpret_cast<int*>(data->s_regs.edi);
  148. auto& waitlst = current_process->wait_lst;
  149. if (waitlst.empty() && !procs->has_child(current_process->pid))
  150. return -ECHILD;
  151. while (waitlst.empty()) {
  152. current_thread->attr.ready = 0;
  153. current_thread->attr.wait = 1;
  154. waitlst.subscribe(current_thread);
  155. schedule();
  156. if (!waitlst.empty()) {
  157. waitlst.unsubscribe(current_thread);
  158. break;
  159. }
  160. }
  161. auto evt = waitlst.front();
  162. pid_t pid = (pid_t)evt.data1;
  163. // TODO: copy_to_user check privilege
  164. *arg1 = (int)evt.data2;
  165. procs->remove(pid);
  166. return pid;
  167. }
  168. int _syscall_getdents(interrupt_stack* data)
  169. {
  170. int fd = data->s_regs.edi;
  171. auto* buf = (char*)(data->s_regs.esi);
  172. size_t cnt = data->s_regs.edx;
  173. auto* dir = current_process->files[fd];
  174. if (dir->type != fs::file::types::directory)
  175. return -ENOTDIR;
  176. size_t orig_cnt = cnt;
  177. int nread = dir->ind->fs->inode_readdir(dir->ind, dir->cursor,
  178. [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
  179. if (!len)
  180. len = strlen(fn);
  181. size_t reclen = sizeof(fs::user_dirent) + 1 + len;
  182. if (cnt < reclen)
  183. return GB_FAILED;
  184. auto* dirp = (fs::user_dirent*)buf;
  185. dirp->d_ino = ino;
  186. dirp->d_reclen = reclen;
  187. // TODO: show offset
  188. // dirp->d_off = 0;
  189. // TODO: use copy_to_user
  190. memcpy(dirp->d_name, fn, len);
  191. buf[reclen - 2] = 0;
  192. buf[reclen - 1] = type;
  193. buf += reclen;
  194. cnt -= reclen;
  195. return GB_OK;
  196. });
  197. if (nread > 0)
  198. dir->cursor += nread;
  199. return orig_cnt - cnt;
  200. }
  201. int _syscall_open(interrupt_stack* data)
  202. {
  203. auto* path = (const char*)data->s_regs.edi;
  204. uint32_t flags = data->s_regs.esi;
  205. return current_process->files.open(path, flags);
  206. }
  207. int _syscall_getcwd(interrupt_stack* data)
  208. {
  209. char* buf = reinterpret_cast<char*>(data->s_regs.edi);
  210. size_t bufsize = reinterpret_cast<size_t>(data->s_regs.esi);
  211. // TODO: use copy_to_user
  212. strncpy(buf, current_process->pwd.c_str(), bufsize);
  213. buf[bufsize - 1] = 0;
  214. return (uint32_t)buf;
  215. }
  216. int _syscall_setsid(interrupt_stack* data)
  217. {
  218. if (current_process->pid == current_process->pgid)
  219. return -EPERM;
  220. current_process->sid = current_process->pid;
  221. current_process->pgid = current_process->pid;
  222. // TODO: get tty* from fd or block device id
  223. procs->set_ctrl_tty(current_process->pid, console);
  224. return current_process->pid;
  225. }
  226. int _syscall_getsid(interrupt_stack* data)
  227. {
  228. pid_t pid = data->s_regs.edi;
  229. auto* proc = procs->find(pid);
  230. if (!proc)
  231. return -ESRCH;
  232. if (proc->sid != current_process->sid)
  233. return -EPERM;
  234. return proc->sid;
  235. }
  236. int _syscall_close(interrupt_stack* data)
  237. {
  238. int fd = data->s_regs.edi;
  239. current_process->files.close(fd);
  240. return 0;
  241. }
  242. extern "C" void syscall_entry(interrupt_stack* data)
  243. {
  244. int ret = syscall_handlers[data->s_regs.eax](data);
  245. data->s_regs.eax = ret;
  246. check_signal();
  247. }
  248. SECTION(".text.kinit")
  249. void init_syscall(void)
  250. {
  251. syscall_handlers[0] = _syscall_fork;
  252. syscall_handlers[1] = _syscall_write;
  253. syscall_handlers[2] = _syscall_sleep;
  254. syscall_handlers[3] = _syscall_chdir;
  255. syscall_handlers[4] = _syscall_exec;
  256. syscall_handlers[5] = _syscall_exit;
  257. syscall_handlers[6] = _syscall_wait;
  258. syscall_handlers[7] = _syscall_read;
  259. syscall_handlers[8] = _syscall_getdents;
  260. syscall_handlers[9] = _syscall_open;
  261. syscall_handlers[10] = _syscall_getcwd;
  262. syscall_handlers[11] = _syscall_setsid;
  263. syscall_handlers[12] = _syscall_getsid;
  264. syscall_handlers[13] = _syscall_close;
  265. }