syscall.cpp 8.1 KB

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