Syscall.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <Kernel/API/Syscall.h>
  8. #include <Kernel/Arch/TrapFrame.h>
  9. #include <Kernel/Arch/x86_64/Interrupts.h>
  10. #include <Kernel/Memory/MemoryManager.h>
  11. #include <Kernel/Panic.h>
  12. #include <Kernel/PerformanceManager.h>
  13. #include <Kernel/Process.h>
  14. #include <Kernel/Scheduler.h>
  15. #include <Kernel/Sections.h>
  16. #include <Kernel/ThreadTracer.h>
  17. namespace Kernel {
  18. extern "C" void syscall_handler(TrapFrame*) __attribute__((used));
  19. extern "C" void syscall_asm_entry();
  20. NEVER_INLINE NAKED void syscall_asm_entry()
  21. {
  22. // clang-format off
  23. #if ARCH(X86_64)
  24. asm(
  25. " pushq $0x0\n"
  26. " pushq %r15\n"
  27. " pushq %r14\n"
  28. " pushq %r13\n"
  29. " pushq %r12\n"
  30. " pushq %r11\n"
  31. " pushq %r10\n"
  32. " pushq %r9\n"
  33. " pushq %r8\n"
  34. " pushq %rax\n"
  35. " pushq %rcx\n"
  36. " pushq %rdx\n"
  37. " pushq %rbx\n"
  38. " pushq %rsp\n"
  39. " pushq %rbp\n"
  40. " pushq %rsi\n"
  41. " pushq %rdi\n"
  42. " pushq %rsp \n" /* set TrapFrame::regs */
  43. " subq $" __STRINGIFY(TRAP_FRAME_SIZE - 8) ", %rsp \n"
  44. " movq %rsp, %rdi \n"
  45. " cld\n"
  46. " call enter_trap_no_irq \n"
  47. " movq %rsp, %rdi \n"
  48. " call syscall_handler\n"
  49. " jmp common_trap_exit \n");
  50. #endif
  51. // clang-format on
  52. }
  53. namespace Syscall {
  54. static ErrorOr<FlatPtr> handle(RegisterState&, FlatPtr function, FlatPtr arg1, FlatPtr arg2, FlatPtr arg3, FlatPtr arg4);
  55. UNMAP_AFTER_INIT void initialize()
  56. {
  57. register_user_callable_interrupt_handler(syscall_vector, syscall_asm_entry);
  58. }
  59. using Handler = auto(Process::*)(FlatPtr, FlatPtr, FlatPtr, FlatPtr) -> ErrorOr<FlatPtr>;
  60. using HandlerWithRegisterState = auto(Process::*)(RegisterState&) -> ErrorOr<FlatPtr>;
  61. struct HandlerMetadata {
  62. Handler handler;
  63. NeedsBigProcessLock needs_lock;
  64. };
  65. #define __ENUMERATE_SYSCALL(sys_call, needs_lock) { bit_cast<Handler>(&Process::sys$##sys_call), needs_lock },
  66. static const HandlerMetadata s_syscall_table[] = {
  67. ENUMERATE_SYSCALLS(__ENUMERATE_SYSCALL)
  68. };
  69. #undef __ENUMERATE_SYSCALL
  70. ErrorOr<FlatPtr> handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, FlatPtr arg2, FlatPtr arg3, FlatPtr arg4)
  71. {
  72. VERIFY_INTERRUPTS_ENABLED();
  73. auto* current_thread = Thread::current();
  74. auto& process = current_thread->process();
  75. current_thread->did_syscall();
  76. PerformanceManager::add_syscall_event(*current_thread, regs);
  77. if (function >= Function::__Count) {
  78. dbgln("Unknown syscall {} requested ({:p}, {:p}, {:p}, {:p})", function, arg1, arg2, arg3, arg4);
  79. return ENOSYS;
  80. }
  81. auto const syscall_metadata = s_syscall_table[function];
  82. if (syscall_metadata.handler == nullptr) {
  83. dbgln("Null syscall {} requested, you probably need to rebuild this program!", function);
  84. return ENOSYS;
  85. }
  86. MutexLocker mutex_locker;
  87. auto const needs_big_lock = syscall_metadata.needs_lock == NeedsBigProcessLock::Yes;
  88. if (needs_big_lock) {
  89. mutex_locker.attach_and_lock(process.big_lock());
  90. };
  91. if (function == SC_exit || function == SC_exit_thread) {
  92. // These syscalls need special handling since they never return to the caller.
  93. // In these cases the process big lock will get released on the exit of the thread.
  94. if (auto* tracer = process.tracer(); tracer && tracer->is_tracing_syscalls()) {
  95. regs.set_return_reg(0);
  96. tracer->set_trace_syscalls(false);
  97. process.tracer_trap(*current_thread, regs); // this triggers SIGTRAP and stops the thread!
  98. }
  99. switch (function) {
  100. case SC_exit:
  101. process.sys$exit(arg1);
  102. case SC_exit_thread:
  103. process.sys$exit_thread(arg1, arg2, arg3);
  104. default:
  105. VERIFY_NOT_REACHED();
  106. }
  107. }
  108. ErrorOr<FlatPtr> result { FlatPtr(nullptr) };
  109. if (function == SC_fork || function == SC_sigreturn) {
  110. // These syscalls want the RegisterState& rather than individual parameters.
  111. auto handler = bit_cast<HandlerWithRegisterState>(syscall_metadata.handler);
  112. result = (process.*(handler))(regs);
  113. } else {
  114. result = (process.*(syscall_metadata.handler))(arg1, arg2, arg3, arg4);
  115. }
  116. return result;
  117. }
  118. }
  119. NEVER_INLINE void syscall_handler(TrapFrame* trap)
  120. {
  121. // Make sure SMAP protection is enabled on syscall entry.
  122. clac();
  123. auto& regs = *trap->regs;
  124. auto* current_thread = Thread::current();
  125. VERIFY(current_thread->previous_mode() == ExecutionMode::User);
  126. auto& process = current_thread->process();
  127. if (process.is_dying()) {
  128. // It's possible this thread is just about to make a syscall while another is
  129. // is killing our process.
  130. current_thread->die_if_needed();
  131. return;
  132. }
  133. if (auto* tracer = process.tracer(); tracer && tracer->is_tracing_syscalls()) {
  134. tracer->set_trace_syscalls(false);
  135. process.tracer_trap(*current_thread, regs); // this triggers SIGTRAP and stops the thread!
  136. }
  137. current_thread->yield_if_stopped();
  138. // Apply a random offset in the range 0-255 to the stack pointer,
  139. // to make kernel stacks a bit less deterministic.
  140. u32 lsw;
  141. u32 msw;
  142. read_tsc(lsw, msw);
  143. auto* ptr = (char*)__builtin_alloca(lsw & 0xff);
  144. asm volatile(""
  145. : "=m"(*ptr));
  146. constexpr FlatPtr iopl_mask = 3u << 12;
  147. FlatPtr flags = regs.flags();
  148. if ((flags & (iopl_mask)) != 0) {
  149. PANIC("Syscall from process with IOPL != 0");
  150. }
  151. Memory::MemoryManager::validate_syscall_preconditions(process, regs);
  152. FlatPtr function;
  153. FlatPtr arg1;
  154. FlatPtr arg2;
  155. FlatPtr arg3;
  156. FlatPtr arg4;
  157. regs.capture_syscall_params(function, arg1, arg2, arg3, arg4);
  158. auto result = Syscall::handle(regs, function, arg1, arg2, arg3, arg4);
  159. if (result.is_error()) {
  160. regs.set_return_reg(-result.error().code());
  161. } else {
  162. regs.set_return_reg(result.value());
  163. }
  164. if (auto* tracer = process.tracer(); tracer && tracer->is_tracing_syscalls()) {
  165. tracer->set_trace_syscalls(false);
  166. process.tracer_trap(*current_thread, regs); // this triggers SIGTRAP and stops the thread!
  167. }
  168. current_thread->yield_if_stopped();
  169. current_thread->check_dispatch_pending_signal();
  170. // If the previous mode somehow changed something is seriously messed up...
  171. VERIFY(current_thread->previous_mode() == ExecutionMode::User);
  172. // Check if we're supposed to return to userspace or just die.
  173. current_thread->die_if_needed();
  174. // Crash any processes which have committed a promise violation during syscall handling.
  175. if (result.is_error() && result.error().code() == EPROMISEVIOLATION) {
  176. VERIFY(current_thread->is_promise_violation_pending());
  177. current_thread->set_promise_violation_pending(false);
  178. process.crash(SIGABRT, 0);
  179. } else {
  180. VERIFY(!current_thread->is_promise_violation_pending());
  181. }
  182. VERIFY(!g_scheduler_lock.is_locked_by_current_processor());
  183. }
  184. }