Files
FEX-Emu--FEX/Source/Tools/LinuxEmulation/LinuxSyscalls/x64/Syscalls.cpp
T
Ryan Houdek 151e2279af Linux: Converts passthrough syscalls to direct passthrough handlers
Reimagining of #3355 without any json generators or new concepts.

Fixes some mislabeling of system calls. Some getting inlined when they
shouldn't be, a lot not getting inlined when they can be.

This really cleans up the syscall implementation, all syscalls that can
be passthrough implementations require a very small two line
declaration.
Additionally cleans up a bit of implementation cruft where some
passthrough syscalls were using the glibc syscall handler, and some were
using the glibc implementation. We have had multiple issues in the past
where the glibc implementation does something subtly different than the
raw syscall and breaks things. Now all passthrough handlers do a system
call directly, removing at least one indirection and some ambiguity.

This makes it significantly easier to add new passthrough syscalls as
well. Only need to do a version check and add the three lines per
syscall. Which there are new syscalls incoming that we will want to add.

Tangible improvements:
- Syscalls are lower overhead than ever.
- When I'm adding more syscalls I have less chance of mucking it up.
2024-02-27 02:40:53 -08:00

104 lines
3.6 KiB
C++

// SPDX-License-Identifier: MIT
/*
$info$
tags: LinuxSyscalls|syscalls-x86-64
$end_info$
*/
#include "LinuxSyscalls/Syscalls.h"
#include "LinuxSyscalls/x64/Syscalls.h"
#include "LinuxSyscalls/x64/SyscallsEnum.h"
#include <FEXCore/HLE/SyscallHandler.h>
namespace FEX::HLE::x64 {
void RegisterEpoll(FEX::HLE::SyscallHandler *Handler);
void RegisterFD(FEX::HLE::SyscallHandler *Handler);
void RegisterInfo(FEX::HLE::SyscallHandler *Handler);
void RegisterMemory(FEX::HLE::SyscallHandler *Handler);
void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler);
void RegisterSignals(FEX::HLE::SyscallHandler *Handler);
void RegisterThread(FEX::HLE::SyscallHandler *Handler);
void RegisterTime(FEX::HLE::SyscallHandler *Handler);
void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler);
void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler);
x64SyscallHandler::x64SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation)
: SyscallHandler {ctx, _SignalDelegation} {
OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX64;
RegisterSyscallHandlers();
}
void x64SyscallHandler::RegisterSyscallHandlers() {
auto cvt = [](auto in) {
union {
decltype(in) val;
void *raw;
} raw;
raw.val = in;
return raw.raw;
};
Definitions.resize(FEX::HLE::x64::SYSCALL_x64_MAX, SyscallFunctionDefinition {
.NumArgs = 255,
.Ptr = cvt(&UnimplementedSyscall),
});
FEX::HLE::RegisterEpoll(this);
FEX::HLE::RegisterFD(this);
FEX::HLE::RegisterFS(this);
FEX::HLE::RegisterInfo(this);
FEX::HLE::RegisterIO(this);
FEX::HLE::RegisterMemory(this);
FEX::HLE::RegisterSignals(this);
FEX::HLE::RegisterThread(this);
FEX::HLE::RegisterTimer(this);
FEX::HLE::RegisterNotImplemented(this);
FEX::HLE::RegisterStubs(this);
// 64bit specific
FEX::HLE::x64::RegisterEpoll(this);
FEX::HLE::x64::RegisterFD(this);
FEX::HLE::x64::RegisterInfo(this);
FEX::HLE::x64::RegisterMemory(this);
FEX::HLE::x64::RegisterSemaphore(this);
FEX::HLE::x64::RegisterSignals(this);
FEX::HLE::x64::RegisterThread(this);
FEX::HLE::x64::RegisterTime(this);
FEX::HLE::x64::RegisterNotImplemented(this);
FEX::HLE::x64::RegisterPassthrough(this);
// x86-64 has a gap of syscalls in the range of [335, 424) where there aren't any
// These are defined that these must return -ENOSYS
// This allows x86-64 to start using the common syscall numbers
// Fill the gap to ensure that FEX doesn't assert
constexpr int SYSCALL_GAP_BEGIN = 335;
constexpr int SYSCALL_GAP_END = 424;
for (int SyscallNumber = SYSCALL_GAP_BEGIN; SyscallNumber < SYSCALL_GAP_END; ++SyscallNumber) {
auto &Def = Definitions.at(SyscallNumber);
Def.Ptr = cvt(&UnimplementedSyscallSafe);
Def.NumArgs = 0;
Def.Flags = FEXCore::IR::SyscallFlags::DEFAULT;
// This will allow our syscall optimization code to make this code more optimal
// Unlikely to hit a hot path though
Def.HostSyscallNumber = SYSCALL_DEF(MAX);
#ifdef DEBUG_STRACE
Def.StraceFmt = "Invalid";
#endif
}
#if PRINT_MISSING_SYSCALLS
for (auto &Syscall: SyscallNames) {
if (Definitions[Syscall.first].Ptr == cvt(&UnimplementedSyscall)) {
LogMan::Msg::DFmt("Unimplemented syscall: {}", Syscall.second);
}
}
#endif
}
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation) {
return fextl::make_unique<x64SyscallHandler>(ctx, _SignalDelegation);
}
}