Syscall.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #include <Kernel/Arch/i386/CPU.h>
  2. #include <Kernel/Process.h>
  3. #include <Kernel/ProcessTracer.h>
  4. #include <Kernel/Syscall.h>
  5. #include <Kernel/VM/MemoryManager.h>
  6. extern "C" void syscall_trap_entry(RegisterDump);
  7. extern "C" void syscall_trap_handler();
  8. asm(
  9. ".globl syscall_trap_handler \n"
  10. "syscall_trap_handler:\n"
  11. " pushl $0x0\n"
  12. " pusha\n"
  13. " pushw %ds\n"
  14. " pushw %es\n"
  15. " pushw %fs\n"
  16. " pushw %gs\n"
  17. " pushw %ss\n"
  18. " pushw %ss\n"
  19. " pushw %ss\n"
  20. " pushw %ss\n"
  21. " pushw %ss\n"
  22. " popw %ds\n"
  23. " popw %es\n"
  24. " popw %fs\n"
  25. " popw %gs\n"
  26. " cld\n"
  27. " call syscall_trap_entry\n"
  28. " popw %gs\n"
  29. " popw %gs\n"
  30. " popw %fs\n"
  31. " popw %es\n"
  32. " popw %ds\n"
  33. " popa\n"
  34. " add $0x4, %esp\n"
  35. " iret\n");
  36. namespace Syscall {
  37. static int handle(RegisterDump&, u32 function, u32 arg1, u32 arg2, u32 arg3);
  38. void initialize()
  39. {
  40. register_user_callable_interrupt_handler(0x82, syscall_trap_handler);
  41. kprintf("Syscall: int 0x82 handler installed\n");
  42. }
  43. #pragma GCC diagnostic ignored "-Wcast-function-type"
  44. typedef int (Process::*Handler)(u32, u32, u32);
  45. #define __ENUMERATE_REMOVED_SYSCALL(x) nullptr,
  46. #define __ENUMERATE_SYSCALL(x) reinterpret_cast<Handler>(&Process::sys$##x),
  47. static Handler s_syscall_table[] = {
  48. ENUMERATE_SYSCALLS
  49. };
  50. #undef __ENUMERATE_SYSCALL
  51. #undef __ENUMERATE_REMOVED_SYSCALL
  52. int handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3)
  53. {
  54. ASSERT_INTERRUPTS_ENABLED();
  55. auto& process = current->process();
  56. process.did_syscall();
  57. if (function == SC_exit || function == SC_exit_thread) {
  58. // These syscalls need special handling since they never return to the caller.
  59. cli();
  60. if (auto* tracer = process.tracer())
  61. tracer->did_syscall(function, arg1, arg2, arg3, 0);
  62. if (function == SC_exit)
  63. process.sys$exit((int)arg1);
  64. else
  65. process.sys$exit_thread((void*)arg1);
  66. ASSERT_NOT_REACHED();
  67. return 0;
  68. }
  69. if (function == SC_fork)
  70. return process.sys$fork(regs);
  71. if (function == SC_sigreturn)
  72. return process.sys$sigreturn(regs);
  73. if (function >= Function::__Count) {
  74. dbg() << process << ": Unknown syscall %u requested (" << arg1 << ", " << arg2 << ", " << arg3 << ")";
  75. return -ENOSYS;
  76. }
  77. if (s_syscall_table[function] == nullptr) {
  78. dbg() << process << ": Null syscall " << function << " requested: \"" << to_string((Function)function) << "\", you probably need to rebuild this program.";
  79. return -ENOSYS;
  80. }
  81. return (process.*(s_syscall_table[function]))(arg1, arg2, arg3);
  82. }
  83. }
  84. void syscall_trap_entry(RegisterDump regs)
  85. {
  86. auto& process = current->process();
  87. if (!MM.validate_user_stack(process, VirtualAddress(regs.esp_if_crossRing))) {
  88. dbgprintf("Invalid stack pointer: %p\n", regs.esp_if_crossRing);
  89. handle_crash(regs, "Bad stack on syscall entry", SIGSTKFLT);
  90. ASSERT_NOT_REACHED();
  91. }
  92. process.big_lock().lock();
  93. u32 function = regs.eax;
  94. u32 arg1 = regs.edx;
  95. u32 arg2 = regs.ecx;
  96. u32 arg3 = regs.ebx;
  97. regs.eax = (u32)Syscall::handle(regs, function, arg1, arg2, arg3);
  98. if (auto* tracer = process.tracer())
  99. tracer->did_syscall(function, arg1, arg2, arg3, regs.eax);
  100. process.big_lock().unlock();
  101. // Check if we're supposed to return to userspace or just die.
  102. current->die_if_needed();
  103. }