/** * Wrappers for various syscalls. * * WARNING: This file contains code that is known to the State of California to cause birth defects or reproductive harm */ #pragma once #include "./metaprogramming.hxx" enum class LnxSystemOp : long { READ = 0, WRITE = 1, OPEN = 2, CLOSE = 3, EXIT = 60, KEXEC_FILE_LOAD = 320 }; template concept LnxSystemCallArgumentType = MphStaticCastableTo<_Type, long> || MphIsPointer<_Type>::value; /** * Cast something to a long for a syscall * * \internal */ template inline long LnxSystemCallCast(_Type arg) { if constexpr (MphIsPointer::value) { return reinterpret_cast(arg); } else { return static_cast(arg); } } /** * Do a system call with only long arguments. This probably isn't memory safe. * * \internal */ template... _ArgTypes> [[using gnu: naked]] inline int LnxSystemCallInternal(long op, _ArgTypes... args) noexcept { // Move arguments to where they belong asm volatile ("mov %%rdi, %%rax" : : : "rax"); if constexpr (sizeof...(args) >= 1) asm volatile ("mov %%rsi, %%rdi" : : : "rdi"); if constexpr (sizeof...(args) >= 2) asm volatile ("mov %%rdx, %%rsi" : : : "rsi"); if constexpr (sizeof...(args) >= 3) asm volatile ("mov %%rcx, %%rdx" : : : "rdx"); if constexpr (sizeof...(args) >= 4) asm volatile ("mov %%r8, %%r10" : : : "r10"); if constexpr (sizeof...(args) >= 5) asm volatile ("mov %%r9, %%r8" : : : "r8" ); if constexpr (sizeof...(args) >= 6) asm volatile ("pop %%r9 " : : : "r9" ); // Call the system asm volatile ("syscall"); // Return. asm volatile ("ret"); } /** * Do a system call, heavily optimized * * \param op operation * \param args the arguments * \return system call return value */ template inline int LnxSystemCall(LnxSystemOp op, _ArgTypes... args) noexcept { return LnxSystemCallInternal(static_cast(op), LnxSystemCallCast(args)...); } /** * Write to a file descriptor */ inline int LnxWrite(int fileno, const char* path, long count) noexcept { return LnxSystemCall(LnxSystemOp::WRITE, fileno, path, count); } /** * Exit. */ [[noreturn]] inline int LnxExitProcess(int status) noexcept { LnxSystemCall(LnxSystemOp::EXIT, status); __builtin_unreachable(); }