Files
FEX-Emu--FEX/Source/Tests/LinuxSyscalls/Syscalls.cpp
T
Scott Mansell 6ed36e3304 Refactor syscalls to take Frame
The vast majoirty of syscalls don't need anything in thread or frame.
So lets save an indirection for all those syscalls.

Most of the syscalls which do need Thread (or CTX via
Thread are in Thread.cpp or Memory.cpp
These have all been modifiy to fetch Thread from Frame
2021-03-09 20:28:50 +13:00

194 lines
6.9 KiB
C++

#include <FEXCore/Utils/LogManager.h>
#include "Common/MathUtils.h"
#include "Tests/LinuxSyscalls/Syscalls.h"
#include "Tests/LinuxSyscalls/x64/Syscalls.h"
#include "Tests/LinuxSyscalls/x32/Syscalls.h"
#include <FEXCore/Core/X86Enums.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/futex.h>
#include <numaif.h>
#include <poll.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/random.h>
#include <sys/sysinfo.h>
#include <sys/utsname.h>
#include <sys/shm.h>
#include <sys/syscall.h>
#include <unistd.h>
namespace FEX::HLE {
SyscallHandler *_SyscallHandler{};
uint64_t SyscallHandler::HandleBRK(FEXCore::Core::CpuStateFrame *Frame, void *Addr) {
std::lock_guard<std::mutex> lk(MMapMutex);
uint64_t Result;
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<uint64_t>(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;
uint64_t NewSizeAligned = AlignUp(NewSize, 4096);
if (NewSizeAligned < DataSpaceMaxSize) {
// If we are shrinking the brk then munmap the ranges
// That way we gain the memory back and also give the application zero pages if it allocates again
// DataspaceMaxSize is always page aligned
uint64_t RemainingSize = DataSpaceMaxSize - NewSizeAligned;
// We have pages we can unmap
munmap(reinterpret_cast<void*>(DataSpace + NewSizeAligned), RemainingSize);
DataSpaceMaxSize = NewSizeAligned;
}
else if (NewSize > DataSpaceMaxSize) {
constexpr static uint64_t SizeAlignment = 8 * 1024 * 1024;
uint64_t AllocateNewSize = AlignUp(NewSize, SizeAlignment) - DataSpaceMaxSize;
if (!Is64BitMode() &&
(DataSpace + DataSpaceMaxSize + AllocateNewSize > 0x1'0000'0000ULL)) {
// If we are 32bit and we tried going about the 32bit limit then out of memory
return DataSpace + DataSpaceSize;
}
uint64_t NewBRK = (uint64_t)mmap((void*)(DataSpace + DataSpaceMaxSize), AllocateNewSize, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (NewBRK != ~0ULL && NewBRK != (DataSpace + DataSpaceMaxSize)) {
// Couldn't allocate that the region we wanted
// Can happen if MAP_FIXED_NOREPLACE isn't understood by the kernel
munmap(reinterpret_cast<void*>(NewBRK), AllocateNewSize);
NewBRK = ~0ULL;
}
if (NewBRK == ~0ULL) {
// If we couldn't allocate a new region then out of memory
return DataSpace + DataSpaceSize;
}
else {
// Increase our BRK size
DataSpaceMaxSize += AllocateNewSize;
}
}
DataSpaceSize = NewSize;
}
Result = DataSpace + DataSpaceSize;
}
return Result;
}
void SyscallHandler::DefaultProgramBreak(uint64_t Base, uint64_t Size) {
DataSpace = Base;
DataSpaceMaxSize = Size;
DataSpaceStartingSize = Size;
}
SyscallHandler::SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation)
: FM {ctx}
, SignalDelegation {_SignalDelegation} {
FEX::HLE::_SyscallHandler = this;
HostKernelVersion = CalculateHostKernelVersion();
}
SyscallHandler::~SyscallHandler() {
munmap(reinterpret_cast<void*>(DataSpace + DataSpaceStartingSize), DataSpaceMaxSize - DataSpaceStartingSize);
}
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::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) {
auto &Def = Definitions[Args->Argument[0]];
uint64_t Result{};
switch (Def.NumArgs) {
case 0: Result = std::invoke(Def.Ptr0, Frame); break;
case 1: Result = std::invoke(Def.Ptr1, Frame, Args->Argument[1]); break;
case 2: Result = std::invoke(Def.Ptr2, Frame, Args->Argument[1], Args->Argument[2]); break;
case 3: Result = std::invoke(Def.Ptr3, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3]); break;
case 4: Result = std::invoke(Def.Ptr4, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4]); break;
case 5: Result = std::invoke(Def.Ptr5, Frame, Args->Argument[1], Args->Argument[2], Args->Argument[3], Args->Argument[4], Args->Argument[5]); break;
case 6: Result = std::invoke(Def.Ptr6, Frame, 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, Frame, 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
uint64_t UnimplementedSyscall(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber) {
ERROR_AND_DIE("Unhandled system call: %d", SyscallNumber);
return -ENOSYS;
}
uint64_t UnimplementedSyscallSafe(FEXCore::Core::CpuStateFrame *Frame, uint64_t SyscallNumber) {
return -ENOSYS;
}
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;
}
}