#include #include "Common/MathUtils.h" #include "Tests/LinuxSyscalls/Syscalls.h" #include "Tests/LinuxSyscalls/x64/Syscalls.h" #include "Tests/LinuxSyscalls/x32/Syscalls.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BRK_SIZE 0x1000'0000 namespace FEX::HLE { SyscallHandler *_SyscallHandler{}; uint64_t SyscallHandler::HandleBRK(FEXCore::Core::InternalThreadState *Thread, void *Addr) { std::lock_guard lk(MMapMutex); uint64_t Result; if (DataSpace == 0) { DefaultProgramBreak(Thread); } if (Addr == nullptr) { // Just wants to get the location of the program break atm Result = DataSpace + DataSpaceSize; } else { // Allocating out data space uint64_t NewEnd = reinterpret_cast(Addr); if (NewEnd < DataSpace) { // Not allowed to move brk end below original start // Set the size to zero DataSpaceSize = 0; } else { uint64_t NewSize = NewEnd - DataSpace; // make sure we don't overflow to TLS storage if (NewSize >= BRK_SIZE) return -ENOMEM; DataSpaceSize = NewSize; } Result = DataSpace + DataSpaceSize; } return Result; } void SyscallHandler::DefaultProgramBreak(FEXCore::Core::InternalThreadState *Thread) { DataSpaceSize = 0; DataSpace = (uint64_t)mmap(nullptr, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } SyscallHandler::SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) : FM {ctx} , SignalDelegation {_SignalDelegation} { FEX::HLE::_SyscallHandler = this; HostKernelVersion = CalculateHostKernelVersion(); } uint32_t SyscallHandler::CalculateHostKernelVersion() { struct utsname buf{}; if (uname(&buf) == -1) { return 0; } int32_t Major{}; int32_t Minor{}; int32_t Patch{}; char Tmp{}; std::istringstream ss{buf.release}; ss >> Major; ss.read(&Tmp, 1); ss >> Minor; ss.read(&Tmp, 1); ss >> Patch; return (Major << 24) | (Minor << 16) | Patch; } uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::InternalThreadState *Thread, FEXCore::HLE::SyscallArguments *Args) { auto &Def = Definitions[Args->Argument[0]]; uint64_t Result{}; switch (Def.NumArgs) { case 0: Result = std::invoke(Def.Ptr0, Thread); break; case 1: Result = std::invoke(Def.Ptr1, Thread, Args->Argument[1]); break; case 2: Result = std::invoke(Def.Ptr2, Thread, Args->Argument[1], Args->Argument[2]); break; case 3: Result = std::invoke(Def.Ptr3, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3]); break; case 4: Result = std::invoke(Def.Ptr4, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4]); break; case 5: Result = std::invoke(Def.Ptr5, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5]); break; case 6: Result = std::invoke(Def.Ptr6, Thread, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Args->Argument[6]); break; // for missing syscalls case 255: return std::invoke(Def.Ptr1, Thread, Args->Argument[0]); default: LogMan::Msg::A("Unhandled syscall: %d", Args->Argument[0]); return -1; break; } #ifdef DEBUG_STRACE Strace(Args, Result); #endif return Result; } #ifdef DEBUG_STRACE void SyscallHandler::Strace(FEXCore::HLE::SyscallArguments *Args, uint64_t Ret) { auto &Def = Definitions[Args->Argument[0]]; switch (Def.NumArgs) { case 0: LogMan::Msg::D(Def.StraceFmt.c_str(), Ret); break; case 1: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Ret); break; case 2: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Ret); break; case 3: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Ret); break; case 4: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Ret); break; case 5: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Ret); break; case 6: LogMan::Msg::D(Def.StraceFmt.c_str(), Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5], Args->Argument[6], Ret); break; default: break; } } #endif FEX::HLE::SyscallHandler *CreateHandler(FEXCore::Context::OperatingMode Mode, FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, FEXCore::CodeLoader *Loader) { FEX::HLE::SyscallHandler *Result{}; if (Mode == FEXCore::Context::MODE_64BIT) { Result = FEX::HLE::x64::CreateHandler(ctx, _SignalDelegation); } else { Result = FEX::HLE::x32::CreateHandler(ctx, _SignalDelegation); } Result->SetCodeLoader(Loader); return Result; } }