mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 18:00:17 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee56a2cbde | ||
|
|
d66a83a98f | ||
|
|
067b346e1b | ||
|
|
ea7d1697b1 | ||
|
|
5fd91d34f1 | ||
|
|
11880459a5 | ||
|
|
0ef0bb2c97 | ||
|
|
72edee7c6f | ||
|
|
cb5644cf81 | ||
|
|
2dd922c3ce | ||
|
|
b7984e8651 | ||
|
|
31e976a5bc | ||
|
|
009ae55ff0 | ||
|
|
98572b9e23 | ||
|
|
1ab234f6dd | ||
|
|
fed5e6d546 | ||
|
|
f27e2246e2 | ||
|
|
4779fb74de | ||
|
|
eaf83aa6b4 | ||
|
|
4f8b28e83b | ||
|
|
c318947695 | ||
|
|
b3489d7262 | ||
|
|
44d738fa93 | ||
|
|
811487ad98 | ||
|
|
4f4e38ace2 | ||
|
|
edd6becc56 | ||
|
|
e47a94cae7 | ||
|
|
cc82dba1ca | ||
|
|
8232669b22 | ||
|
|
28936073c4 | ||
|
|
ef2559d911 | ||
|
|
d24446ed13 | ||
|
|
67f13ba927 | ||
|
|
dc5239c003 | ||
|
|
f346f89678 | ||
|
|
2f9449cb5a | ||
|
|
139367d248 | ||
|
|
fcebad51bd | ||
|
|
b50292493a | ||
|
|
b74de53056 | ||
|
|
49e798ab2b | ||
|
|
151e2279af | ||
|
|
93ada89708 | ||
|
|
f41674bb7d | ||
|
|
854fd70735 | ||
|
|
78a362581d | ||
|
|
8c0d5c6583 | ||
|
|
1c184997e7 | ||
|
|
ccc699444d | ||
|
|
946c805d84 | ||
|
|
118b8b200e | ||
|
|
aa9d7c5629 | ||
|
|
0b34035085 | ||
|
|
b6bd826014 | ||
|
|
12cc980603 | ||
|
|
f3d55dd721 | ||
|
|
91cef6b76f | ||
|
|
270cbf39b5 | ||
|
|
2e0be0a5e7 | ||
|
|
d60c089697 | ||
|
|
e76ebeab58 | ||
|
|
333271d490 | ||
|
|
a750870abf | ||
|
|
15db72ef60 | ||
|
|
9687ac51f0 | ||
|
|
5f16f357af | ||
|
|
4f028b8614 | ||
|
|
32a4abbea7 | ||
|
|
c00c9b397e | ||
|
|
6b5d8bd8c0 | ||
|
|
7deb4976a3 | ||
|
|
2cfd71c159 | ||
|
|
0f26780de0 | ||
|
|
1e153e0c81 | ||
|
|
6994fc3a01 | ||
|
|
0ef72bf118 | ||
|
|
49ca0e2181 | ||
|
|
947ae1c243 | ||
|
|
d703f3ccee | ||
|
|
d8a18687e8 | ||
|
|
045549f166 | ||
|
|
80e632db8a | ||
|
|
852e3c4e93 | ||
|
|
e86547bbcb | ||
|
|
883cca2e8f | ||
|
|
8540332520 | ||
|
|
df5bdefb8a | ||
|
|
3d1fb7701c | ||
|
|
140976d322 | ||
|
|
9a11d3b1a2 | ||
|
|
96e652879f | ||
|
|
cc1c1dd047 | ||
|
|
c1d572951f | ||
|
|
dd9d3264dd | ||
|
|
2aaf957ad8 | ||
|
|
d459b2f9b5 | ||
|
|
22ab7f2b3e | ||
|
|
f7e32373ce | ||
|
|
25d422e92b | ||
|
|
cfbeece09f | ||
|
|
a597a09825 | ||
|
|
99854ff310 | ||
|
|
44d1502b5a | ||
|
|
c3c635e36e | ||
|
|
7e2f20cabb | ||
|
|
3425b07711 | ||
|
|
9b93495d45 | ||
|
|
cf067994f3 | ||
|
|
0a64f8a9c5 | ||
|
|
3ac7fe3f05 | ||
|
|
be96cb7bd0 | ||
|
|
59ec88f48d | ||
|
|
6ec628fa31 | ||
|
|
90256730c3 | ||
|
|
3a0f9db512 | ||
|
|
5378ae2e76 | ||
|
|
cc9c80d79f | ||
|
|
60e8da05cd | ||
|
|
aac7fa9b58 | ||
|
|
bd4a81a2a1 | ||
|
|
a6211f29e7 | ||
|
|
da263834f8 | ||
|
|
3d671cba10 | ||
|
|
d4be2dc636 | ||
|
|
3e5694bd06 | ||
|
|
66feea9e8e | ||
|
|
2bcd285851 | ||
|
|
30ff225e80 | ||
|
|
8762bc1fa3 | ||
|
|
5b4162b712 | ||
|
|
cb5c07f4b1 | ||
|
|
3364b48f3b | ||
|
|
67530171e6 | ||
|
|
6f00611892 | ||
|
|
67941f04eb | ||
|
|
42531108b7 | ||
|
|
7edab7ee3b | ||
|
|
b9f2389d74 | ||
|
|
3c0b041c44 | ||
|
|
80fcd640be | ||
|
|
0908968e87 | ||
|
|
8e0543d9af | ||
|
|
b902b8edab | ||
|
|
9c38332e7e | ||
|
|
0503c89ff6 | ||
|
|
6dd410698a | ||
|
|
bbac014d6d | ||
|
|
a723ff09c1 | ||
|
|
5769ffbba7 | ||
|
|
a7c7fe4a35 | ||
|
|
80f20ad121 | ||
|
|
808ced455d | ||
|
|
0505b30d34 | ||
|
|
16a5d1a6b1 | ||
|
|
9cab746aa7 | ||
|
|
b888bb5ce5 | ||
|
|
47218254a1 | ||
|
|
fba5678476 | ||
|
|
68232366e4 | ||
|
|
d7ff1b78fb | ||
|
|
df3e51fc8c | ||
|
|
06c29eab88 |
No files matched your search
+1
-1
@@ -41,7 +41,7 @@
|
||||
url = https://github.com/FEX-Emu/drm-headers.git
|
||||
[submodule "External/xxhash"]
|
||||
path = External/xxhash
|
||||
url = https://github.com/FEX-Emu/xxHash.git
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
[submodule "External/Catch2"]
|
||||
path = External/Catch2
|
||||
url = https://github.com/catchorg/Catch2.git
|
||||
|
||||
+9
-2
@@ -122,6 +122,11 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64|^arm64|^armv8\.*")
|
||||
add_definitions(-D_M_ARM_64=1)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm64ec")
|
||||
set(_M_ARM_64EC 1)
|
||||
add_definitions(-D_M_ARM_64EC=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CCACHE)
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
@@ -232,8 +237,10 @@ endif()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Python 3.0 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
add_subdirectory(External/xxhash/)
|
||||
include_directories(External/xxhash/)
|
||||
set(XXHASH_BUNDLED_MODE TRUE)
|
||||
set(XXHASH_BUILD_XXHSUM FALSE)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(External/xxhash/cmake_unofficial/)
|
||||
|
||||
add_definitions(-Wno-trigraphs)
|
||||
add_definitions(-DGLOBAL_DATA_DIRECTORY="${DATA_DIRECTORY}/")
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"Config": {
|
||||
"AdditionalArguments": "--no-sandbox"
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
Submodule External/Vulkan-Headers updated: 85c2334e92...31aa7f634b.
Vendored
+1
-1
Submodule External/vixl updated: debc345683...7725aec177.
Vendored
+1
-1
Submodule External/xxhash updated: ba7375d54f...bbb27a5efb.
@@ -194,7 +194,7 @@ endif()
|
||||
# Some defines for the softfloat library
|
||||
list(APPEND DEFINES "-DSOFTFLOAT_BUILTIN_CLZ")
|
||||
|
||||
set (LIBS fmt::fmt vixl xxhash FEXHeaderUtils)
|
||||
set (LIBS fmt::fmt vixl xxHash::xxhash FEXHeaderUtils)
|
||||
|
||||
if (NOT MINGW_BUILD)
|
||||
list (APPEND LIBS dl)
|
||||
|
||||
@@ -115,6 +115,13 @@
|
||||
"\toff: Default CPU features queried from CPU features",
|
||||
"\t{enable,disable}sha: Will force enable or disable sha even if the host doesn't support it"
|
||||
]
|
||||
},
|
||||
"SmallTSCScale": {
|
||||
"Type": "bool",
|
||||
"Default": "true",
|
||||
"Desc": [
|
||||
"Scales the cycle counter on systems that have low frequencies."
|
||||
]
|
||||
}
|
||||
},
|
||||
"Emulation": {
|
||||
|
||||
@@ -74,6 +74,8 @@ namespace FEXCore::Context {
|
||||
};
|
||||
|
||||
using BlockDelinkerFunc = void(*)(FEXCore::Core::CpuStateFrame *Frame, FEXCore::Context::ExitFunctionLinkData *Record);
|
||||
constexpr uint32_t TSC_SCALE = 128;
|
||||
constexpr uint32_t TSC_SCALE_MAXIMUM = 1'000'000'000; ///< 1Ghz
|
||||
|
||||
class ContextImpl final : public FEXCore::Context::Context {
|
||||
public:
|
||||
@@ -230,6 +232,7 @@ namespace FEXCore::Context {
|
||||
FEX_CONFIG_OPT(x87ReducedPrecision, X87REDUCEDPRECISION);
|
||||
FEX_CONFIG_OPT(DisableTelemetry, DISABLETELEMETRY);
|
||||
FEX_CONFIG_OPT(DisableVixlIndirectCalls, DISABLE_VIXL_INDIRECT_RUNTIME_CALLS);
|
||||
FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE);
|
||||
} Config;
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace FEXCore::CPU {
|
||||
// TODO: Allow x18 register allocation on Linux in the future to gain one more register.
|
||||
|
||||
namespace x64 {
|
||||
#ifndef _M_ARM_64EC
|
||||
// All but x19 and x29 are caller saved
|
||||
constexpr std::array<FEXCore::ARMEmitter::Register, 18> SRA = {
|
||||
FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5,
|
||||
@@ -82,6 +83,54 @@ namespace x64 {
|
||||
FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13,
|
||||
FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15,
|
||||
};
|
||||
#else
|
||||
constexpr std::array<FEXCore::ARMEmitter::Register, 18> SRA = {
|
||||
FEXCore::ARMEmitter::Reg::r8, FEXCore::ARMEmitter::Reg::r0,
|
||||
FEXCore::ARMEmitter::Reg::r1, FEXCore::ARMEmitter::Reg::r27,
|
||||
// SP's register location isn't specified by the ARM64EC ABI, we choose to use r23
|
||||
FEXCore::ARMEmitter::Reg::r23, FEXCore::ARMEmitter::Reg::r29,
|
||||
FEXCore::ARMEmitter::Reg::r25, FEXCore::ARMEmitter::Reg::r26,
|
||||
FEXCore::ARMEmitter::Reg::r2, FEXCore::ARMEmitter::Reg::r3,
|
||||
FEXCore::ARMEmitter::Reg::r4, FEXCore::ARMEmitter::Reg::r5,
|
||||
FEXCore::ARMEmitter::Reg::r19, FEXCore::ARMEmitter::Reg::r20,
|
||||
FEXCore::ARMEmitter::Reg::r21, FEXCore::ARMEmitter::Reg::r22,
|
||||
REG_PF, REG_AF,
|
||||
};
|
||||
|
||||
constexpr std::array<FEXCore::ARMEmitter::Register, 7> RA = {
|
||||
FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7,
|
||||
FEXCore::ARMEmitter::Reg::r14,FEXCore::ARMEmitter::Reg::r15,
|
||||
FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17,
|
||||
FEXCore::ARMEmitter::Reg::r30,
|
||||
};
|
||||
|
||||
constexpr std::array<std::pair<FEXCore::ARMEmitter::Register, FEXCore::ARMEmitter::Register>, 3> RAPair = {{
|
||||
{FEXCore::ARMEmitter::Reg::r6, FEXCore::ARMEmitter::Reg::r7},
|
||||
{FEXCore::ARMEmitter::Reg::r14, FEXCore::ARMEmitter::Reg::r15},
|
||||
{FEXCore::ARMEmitter::Reg::r16, FEXCore::ARMEmitter::Reg::r17},
|
||||
}};
|
||||
|
||||
constexpr std::array<FEXCore::ARMEmitter::VRegister, 16> SRAFPR = {
|
||||
FEXCore::ARMEmitter::VReg::v0, FEXCore::ARMEmitter::VReg::v1,
|
||||
FEXCore::ARMEmitter::VReg::v2, FEXCore::ARMEmitter::VReg::v3,
|
||||
FEXCore::ARMEmitter::VReg::v4, FEXCore::ARMEmitter::VReg::v5,
|
||||
FEXCore::ARMEmitter::VReg::v6, FEXCore::ARMEmitter::VReg::v7,
|
||||
FEXCore::ARMEmitter::VReg::v8, FEXCore::ARMEmitter::VReg::v9,
|
||||
FEXCore::ARMEmitter::VReg::v10, FEXCore::ARMEmitter::VReg::v11,
|
||||
FEXCore::ARMEmitter::VReg::v12, FEXCore::ARMEmitter::VReg::v13,
|
||||
FEXCore::ARMEmitter::VReg::v14, FEXCore::ARMEmitter::VReg::v15,
|
||||
};
|
||||
|
||||
constexpr std::array<FEXCore::ARMEmitter::VRegister, 14> RAFPR = {
|
||||
FEXCore::ARMEmitter::VReg::v18, FEXCore::ARMEmitter::VReg::v19,
|
||||
FEXCore::ARMEmitter::VReg::v20, FEXCore::ARMEmitter::VReg::v21,
|
||||
FEXCore::ARMEmitter::VReg::v22, FEXCore::ARMEmitter::VReg::v23,
|
||||
FEXCore::ARMEmitter::VReg::v24, FEXCore::ARMEmitter::VReg::v25,
|
||||
FEXCore::ARMEmitter::VReg::v26, FEXCore::ARMEmitter::VReg::v27,
|
||||
FEXCore::ARMEmitter::VReg::v28, FEXCore::ARMEmitter::VReg::v29,
|
||||
FEXCore::ARMEmitter::VReg::v30, FEXCore::ARMEmitter::VReg::v31
|
||||
};
|
||||
#endif
|
||||
|
||||
// I wish this could get constexpr generated from SRA's definition but impossible until libstdc++12, libc++15.
|
||||
// SRA GPRs that need to be spilled when calling a function with `preserve_all` ABI.
|
||||
@@ -370,6 +419,9 @@ Arm64Emitter::Arm64Emitter(FEXCore::Context::ContextImpl *ctx, void* EmissionPtr
|
||||
GeneralPairRegisters = x64::RAPair;
|
||||
StaticFPRegisters = x64::SRAFPR;
|
||||
GeneralFPRegisters = x64::RAFPR;
|
||||
#ifdef _M_ARM_64EC
|
||||
ConfiguredDynamicRegisterBase = std::span(x64::RA.begin(), 7);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ConfiguredDynamicRegisterBase = std::span(x32::RA.begin() + 6, 8);
|
||||
@@ -931,7 +983,9 @@ void Arm64Emitter::PushDynamicRegsAndLR(FEXCore::ARMEmitter::Register TmpReg) {
|
||||
// Push the general registers.
|
||||
PushGeneralRegisters(TmpReg, ConfiguredDynamicRegisterBase);
|
||||
|
||||
#ifndef _M_ARM_64EC
|
||||
str(ARMEmitter::XReg::lr, TmpReg, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arm64Emitter::PopDynamicRegsAndLR() {
|
||||
@@ -943,7 +997,9 @@ void Arm64Emitter::PopDynamicRegsAndLR() {
|
||||
// Pop GPRs second
|
||||
PopGeneralRegisters(ConfiguredDynamicRegisterBase);
|
||||
|
||||
#ifndef _M_ARM_64EC
|
||||
ldr<ARMEmitter::IndexType::POST>(ARMEmitter::XReg::lr, ARMEmitter::Reg::rsp, 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arm64Emitter::SpillForPreserveAllABICall(FEXCore::ARMEmitter::Register TmpReg, bool FPRs) {
|
||||
|
||||
@@ -37,17 +37,37 @@ namespace FEXCore::CPU {
|
||||
// Contains the address to the currently available CPU state
|
||||
constexpr auto STATE = FEXCore::ARMEmitter::XReg::x28;
|
||||
|
||||
#ifndef _M_ARM_64EC
|
||||
// GPR temporaries. Only x3 can be used across spill boundaries
|
||||
// so if these ever need to change, be very careful about that.
|
||||
constexpr auto TMP1 = FEXCore::ARMEmitter::XReg::x0;
|
||||
constexpr auto TMP2 = FEXCore::ARMEmitter::XReg::x1;
|
||||
constexpr auto TMP3 = FEXCore::ARMEmitter::XReg::x2;
|
||||
constexpr auto TMP4 = FEXCore::ARMEmitter::XReg::x3;
|
||||
constexpr bool TMP_ABIARGS = true; // TMP{1-4} map to ABI arguments 0-3
|
||||
constexpr bool TMP_ABIARGS = true;
|
||||
|
||||
// We pin r26/r27 as PF/AF respectively, this is internal FEX ABI.
|
||||
constexpr auto REG_PF = FEXCore::ARMEmitter::Reg::r26;
|
||||
constexpr auto REG_AF = FEXCore::ARMEmitter::Reg::r27;
|
||||
|
||||
// Vector temporaries
|
||||
constexpr auto VTMP1 = FEXCore::ARMEmitter::VReg::v0;
|
||||
constexpr auto VTMP2 = FEXCore::ARMEmitter::VReg::v1;
|
||||
#else
|
||||
constexpr auto TMP1 = FEXCore::ARMEmitter::XReg::x10;
|
||||
constexpr auto TMP2 = FEXCore::ARMEmitter::XReg::x11;
|
||||
constexpr auto TMP3 = FEXCore::ARMEmitter::XReg::x12;
|
||||
constexpr auto TMP4 = FEXCore::ARMEmitter::XReg::x13;
|
||||
constexpr bool TMP_ABIARGS = false;
|
||||
|
||||
// We pin r11/r12 as PF/AF respectively for arm64ec, as r26/r27 are used for SRA.
|
||||
constexpr auto REG_PF = FEXCore::ARMEmitter::Reg::r9;
|
||||
constexpr auto REG_AF = FEXCore::ARMEmitter::Reg::r24;
|
||||
|
||||
// Vector temporaries
|
||||
constexpr auto VTMP1 = FEXCore::ARMEmitter::VReg::v16;
|
||||
constexpr auto VTMP2 = FEXCore::ARMEmitter::VReg::v17;
|
||||
#endif
|
||||
|
||||
// Predicate register temporaries (used when AVX support is enabled)
|
||||
// PRED_TMP_16B indicates a predicate register that indicates the first 16 bytes set to 1.
|
||||
@@ -55,9 +75,6 @@ constexpr auto VTMP2 = FEXCore::ARMEmitter::VReg::v1;
|
||||
constexpr FEXCore::ARMEmitter::PRegister PRED_TMP_16B = FEXCore::ARMEmitter::PReg::p6;
|
||||
constexpr FEXCore::ARMEmitter::PRegister PRED_TMP_32B = FEXCore::ARMEmitter::PReg::p7;
|
||||
|
||||
// We pin r26/r27 as PF/AF respectively, this is internal FEX ABI.
|
||||
constexpr auto REG_PF = FEXCore::ARMEmitter::Reg::r26;
|
||||
constexpr auto REG_AF = FEXCore::ARMEmitter::Reg::r27;
|
||||
|
||||
// This class contains common emitter utility functions that can
|
||||
// be used by both Arm64 JIT and ARM64 Dispatcher
|
||||
|
||||
@@ -98,7 +98,7 @@ constexpr uint32_t FAMILY_IDENTIFIER =
|
||||
#endif
|
||||
|
||||
#ifdef _M_ARM_64
|
||||
static uint32_t GetCycleCounterFrequency() {
|
||||
uint32_t GetCycleCounterFrequency() {
|
||||
uint64_t Result{};
|
||||
__asm("mrs %[Res], CNTFRQ_EL0"
|
||||
: [Res] "=r" (Result));
|
||||
@@ -349,7 +349,7 @@ void CPUIDEmu::SetupHostHybridFlag() {
|
||||
}
|
||||
|
||||
#else
|
||||
static uint32_t GetCycleCounterFrequency() {
|
||||
uint32_t GetCycleCounterFrequency() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -803,7 +803,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_15h(uint32_t Leaf) const {
|
||||
uint32_t FrequencyHz = GetCycleCounterFrequency();
|
||||
if (FrequencyHz) {
|
||||
Res.eax = 1;
|
||||
Res.ebx = 1;
|
||||
Res.ebx = CTX->Config.SmallTSCScale() ? FEXCore::Context::TSC_SCALE : 1;
|
||||
Res.ecx = FrequencyHz;
|
||||
}
|
||||
return Res;
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Context {
|
||||
class ContextImpl;
|
||||
}
|
||||
|
||||
uint32_t GetCycleCounterFrequency();
|
||||
|
||||
// Debugging define to switch what family of CPU we execute as.
|
||||
// Might be useful if an application makes an assumption about a CPU.
|
||||
// #define CPUID_AMD
|
||||
@@ -115,6 +117,7 @@ private:
|
||||
bool Hybrid{};
|
||||
uint32_t Cores{};
|
||||
FEX_CONFIG_OPT(HideHypervisorBit, HIDEHYPERVISORBIT);
|
||||
FEX_CONFIG_OPT(SmallTSCScale, SMALLTSCSCALE);
|
||||
|
||||
// XFEATURE_ENABLED_MASK
|
||||
// Mask that configures what features are enabled on the CPU.
|
||||
|
||||
@@ -99,6 +99,10 @@ namespace FEXCore::Context {
|
||||
Symbols.InitFile();
|
||||
}
|
||||
|
||||
if (FEXCore::GetCycleCounterFrequency() >= FEXCore::Context::TSC_SCALE_MAXIMUM) {
|
||||
Config.SmallTSCScale = false;
|
||||
}
|
||||
|
||||
// Track atomic TSO emulation configuration.
|
||||
UpdateAtomicTSOEmulationConfig();
|
||||
}
|
||||
@@ -277,6 +281,7 @@ namespace FEXCore::Context {
|
||||
.DispatcherBegin = Dispatcher->Start,
|
||||
.DispatcherEnd = Dispatcher->End,
|
||||
|
||||
.AbsoluteLoopTopAddress = Dispatcher->AbsoluteLoopTopAddress,
|
||||
.AbsoluteLoopTopAddressFillSRA = Dispatcher->AbsoluteLoopTopAddressFillSRA,
|
||||
.SignalHandlerReturnAddress = Dispatcher->SignalHandlerReturnAddress,
|
||||
.SignalHandlerReturnAddressRT = Dispatcher->SignalHandlerReturnAddressRT,
|
||||
@@ -343,14 +348,6 @@ namespace FEXCore::Context {
|
||||
Thread->ThreadManager.TID = FHU::Syscalls::gettid();
|
||||
Thread->ThreadManager.PID = ::getpid();
|
||||
|
||||
if (Config.BlockJITNaming() ||
|
||||
Config.GlobalJITNaming() ||
|
||||
Config.LibraryJITNaming()) {
|
||||
// Allocate a TLS JIT symbol buffer only if enabled.
|
||||
Thread->SymbolBuffer = JITSymbols::AllocateBuffer();
|
||||
}
|
||||
|
||||
SignalDelegation->RegisterTLSState(Thread);
|
||||
if (ThunkHandler) {
|
||||
ThunkHandler->RegisterTLSState(Thread);
|
||||
}
|
||||
@@ -415,6 +412,13 @@ namespace FEXCore::Context {
|
||||
Thread->CurrentFrame->State.DeferredSignalRefCount.Store(0);
|
||||
Thread->CurrentFrame->State.DeferredSignalFaultAddress = reinterpret_cast<Core::NonAtomicRefCounter<uint64_t>*>(FEXCore::Allocator::VirtualAlloc(4096));
|
||||
|
||||
if (Config.BlockJITNaming() ||
|
||||
Config.GlobalJITNaming() ||
|
||||
Config.LibraryJITNaming()) {
|
||||
// Allocate a JIT symbol buffer only if enabled.
|
||||
Thread->SymbolBuffer = JITSymbols::AllocateBuffer();
|
||||
}
|
||||
|
||||
return Thread;
|
||||
}
|
||||
|
||||
@@ -423,7 +427,6 @@ namespace FEXCore::Context {
|
||||
#ifndef _WIN32
|
||||
Alloc::OSAllocator::UninstallTLSData(Thread);
|
||||
#endif
|
||||
SignalDelegation->UninstallTLSState(Thread);
|
||||
}
|
||||
|
||||
FEXCore::Allocator::VirtualFree(reinterpret_cast<void*>(Thread->CurrentFrame->State.DeferredSignalFaultAddress), 4096);
|
||||
@@ -910,7 +913,6 @@ namespace FEXCore::Context {
|
||||
#ifndef _WIN32
|
||||
Alloc::OSAllocator::UninstallTLSData(Thread);
|
||||
#endif
|
||||
SignalDelegation->UninstallTLSState(Thread);
|
||||
}
|
||||
|
||||
static void InvalidateGuestThreadCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) {
|
||||
|
||||
@@ -85,6 +85,21 @@ DEF_OP(Add) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(AddWithFlags) {
|
||||
auto Op = IROp->C<IR::IROp_AddWithFlags>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == 4 || OpSize == 8, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
adds(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), Const);
|
||||
} else {
|
||||
adds(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(AddShift) {
|
||||
auto Op = IROp->C<IR::IROp_AddShift>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
@@ -97,16 +112,24 @@ DEF_OP(AddShift) {
|
||||
|
||||
DEF_OP(AddNZCV) {
|
||||
auto Op = IROp->C<IR::IROp_AddNZCV>();
|
||||
const auto OpSize = IROp->Size;
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
auto Src1 = GetReg(Op->Src1.ID());
|
||||
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
cmn(EmitSize, GetReg(Op->Src1.ID()), Const);
|
||||
LOGMAN_THROW_AA_FMT(OpSize >= 4, "Constant not allowed here");
|
||||
cmn(EmitSize, Src1, Const);
|
||||
} else {
|
||||
cmn(EmitSize, GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
unsigned Shift = OpSize < 4 ? (32 - (8 * OpSize)) : 0;
|
||||
|
||||
if (OpSize < 4) {
|
||||
lsl(ARMEmitter::Size::i32Bit, TMP1, Src1, Shift);
|
||||
cmn(EmitSize, TMP1, GetReg(Op->Src2.ID()), ARMEmitter::ShiftType::LSL, Shift);
|
||||
} else {
|
||||
cmn(EmitSize, Src1, GetReg(Op->Src2.ID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +143,36 @@ DEF_OP(AdcNZCV) {
|
||||
adcs(EmitSize, ARMEmitter::Reg::zr, GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(AdcWithFlags) {
|
||||
auto Op = IROp->C<IR::IROp_AdcWithFlags>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
adcs(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(Adc) {
|
||||
auto Op = IROp->C<IR::IROp_Adc>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
adc(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(SbbWithFlags) {
|
||||
auto Op = IROp->C<IR::IROp_SbbWithFlags>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
sbcs(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(SbbNZCV) {
|
||||
auto Op = IROp->C<IR::IROp_SbbNZCV>();
|
||||
const auto OpSize = IROp->Size;
|
||||
@@ -130,6 +183,16 @@ DEF_OP(SbbNZCV) {
|
||||
sbcs(EmitSize, ARMEmitter::Reg::zr, GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(Sbb) {
|
||||
auto Op = IROp->C<IR::IROp_Sbb>();
|
||||
const auto OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
sbc(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
|
||||
DEF_OP(TestNZ) {
|
||||
auto Op = IROp->C<IR::IROp_TestNZ>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
@@ -178,7 +241,7 @@ DEF_OP(Sub) {
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
sub(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), Const);
|
||||
} else {
|
||||
sub(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
sub(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,21 +255,47 @@ DEF_OP(SubShift) {
|
||||
sub(EmitSize, GetReg(Node), GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()), ConvertIRShiftType(Op->Shift), Op->ShiftAmount);
|
||||
}
|
||||
|
||||
DEF_OP(SubNZCV) {
|
||||
auto Op = IROp->C<IR::IROp_SubNZCV>();
|
||||
const auto OpSize = IROp->Size;
|
||||
DEF_OP(SubWithFlags) {
|
||||
auto Op = IROp->C<IR::IROp_SubWithFlags>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
LOGMAN_THROW_AA_FMT(OpSize == IR::i32Bit || OpSize == IR::i64Bit, "Unsupported {} size: {}", __func__, OpSize);
|
||||
LOGMAN_THROW_AA_FMT(OpSize == 4 || OpSize == 8, "Unsupported {} size: {}", __func__, OpSize);
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
cmp(EmitSize, GetReg(Op->Src1.ID()), Const);
|
||||
} else if (IsInlineConstant(Op->Src1, &Const)) {
|
||||
LOGMAN_THROW_AA_FMT(Const == 0, "Only valid constant");
|
||||
cmp(EmitSize, ARMEmitter::Reg::zr, GetReg(Op->Src2.ID()));
|
||||
subs(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), Const);
|
||||
} else {
|
||||
cmp(EmitSize, GetReg(Op->Src1.ID()), GetReg(Op->Src2.ID()));
|
||||
subs(EmitSize, GetReg(Node), GetZeroableReg(Op->Src1), GetReg(Op->Src2.ID()));
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(SubNZCV) {
|
||||
auto Op = IROp->C<IR::IROp_SubNZCV>();
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
|
||||
const auto EmitSize = OpSize == IR::i64Bit ? ARMEmitter::Size::i64Bit : ARMEmitter::Size::i32Bit;
|
||||
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
LOGMAN_THROW_AA_FMT(OpSize >= 4, "Constant not allowed here");
|
||||
cmp(EmitSize, GetReg(Op->Src1.ID()), Const);
|
||||
} else {
|
||||
unsigned Shift = OpSize < 4 ? (32 - (8 * OpSize)) : 0;
|
||||
ARMEmitter::Register ShiftedSrc1 = GetZeroableReg(Op->Src1);
|
||||
|
||||
// Shift to fix flags for <32-bit ops.
|
||||
// Any shift of zero is still zero so optimize out silly zero shifts.
|
||||
if (OpSize < 4 && ShiftedSrc1 != ARMEmitter::Reg::zr) {
|
||||
lsl(ARMEmitter::Size::i32Bit, TMP1, ShiftedSrc1, Shift);
|
||||
ShiftedSrc1 = TMP1;
|
||||
}
|
||||
|
||||
if (OpSize < 4) {
|
||||
cmp(EmitSize, ShiftedSrc1, GetReg(Op->Src2.ID()), ARMEmitter::ShiftType::LSL, Shift);
|
||||
} else {
|
||||
cmp(EmitSize, ShiftedSrc1, GetReg(Op->Src2.ID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +311,20 @@ DEF_OP(RmifNZCV) {
|
||||
rmif(GetReg(Op->Src.ID()).X(), Op->Rotate, Op->Mask);
|
||||
}
|
||||
|
||||
DEF_OP(SetSmallNZV) {
|
||||
auto Op = IROp->C<IR::IROp_SetSmallNZV>();
|
||||
LOGMAN_THROW_A_FMT(CTX->HostFeatures.SupportsFlagM, "Unsupported flagm op");
|
||||
|
||||
const uint8_t OpSize = IROp->Size;
|
||||
LOGMAN_THROW_AA_FMT(OpSize == 1 || OpSize == 2, "Unsupported {} size: {}", __func__, OpSize);
|
||||
|
||||
if (OpSize == 1) {
|
||||
setf8(GetReg(Op->Src.ID()).W());
|
||||
} else {
|
||||
setf16(GetReg(Op->Src.ID()).W());
|
||||
}
|
||||
}
|
||||
|
||||
DEF_OP(AXFlag) {
|
||||
LOGMAN_THROW_A_FMT(CTX->HostFeatures.SupportsFlagM2, "Unsupported flagm2 op");
|
||||
axflag();
|
||||
@@ -264,9 +367,7 @@ DEF_OP(CondAddNZCV) {
|
||||
|
||||
ARMEmitter::StatusFlags Flags = (ARMEmitter::StatusFlags)Op->FalseNZCV;
|
||||
uint64_t Const = 0;
|
||||
auto Src1 = IsInlineConstant(Op->Src1, &Const) ? ARMEmitter::Reg::zr :
|
||||
GetReg(Op->Src1.ID());
|
||||
LOGMAN_THROW_A_FMT(Const == 0, "Unsupported inline constant");
|
||||
auto Src1 = GetZeroableReg(Op->Src1);
|
||||
|
||||
if (IsInlineConstant(Op->Src2, &Const)) {
|
||||
ccmn(EmitSize, Src1, Const, Flags, MapSelectCC(Op->Cond));
|
||||
@@ -1470,11 +1571,8 @@ DEF_OP(NZCVSelect) {
|
||||
csetm(EmitSize, Dst, cc);
|
||||
else
|
||||
cset(EmitSize, Dst, cc);
|
||||
} else if (is_const_false) {
|
||||
LOGMAN_THROW_A_FMT(const_false == 0, "NZCVSelect: unsupported constant");
|
||||
csel(EmitSize, Dst, GetReg(Op->TrueVal.ID()), ARMEmitter::Reg::zr, cc);
|
||||
} else {
|
||||
csel(EmitSize, Dst, GetReg(Op->TrueVal.ID()), GetReg(Op->FalseVal.ID()), cc);
|
||||
csel(EmitSize, Dst, GetReg(Op->TrueVal.ID()), GetZeroableReg(Op->FalseVal), cc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -310,8 +310,7 @@ DEF_OP(AtomicSwap) {
|
||||
OpSize == 1 ? ARMEmitter::SubRegSize::i8Bit : ARMEmitter::SubRegSize::i8Bit;
|
||||
|
||||
if (CTX->HostFeatures.SupportsAtomics) {
|
||||
mov(EmitSize, TMP2, Src);
|
||||
ldswpal(SubEmitSize, TMP2, GetReg(Node), MemSrc);
|
||||
ldswpal(SubEmitSize, Src, GetReg(Node), MemSrc);
|
||||
}
|
||||
else {
|
||||
ARMEmitter::BackwardLabel LoopTop;
|
||||
|
||||
@@ -116,6 +116,16 @@ private:
|
||||
return PhyReg;
|
||||
}
|
||||
|
||||
[[nodiscard]] FEXCore::ARMEmitter::Register GetZeroableReg(IR::OrderedNodeWrapper Src) const {
|
||||
uint64_t Const;
|
||||
if (IsInlineConstant(Src, &Const)) {
|
||||
LOGMAN_THROW_AA_FMT(Const == 0, "Only valid constant");
|
||||
return ARMEmitter::Reg::zr;
|
||||
} else {
|
||||
return GetReg(Src.ID());
|
||||
}
|
||||
}
|
||||
|
||||
// Converts IR-base shift type to ARMEmitter shift type.
|
||||
// Will be a no-op, only a type conversion since the two definitions match.
|
||||
[[nodiscard]] ARMEmitter::ShiftType ConvertIRShiftType(IR::ShiftType Shift) const {
|
||||
|
||||
@@ -338,129 +338,48 @@ void OpDispatchBuilder::CallbackReturnOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SecondaryALUOp(OpcodeArgs) {
|
||||
FEXCore::IR::IROps IROp;
|
||||
FEXCore::IR::IROps IROp, AtomicIROp;
|
||||
#define OPD(group, prefix, Reg) (((group - FEXCore::X86Tables::TYPE_GROUP_1) << 6) | (prefix) << 3 | (Reg))
|
||||
switch (Op->OP) {
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 0):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 0):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 0):
|
||||
IROp = FEXCore::IR::IROps::OP_ADD;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHADD;
|
||||
break;
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 1):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 1):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 1):
|
||||
IROp = FEXCore::IR::IROps::OP_OR;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHOR;
|
||||
break;
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 4):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 4):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 4):
|
||||
IROp = FEXCore::IR::IROps::OP_ANDWITHFLAGS;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHAND;
|
||||
break;
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 5):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 5):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 5):
|
||||
IROp = FEXCore::IR::IROps::OP_SUB;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHSUB;
|
||||
break;
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 6):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 6):
|
||||
case OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 6):
|
||||
IROp = FEXCore::IR::IROps::OP_XOR;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_ATOMICFETCHXOR;
|
||||
break;
|
||||
default:
|
||||
IROp = FEXCore::IR::IROps::OP_LAST;
|
||||
AtomicIROp = FEXCore::IR::IROps::OP_LAST;
|
||||
LOGMAN_MSG_A_FMT("Unknown ALU Op: 0x{:x}", Op->OP);
|
||||
break;
|
||||
};
|
||||
#undef OPD
|
||||
// Logical ops can tolerate garbage in the upper bits, so don't mask.
|
||||
bool AllowUpperGarbage = IROp == FEXCore::IR::IROps::OP_ANDWITHFLAGS ||
|
||||
IROp == FEXCore::IR::IROps::OP_XOR ||
|
||||
IROp == FEXCore::IR::IROps::OP_OR;
|
||||
|
||||
// X86 basic ALU ops just do the operation between the destination and a single source
|
||||
uint8_t Size = GetDstSize(Op);
|
||||
auto Src = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, {.AllowUpperGarbage = AllowUpperGarbage || Size >= 4});
|
||||
OrderedNode *Result{};
|
||||
OrderedNode *Dest{};
|
||||
|
||||
if (DestIsLockedMem(Op)) {
|
||||
HandledLock = true;
|
||||
auto DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
|
||||
switch (IROp) {
|
||||
case FEXCore::IR::IROps::OP_ADD: {
|
||||
Dest = _AtomicFetchAdd(IR::SizeToOpSize(Size), Src, DestMem);
|
||||
Result = _Add(IR::SizeToOpSize(std::max<uint8_t>(4u, std::max(GetOpSize(Dest), GetOpSize(Src)))), Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_SUB: {
|
||||
Dest = _AtomicFetchSub(IR::SizeToOpSize(Size), Src, DestMem);
|
||||
Result = _Sub(IR::SizeToOpSize(std::max<uint8_t>(4u, std::max(GetOpSize(Dest), GetOpSize(Src)))), Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_OR: {
|
||||
Dest = _AtomicFetchOr(IR::SizeToOpSize(Size), Src, DestMem);
|
||||
Result = _Or(IR::SizeToOpSize(std::max<uint8_t>(4u, std::max(GetOpSize(Dest), GetOpSize(Src)))), Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_ANDWITHFLAGS: {
|
||||
Dest = _AtomicFetchAnd(IR::SizeToOpSize(Size), Src, DestMem);
|
||||
Result = _AndWithFlags(IR::SizeToOpSize(std::max(GetOpSize(Dest), GetOpSize(Src))), Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_XOR: {
|
||||
Dest = _AtomicFetchXor(IR::SizeToOpSize(Size), Src, DestMem);
|
||||
Result = _Xor(IR::SizeToOpSize(std::max<uint8_t>(4u, std::max(GetOpSize(Dest), GetOpSize(Src)))), Dest, Src);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOGMAN_MSG_A_FMT("Unknown Atomic IR Op: {}", ToUnderlying(IROp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = AllowUpperGarbage || Size >= 4});
|
||||
|
||||
if (IROp != FEXCore::IR::IROps::OP_ANDWITHFLAGS)
|
||||
Size = std::max<uint8_t>(4u, Size);
|
||||
|
||||
DeriveOp(ALUOp, IROp, _AndWithFlags(IR::SizeToOpSize(Size), Dest, Src));
|
||||
|
||||
Result = ALUOp;
|
||||
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
// Flags set
|
||||
{
|
||||
switch (IROp) {
|
||||
case FEXCore::IR::IROps::OP_ADD:
|
||||
GenerateFlags_ADD(Op, Result, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_SUB:
|
||||
GenerateFlags_SUB(Op, Result, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_XOR:
|
||||
case FEXCore::IR::IROps::OP_OR: {
|
||||
GenerateFlags_Logical(Op, Result, Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_ANDWITHFLAGS: {
|
||||
InvalidateDeferredFlags();
|
||||
|
||||
// SF/ZF/CF/OF
|
||||
CachedNZCV = nullptr;
|
||||
PossiblySetNZCVBits = (1u << 31) | (1u << 30);
|
||||
NZCVDirty = false;
|
||||
|
||||
// PF/AF
|
||||
CalculatePF(Result);
|
||||
_InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
ALUOpImpl(Op, IROp, AtomicIROp, 1);
|
||||
}
|
||||
|
||||
template<uint32_t SrcIndex>
|
||||
@@ -468,66 +387,64 @@ void OpDispatchBuilder::ADCOp(OpcodeArgs) {
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags);
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true});
|
||||
uint8_t Size = GetDstSize(Op);
|
||||
const auto OpSize = IR::SizeToOpSize(std::max<uint8_t>(4u, Size));
|
||||
|
||||
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
auto ALUOp = _Add(OpSize, Src, CF);
|
||||
|
||||
OrderedNode *Result{};
|
||||
OrderedNode *Before{};
|
||||
if (DestIsLockedMem(Op)) {
|
||||
auto ALUOp = _Adc(OpSize, _Constant(0), Src);
|
||||
|
||||
HandledLock = true;
|
||||
OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
|
||||
Before = _AtomicFetchAdd(IR::SizeToOpSize(Size), ALUOp, DestMem);
|
||||
Result = _Add(OpSize, Before, ALUOp);
|
||||
}
|
||||
else {
|
||||
Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags);
|
||||
Result = _Add(OpSize, Before, ALUOp);
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
}
|
||||
|
||||
if (Size < 4)
|
||||
Result = _Bfe(IR::SizeToOpSize(std::max<uint8_t>(4u, Size)), Size * 8, 0, Result);
|
||||
GenerateFlags_ADC(Op, Result, Before, Src, CF);
|
||||
OrderedNode *Result = CalculateFlags_ADC(Size, Before, Src);
|
||||
if (!DestIsLockedMem(Op))
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
template<uint32_t SrcIndex, bool SetFlags>
|
||||
template<uint32_t SrcIndex>
|
||||
void OpDispatchBuilder::SBBOp(OpcodeArgs) {
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags);
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true});
|
||||
auto Size = GetDstSize(Op);
|
||||
const auto OpSize = IR::SizeToOpSize(std::max<uint8_t>(4u, Size));
|
||||
|
||||
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
auto ALUOp = _Add(OpSize, Src, CF);
|
||||
|
||||
OrderedNode *Result{};
|
||||
OrderedNode *Before{};
|
||||
if (DestIsLockedMem(Op)) {
|
||||
HandledLock = true;
|
||||
OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
|
||||
Before = _AtomicFetchSub(IR::SizeToOpSize(Size), ALUOp, DestMem);
|
||||
Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Before, ALUOp);
|
||||
|
||||
auto SrcPlusCF = _Adc(OpSize, _Constant(0), Src);
|
||||
Before = _AtomicFetchSub(IR::SizeToOpSize(Size), SrcPlusCF, DestMem);
|
||||
}
|
||||
else {
|
||||
Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags);
|
||||
Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Before, ALUOp);
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
}
|
||||
|
||||
if (SetFlags) {
|
||||
if (Size < 4) {
|
||||
Result = _Bfe(IR::SizeToOpSize(std::max<uint8_t>(4u, Size)), Size * 8, 0, Result);
|
||||
}
|
||||
GenerateFlags_SBB(Op, Result, Before, Src, CF);
|
||||
}
|
||||
Result = CalculateFlags_SBB(Size, Before, Src);
|
||||
|
||||
if (!DestIsLockedMem(Op))
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::SALCOp(OpcodeArgs) {
|
||||
CalculateDeferredFlags();
|
||||
|
||||
auto Result = _NZCVSelect(OpSize::i32Bit, CondClassType{COND_UGE} /* CF = 1 */,
|
||||
_Constant(0xffffffff), _Constant(0));
|
||||
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::PUSHOp(OpcodeArgs) {
|
||||
@@ -1303,16 +1220,8 @@ void OpDispatchBuilder::TESTOp(OpcodeArgs) {
|
||||
Src = Dest;
|
||||
}
|
||||
|
||||
InvalidateDeferredFlags();
|
||||
|
||||
// SF/ZF/CF/OF
|
||||
OrderedNode *ALUOp = _AndWithFlags(IR::SizeToOpSize(Size), Dest, Src);
|
||||
CachedNZCV = nullptr;
|
||||
PossiblySetNZCVBits = (1u << 31) | (1u << 30);
|
||||
NZCVDirty = false;
|
||||
|
||||
// PF/AF
|
||||
CalculatePF(ALUOp);
|
||||
HandleNZ00Write();
|
||||
CalculatePF(_AndWithFlags(IR::SizeToOpSize(Size), Dest, Src));
|
||||
_InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC);
|
||||
}
|
||||
|
||||
@@ -1363,14 +1272,9 @@ template<uint32_t SrcIndex>
|
||||
void OpDispatchBuilder::CMPOp(OpcodeArgs) {
|
||||
// CMP is an instruction that does a SUB between the sources
|
||||
// Result isn't stored in result, only writes to flags
|
||||
auto Size = GetDstSize(Op);
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = Size >= 4});
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= 4});
|
||||
|
||||
auto ALUOp = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Dest, Src);
|
||||
|
||||
OrderedNode *Result = ALUOp;
|
||||
GenerateFlags_SUB(Op, Result, Dest, Src);
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIndex], Op->Flags, {.AllowUpperGarbage = true});
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
GenerateFlags_SUB(Op, Dest, Src);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CQOOp(OpcodeArgs) {
|
||||
@@ -1808,9 +1712,7 @@ void OpDispatchBuilder::SHLDOp(OpcodeArgs) {
|
||||
|
||||
StoreResult(GPRClass, Op, Res, -1);
|
||||
|
||||
if (Size != 64) {
|
||||
Res = _Bfe(OpSize::i64Bit, Size, 0, Res);
|
||||
}
|
||||
// No need to mask result, upper garbage is ignored in the flag calc
|
||||
GenerateFlags_ShiftLeft(Op, Res, Dest, Shift);
|
||||
}
|
||||
|
||||
@@ -3196,29 +3098,23 @@ void OpDispatchBuilder::XADDOp(OpcodeArgs) {
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
OrderedNode *Result;
|
||||
|
||||
const auto Size = GetSrcBitSize(Op);
|
||||
const auto OpSize = Size == 64 ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
|
||||
if (Op->Dest.IsGPR()) {
|
||||
// If this is a GPR then we can just do an Add
|
||||
Result = _Add(OpSize, Dest, Src);
|
||||
Result = CalculateFlags_ADD(GetSrcSize(Op), Dest, Src);
|
||||
|
||||
// Previous value in dest gets stored in src
|
||||
StoreResult(GPRClass, Op, Op->Src[0], Dest, -1);
|
||||
|
||||
// Calculated value gets stored in dst (order is important if dst is same as src)
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
|
||||
GenerateFlags_ADD(Op, Result, Dest, Src);
|
||||
}
|
||||
else {
|
||||
HandledLock = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_LOCK;
|
||||
Dest = AppendSegmentOffset(Dest, Op->Flags);
|
||||
auto Before = _AtomicFetchAdd(OpSizeFromSrc(Op), Src, Dest);
|
||||
StoreResult(GPRClass, Op, Op->Src[0], Before, -1);
|
||||
Result = _Add(OpSize, Before, Src); // Seperate result just for flags
|
||||
|
||||
GenerateFlags_ADD(Op, Result, Before, Src);
|
||||
CalculateFlags_ADD(GetSrcSize(Op), Before, Src);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3596,12 +3492,31 @@ void OpDispatchBuilder::SGDTOp(OpcodeArgs) {
|
||||
_StoreMemAutoTSO(GPRClass, GDTStoreSize, _Add(OpSize::i64Bit, DestAddress, _Constant(2)), _Constant(GDTAddress));
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RDTSCOp(OpcodeArgs) {
|
||||
|
||||
OpDispatchBuilder::CycleCounterPair OpDispatchBuilder::CycleCounter() {
|
||||
OrderedNode *CounterLow{};
|
||||
OrderedNode *CounterHigh{};
|
||||
auto Counter = _CycleCounter();
|
||||
auto CounterLow = _Bfe(OpSize::i64Bit, 32, 0, Counter);
|
||||
auto CounterHigh = _Bfe(OpSize::i64Bit, 32, 32, Counter);
|
||||
StoreGPRRegister(X86State::REG_RAX, CounterLow);
|
||||
StoreGPRRegister(X86State::REG_RDX, CounterHigh);
|
||||
if (CTX->Config.SmallTSCScale()) {
|
||||
const auto ShiftAmount = FEXCore::ilog2(FEXCore::Context::TSC_SCALE);
|
||||
CounterLow = _Lshl(OpSize::i32Bit, Counter, _Constant(ShiftAmount));
|
||||
CounterHigh = _Lshr(OpSize::i64Bit, Counter, _Constant(32 - ShiftAmount));
|
||||
}
|
||||
else {
|
||||
CounterLow = _Bfe(OpSize::i64Bit, 32, 0, Counter);
|
||||
CounterHigh = _Bfe(OpSize::i64Bit, 32, 32, Counter);
|
||||
}
|
||||
|
||||
return {
|
||||
.CounterLow = CounterLow,
|
||||
.CounterHigh = CounterHigh,
|
||||
};
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RDTSCOp(OpcodeArgs) {
|
||||
auto Counter = CycleCounter();
|
||||
StoreGPRRegister(X86State::REG_RAX, Counter.CounterLow);
|
||||
StoreGPRRegister(X86State::REG_RDX, Counter.CounterHigh);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::INCOp(OpcodeArgs) {
|
||||
@@ -3628,12 +3543,28 @@ void OpDispatchBuilder::INCOp(OpcodeArgs) {
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= 32});
|
||||
}
|
||||
|
||||
Result = _Add(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, OneConst);
|
||||
CalculateDeferredFlags();
|
||||
|
||||
if (Size < 32 && CTX->HostFeatures.SupportsFlagM) {
|
||||
// Addition producing upper garbage
|
||||
Result = _Add(OpSize::i32Bit, Dest, OneConst);
|
||||
CalculatePF(Result);
|
||||
CalculateAF(Dest, OneConst);
|
||||
|
||||
// Correctly set NZ flags, preserving C
|
||||
HandleNZCV_RMW();
|
||||
_SetSmallNZV(OpSizeFromSrc(Op), Result);
|
||||
|
||||
// Fix up V flag. INC overflows only when incrementing a positive and
|
||||
// getting a negative. So compare the sign bits to calculate V.
|
||||
_RmifNZCV(_Andn(OpSize::i32Bit, Result, Dest), Size - 1, 1);
|
||||
} else {
|
||||
Result = CalculateFlags_ADD(OpSizeFromSrc(Op), Dest, OneConst, false);
|
||||
}
|
||||
|
||||
if (!IsLocked) {
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
GenerateFlags_ADD(Op, Result, Dest, OneConst, false);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DECOp(OpcodeArgs) {
|
||||
@@ -3654,17 +3585,35 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) {
|
||||
HandledLock = true;
|
||||
auto DestAddress = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
DestAddress = AppendSegmentOffset(DestAddress, Op->Flags);
|
||||
Dest = _AtomicFetchSub(OpSizeFromSrc(Op), OneConst, DestAddress);
|
||||
|
||||
// Use Add instead of Sub to avoid a NEG
|
||||
Dest = _AtomicFetchAdd(OpSizeFromSrc(Op), _Constant(Size, -1), DestAddress);
|
||||
} else {
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = Size >= 32});
|
||||
}
|
||||
|
||||
Result = _Sub(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Dest, OneConst);
|
||||
CalculateDeferredFlags();
|
||||
|
||||
if (Size < 32 && CTX->HostFeatures.SupportsFlagM) {
|
||||
// Subtraction producing upper garbage
|
||||
Result = _Sub(OpSize::i32Bit, Dest, OneConst);
|
||||
CalculatePF(Result);
|
||||
CalculateAF(Dest, OneConst);
|
||||
|
||||
// Correctly set NZ flags, preserving C
|
||||
HandleNZCV_RMW();
|
||||
_SetSmallNZV(OpSizeFromSrc(Op), Result);
|
||||
|
||||
// Fix up V flag. DEC overflows only when decrementing a negative and
|
||||
// getting a positive. So compare the sign bits to calculate V.
|
||||
_RmifNZCV(_Andn(OpSize::i32Bit, Dest, Result), Size - 1, 1);
|
||||
} else {
|
||||
Result = CalculateFlags_SUB(OpSizeFromSrc(Op), Dest, OneConst, false);
|
||||
}
|
||||
|
||||
if (!IsLocked) {
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
GenerateFlags_SUB(Op, Result, Dest, OneConst, false);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
@@ -3794,8 +3743,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
auto Src1 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RSI, Size);
|
||||
|
||||
OrderedNode* Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Src2, Src1);
|
||||
GenerateFlags_SUB(Op, Result, Src2, Src1);
|
||||
GenerateFlags_SUB(Op, Src2, Src1);
|
||||
|
||||
auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC);
|
||||
auto SizeConst = _Constant(Size);
|
||||
@@ -3851,8 +3799,7 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
auto Src1 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
auto Src2 = _LoadMem(GPRClass, Size, Dest_RSI, Size);
|
||||
|
||||
OrderedNode* Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Src2, Src1);
|
||||
GenerateFlags_SUB(Op, Result, Src2, Src1);
|
||||
GenerateFlags_SUB(Op, Src2, Src1);
|
||||
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
@@ -3873,9 +3820,8 @@ void OpDispatchBuilder::CMPSOp(OpcodeArgs) {
|
||||
Dest_RSI = _Add(OpSize::i64Bit, Dest_RSI, PtrDir);
|
||||
StoreGPRRegister(X86State::REG_RSI, Dest_RSI);
|
||||
|
||||
OrderedNode *ZF = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC);
|
||||
CalculateDeferredFlags();
|
||||
InternalCondJump = CondJump(ZF, {REPE ? COND_NEQ : COND_EQ});
|
||||
InternalCondJump = CondJumpNZCV({REPE ? COND_EQ : COND_NEQ});
|
||||
|
||||
// Jump back to the start if we have more work to do
|
||||
SetTrueJumpTarget(InternalCondJump, LoopStart);
|
||||
@@ -4002,11 +3948,10 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
OrderedNode *Dest_RDI = LoadGPRRegister(X86State::REG_RDI);
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true});
|
||||
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
|
||||
OrderedNode* Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Src1, Src2);
|
||||
GenerateFlags_SUB(Op, Result, Src1, Src2);
|
||||
GenerateFlags_SUB(Op, Src1, Src2);
|
||||
|
||||
auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC);
|
||||
auto SizeConst = _Constant(Size);
|
||||
@@ -4054,11 +3999,10 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
|
||||
Dest_RDI = AppendSegmentOffset(Dest_RDI, 0, FEXCore::X86Tables::DecodeFlags::FLAG_ES_PREFIX, true);
|
||||
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
|
||||
auto Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true});
|
||||
auto Src2 = _LoadMemAutoTSO(GPRClass, Size, Dest_RDI, Size);
|
||||
|
||||
OrderedNode* Result = _Sub(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Src1, Src2);
|
||||
GenerateFlags_SUB(Op, Result, Src1, Src2);
|
||||
GenerateFlags_SUB(Op, Src1, Src2);
|
||||
|
||||
// Calculate flags early.
|
||||
CalculateDeferredFlags();
|
||||
@@ -4076,9 +4020,8 @@ void OpDispatchBuilder::SCASOp(OpcodeArgs) {
|
||||
TailDest_RDI = _Add(OpSize::i64Bit, TailDest_RDI, PtrDir);
|
||||
StoreGPRRegister(X86State::REG_RDI, TailDest_RDI);
|
||||
|
||||
OrderedNode *ZF = GetRFLAG(FEXCore::X86State::RFLAG_ZF_RAW_LOC);
|
||||
CalculateDeferredFlags();
|
||||
InternalCondJump = CondJump(ZF, {REPE ? COND_NEQ : COND_EQ});
|
||||
InternalCondJump = CondJumpNZCV({REPE ? COND_EQ : COND_NEQ});
|
||||
|
||||
// Jump back to the start if we have more work to do
|
||||
SetTrueJumpTarget(InternalCondJump, LoopStart);
|
||||
@@ -4151,24 +4094,19 @@ void OpDispatchBuilder::NEGOp(OpcodeArgs) {
|
||||
auto Size = GetSrcSize(Op);
|
||||
auto ZeroConst = _Constant(0);
|
||||
|
||||
OrderedNode *Dest{};
|
||||
OrderedNode *Result{};
|
||||
|
||||
if (DestIsLockedMem(Op)) {
|
||||
OrderedNode *DestMem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.LoadData = false});
|
||||
DestMem = AppendSegmentOffset(DestMem, Op->Flags);
|
||||
|
||||
Dest = _AtomicFetchNeg(IR::SizeToOpSize(Size), DestMem);
|
||||
Result = _Neg(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Dest);
|
||||
OrderedNode *Dest = _AtomicFetchNeg(IR::SizeToOpSize(Size), DestMem);
|
||||
CalculateFlags_SUB(Size, ZeroConst, Dest);
|
||||
}
|
||||
else {
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags);
|
||||
Result = _Neg(Size == 8 ? OpSize::i64Bit : OpSize::i32Bit, Dest);
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
OrderedNode *Result = CalculateFlags_SUB(Size, ZeroConst, Dest);
|
||||
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
GenerateFlags_SUB(Op, Result, ZeroConst, Dest);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::DIVOp(OpcodeArgs) {
|
||||
@@ -4378,8 +4316,7 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
// Compare RAX with the destination, setting flags accordingly.
|
||||
OrderedNode *Result = _Sub(IR::SizeToOpSize(GPRSize), Src3Lower, Src1Lower);
|
||||
GenerateFlags_SUB(Op, Result, Src3Lower, Src1Lower);
|
||||
GenerateFlags_SUB(Op, Src3Lower, Src1Lower);
|
||||
CalculateDeferredFlags();
|
||||
|
||||
if (!Trivial) {
|
||||
@@ -4445,11 +4382,7 @@ void OpDispatchBuilder::CMPXCHGOp(OpcodeArgs) {
|
||||
// RAX gets the result of the CAS op
|
||||
StoreGPRRegister(X86State::REG_RAX, RAXResult, Size);
|
||||
|
||||
|
||||
const auto Size = GetDstBitSize(Op);
|
||||
|
||||
OrderedNode *Result = _Sub(Size == 64 ? OpSize::i64Bit : OpSize::i32Bit, Src3Lower, CASResult);
|
||||
GenerateFlags_SUB(Op, Result, Src3Lower, CASResult);
|
||||
GenerateFlags_SUB(Op, Src3Lower, CASResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4853,7 +4786,12 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(RegisterClassType Class, X
|
||||
if (!IsVSIB && Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
if (Operand.Data.SIB.Scale == 1) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index);
|
||||
}
|
||||
else {
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// NOTE: VSIB cannot have the index * scale portion calculated ahead of time,
|
||||
@@ -5107,7 +5045,12 @@ void OpDispatchBuilder::StoreResult_WithOpSize(FEXCore::IR::RegisterClassType Cl
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID && Operand.Data.SIB.Base != FEXCore::X86State::REG_INVALID) {
|
||||
auto Base = LoadGPRRegister(Operand.Data.SIB.Base, GPRSize);
|
||||
auto Index = LoadGPRRegister(Operand.Data.SIB.Index, GPRSize);
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
if (Operand.Data.SIB.Scale == 1) {
|
||||
Tmp = _Add(IR::SizeToOpSize(GPRSize), Base, Index);
|
||||
}
|
||||
else {
|
||||
Tmp = _AddShift(IR::SizeToOpSize(GPRSize), Base, Index, ShiftType::LSL, FEXCore::ilog2(Operand.Data.SIB.Scale));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Operand.Data.SIB.Index != FEXCore::X86State::REG_INVALID) {
|
||||
@@ -5220,7 +5163,24 @@ void OpDispatchBuilder::MOVGPRNTOp(OpcodeArgs) {
|
||||
StoreResult(GPRClass, Op, Src, 1, MemoryAccessType::STREAM);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp) {
|
||||
void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx) {
|
||||
/* On x86, the canonical way to zero a register is XOR with itself... because
|
||||
* modern x86 detects this pattern in hardware. arm64 does not detect this
|
||||
* pattern, we should do it like the x86 hardware would. On arm64, "mov x0,
|
||||
* #0" is faster than "eor x0, x0, x0". Additionally this lets more constant
|
||||
* folding kick in for flags.
|
||||
*/
|
||||
if (!DestIsLockedMem(Op) &&
|
||||
ALUIROp == FEXCore::IR::IROps::OP_XOR &&
|
||||
Op->Dest.IsGPR() && Op->Src[SrcIdx].IsGPR() &&
|
||||
Op->Dest.Data.GPR == Op->Src[SrcIdx].Data.GPR) {
|
||||
|
||||
auto Result = _Constant(0);
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
GenerateFlags_Logical(Op, Result, Result, Result);
|
||||
return;
|
||||
}
|
||||
|
||||
auto Size = GetDstSize(Op);
|
||||
|
||||
auto RoundedSize = Size;
|
||||
@@ -5229,14 +5189,8 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor
|
||||
|
||||
const auto OpSize = IR::SizeToOpSize(RoundedSize);
|
||||
|
||||
// Logical ops can tolerate garbage in the upper bits, so don't mask.
|
||||
bool AllowUpperGarbage = ALUIROp == FEXCore::IR::IROps::OP_ANDWITHFLAGS ||
|
||||
ALUIROp == FEXCore::IR::IROps::OP_XOR ||
|
||||
ALUIROp == FEXCore::IR::IROps::OP_OR;
|
||||
|
||||
// X86 basic ALU ops just do the operation between the destination and a single source
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags,
|
||||
{.AllowUpperGarbage = AllowUpperGarbage || Size >= 4});
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[SrcIdx], Op->Flags, {.AllowUpperGarbage = true});
|
||||
|
||||
OrderedNode *Result{};
|
||||
OrderedNode *Dest{};
|
||||
@@ -5248,68 +5202,43 @@ void OpDispatchBuilder::ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCor
|
||||
|
||||
DeriveOp(FetchOp, AtomicFetchOp, _AtomicFetchAdd(IR::SizeToOpSize(Size), Src, DestMem));
|
||||
Dest = FetchOp;
|
||||
|
||||
DeriveOp(ALUOp, ALUIROp, _AndWithFlags(OpSize, Dest, Src));
|
||||
Result = ALUOp;
|
||||
}
|
||||
else {
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags,
|
||||
{.AllowUpperGarbage = AllowUpperGarbage || Size >= 4});
|
||||
|
||||
/* On x86, the canonical way to zero a register is XOR with itself...
|
||||
* because modern x86 detects this pattern in hardware. arm64 does not
|
||||
* detect this pattern, we should do it like the x86 hardware would. On
|
||||
* arm64, "mov x0, #0" is faster than "eor x0, x0, x0". Additionally this
|
||||
* lets more constant folding kick in for flags.
|
||||
*/
|
||||
if (ALUIROp == FEXCore::IR::IROps::OP_XOR &&
|
||||
Op->Dest.IsGPR() && Op->Src[0].IsGPR() &&
|
||||
Op->Dest.Data.GPR == Op->Src[0].Data.GPR) {
|
||||
|
||||
Result = _Constant(0);
|
||||
} else {
|
||||
DeriveOp(ALUOp, ALUIROp, _AndWithFlags(OpSize, Dest, Src));
|
||||
Result = ALUOp;
|
||||
}
|
||||
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true});
|
||||
}
|
||||
|
||||
DeriveOp(ALUOp, ALUIROp, _AndWithFlags(OpSize, Dest, Src));
|
||||
Result = ALUOp;
|
||||
|
||||
// Flags set
|
||||
{
|
||||
switch (ALUIROp) {
|
||||
case FEXCore::IR::IROps::OP_ADD:
|
||||
GenerateFlags_ADD(Op, Result, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_SUB:
|
||||
GenerateFlags_SUB(Op, Result, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_XOR:
|
||||
case FEXCore::IR::IROps::OP_OR: {
|
||||
GenerateFlags_Logical(Op, Result, Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_ANDWITHFLAGS: {
|
||||
InvalidateDeferredFlags();
|
||||
|
||||
// SF/ZF/CF/OF
|
||||
CachedNZCV = nullptr;
|
||||
PossiblySetNZCVBits = (1u << 31) | (1u << 30);
|
||||
NZCVDirty = false;
|
||||
|
||||
// PF/AF
|
||||
CalculatePF(Result);
|
||||
_InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
switch (ALUIROp) {
|
||||
case FEXCore::IR::IROps::OP_ADD:
|
||||
Result = CalculateFlags_ADD(Size, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_SUB:
|
||||
Result = CalculateFlags_SUB(Size, Dest, Src);
|
||||
break;
|
||||
case FEXCore::IR::IROps::OP_XOR:
|
||||
case FEXCore::IR::IROps::OP_OR: {
|
||||
GenerateFlags_Logical(Op, Result, Dest, Src);
|
||||
break;
|
||||
}
|
||||
case FEXCore::IR::IROps::OP_ANDWITHFLAGS: {
|
||||
HandleNZ00Write();
|
||||
CalculatePF(Result);
|
||||
_InvalidateFlags(1 << X86State::RFLAG_AF_RAW_LOC);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!DestIsLockedMem(Op))
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
}
|
||||
|
||||
template<FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp>
|
||||
void OpDispatchBuilder::ALUOp(OpcodeArgs) {
|
||||
ALUOpImpl(Op, ALUIROp, AtomicFetchOp);
|
||||
ALUOpImpl(Op, ALUIROp, AtomicFetchOp, 0);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::INTOp(OpcodeArgs) {
|
||||
@@ -5326,6 +5255,9 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) {
|
||||
constexpr uint8_t SYSCALL_LITERAL = 0x2E;
|
||||
#endif
|
||||
if (Literal == SYSCALL_LITERAL) {
|
||||
if (CTX->Config.Is64BitMode()) [[unlikely]] {
|
||||
ERROR_AND_DIE_FMT("[Unsupported] Trying to execute 32-bit syscall from a 64-bit process.");
|
||||
}
|
||||
// Syscall on linux
|
||||
SyscallOp<false>(Op);
|
||||
return;
|
||||
@@ -5391,11 +5323,11 @@ void OpDispatchBuilder::INTOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
if (Op->OP == 0xCE) { // Conditional to only break if Overflow == 1
|
||||
auto Flag = GetRFLAG(FEXCore::X86State::RFLAG_OF_RAW_LOC);
|
||||
CalculateDeferredFlags();
|
||||
|
||||
// If condition doesn't hold then keep going
|
||||
auto CondJump_ = CondJump(Flag, {COND_EQ});
|
||||
// COND_FNU means OF == 0
|
||||
auto CondJump_ = CondJumpNZCV({COND_FNU});
|
||||
auto FalseBlock = CreateNewCodeBlockAfter(GetCurrentBlock());
|
||||
SetFalseJumpTarget(CondJump_, FalseBlock);
|
||||
SetCurrentCodeBlock(FalseBlock);
|
||||
@@ -5517,13 +5449,12 @@ void OpDispatchBuilder::RDTSCPOp(OpcodeArgs) {
|
||||
// - Explicitly use an LFENCE after RDTSCP if you want to block this behaviour
|
||||
|
||||
_Fence({FEXCore::IR::Fence_Load});
|
||||
auto Counter = _CycleCounter();
|
||||
auto CounterLow = _Bfe(OpSize::i64Bit, 32, 0, Counter);
|
||||
auto CounterHigh = _Bfe(OpSize::i64Bit, 32, 32, Counter);
|
||||
auto Counter = CycleCounter();
|
||||
|
||||
auto ID = _ProcessorID();
|
||||
StoreGPRRegister(X86State::REG_RAX, CounterLow);
|
||||
StoreGPRRegister(X86State::REG_RAX, Counter.CounterLow);
|
||||
StoreGPRRegister(X86State::REG_RCX, ID);
|
||||
StoreGPRRegister(X86State::REG_RDX, CounterHigh);
|
||||
StoreGPRRegister(X86State::REG_RDX, Counter.CounterHigh);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CRC32(OpcodeArgs) {
|
||||
@@ -6106,7 +6037,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{0x10, 6, &OpDispatchBuilder::ADCOp<0>},
|
||||
|
||||
{0x18, 6, &OpDispatchBuilder::SBBOp<0, true>},
|
||||
{0x18, 6, &OpDispatchBuilder::SBBOp<0>},
|
||||
|
||||
{0x20, 6, &OpDispatchBuilder::ALUOp<FEXCore::IR::IROps::OP_ANDWITHFLAGS, FEXCore::IR::IROps::OP_ATOMICFETCHAND>},
|
||||
|
||||
@@ -6188,7 +6119,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{0xCE, 1, &OpDispatchBuilder::INTOp},
|
||||
{0xD4, 1, &OpDispatchBuilder::AAMOp},
|
||||
{0xD5, 1, &OpDispatchBuilder::AADOp},
|
||||
{0xD6, 1, &OpDispatchBuilder::SBBOp<0, false>},
|
||||
{0xD6, 1, &OpDispatchBuilder::SALCOp},
|
||||
};
|
||||
|
||||
constexpr std::tuple<uint8_t, uint8_t, X86Tables::OpDispatchPtr> BaseOpTable_64[] = {
|
||||
@@ -6350,7 +6281,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 0), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 1), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 2), 1, &OpDispatchBuilder::ADCOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 3), 1, &OpDispatchBuilder::SBBOp<1, true>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 3), 1, &OpDispatchBuilder::SBBOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 4), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 5), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x80), 6), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
@@ -6359,7 +6290,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 0), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 1), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 2), 1, &OpDispatchBuilder::ADCOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 3), 1, &OpDispatchBuilder::SBBOp<1, true>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 3), 1, &OpDispatchBuilder::SBBOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 4), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 5), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x81), 6), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
@@ -6368,7 +6299,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 0), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 1), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 2), 1, &OpDispatchBuilder::ADCOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 3), 1, &OpDispatchBuilder::SBBOp<1, true>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 3), 1, &OpDispatchBuilder::SBBOp<1>},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 4), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 5), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
{OPD(FEXCore::X86Tables::TYPE_GROUP_1, OpToIndex(0x83), 6), 1, &OpDispatchBuilder::SecondaryALUOp},
|
||||
|
||||
@@ -78,10 +78,7 @@ friend class FEXCore::IR::PassManager;
|
||||
public:
|
||||
enum class FlagsGenerationType : uint8_t {
|
||||
TYPE_NONE,
|
||||
TYPE_ADC,
|
||||
TYPE_SBB,
|
||||
TYPE_SUB,
|
||||
TYPE_ADD,
|
||||
TYPE_MUL,
|
||||
TYPE_UMUL,
|
||||
TYPE_LOGICAL,
|
||||
@@ -271,8 +268,9 @@ public:
|
||||
void SecondaryALUOp(OpcodeArgs);
|
||||
template<uint32_t SrcIndex>
|
||||
void ADCOp(OpcodeArgs);
|
||||
template<uint32_t SrcIndex, bool SetFlags>
|
||||
template<uint32_t SrcIndex>
|
||||
void SBBOp(OpcodeArgs);
|
||||
void SALCOp(OpcodeArgs);
|
||||
void PUSHOp(OpcodeArgs);
|
||||
void PUSHREGOp(OpcodeArgs);
|
||||
void PUSHAOp(OpcodeArgs);
|
||||
@@ -352,6 +350,11 @@ public:
|
||||
void PUSHFOp(OpcodeArgs);
|
||||
void POPFOp(OpcodeArgs);
|
||||
|
||||
struct CycleCounterPair {
|
||||
OrderedNode *CounterLow;
|
||||
OrderedNode *CounterHigh;
|
||||
};
|
||||
CycleCounterPair CycleCounter();
|
||||
void RDTSCOp(OpcodeArgs);
|
||||
void INCOp(OpcodeArgs);
|
||||
void DECOp(OpcodeArgs);
|
||||
@@ -997,7 +1000,7 @@ private:
|
||||
// Used during new op bringup
|
||||
bool ShouldDump{false};
|
||||
|
||||
void ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp);
|
||||
void ALUOpImpl(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx);
|
||||
|
||||
// Opcode helpers for generalizing behavior across VEX and non-VEX variants.
|
||||
|
||||
@@ -1263,6 +1266,30 @@ private:
|
||||
return NZCVMask;
|
||||
}
|
||||
|
||||
// Set flag tracking to prepare for an operation that directly writes NZCV. If
|
||||
// some bits are known to be zeroed, the PossiblySetNZCVBits mask can be
|
||||
// passed. Otherwise, it defaults to assuming all bits may be set after
|
||||
// (this is conservative).
|
||||
void HandleNZCVWrite(uint32_t _PossiblySetNZCVBits = ~0) {
|
||||
InvalidateDeferredFlags();
|
||||
CachedNZCV = nullptr;
|
||||
PossiblySetNZCVBits = _PossiblySetNZCVBits;
|
||||
NZCVDirty = false;
|
||||
}
|
||||
|
||||
// Set flag tracking to prepare for a read-modify-write operation on NZCV.
|
||||
void HandleNZCV_RMW(uint32_t _PossiblySetNZCVBits = ~0) {
|
||||
if (NZCVDirty && CachedNZCV)
|
||||
_StoreNZCV(CachedNZCV);
|
||||
|
||||
HandleNZCVWrite(_PossiblySetNZCVBits);
|
||||
}
|
||||
|
||||
// Special case of the above where we are known to zero C/V
|
||||
void HandleNZ00Write() {
|
||||
HandleNZCVWrite((1u << 31) | (1u << 30));
|
||||
}
|
||||
|
||||
OrderedNode *GetNZCV() {
|
||||
if (!CachedNZCV) {
|
||||
CachedNZCV = _LoadNZCV();
|
||||
@@ -1618,13 +1645,6 @@ private:
|
||||
OrderedNode *Src2;
|
||||
} TwoSource;
|
||||
|
||||
// ADC, SBB
|
||||
struct {
|
||||
OrderedNode *Src1;
|
||||
OrderedNode *Src2;
|
||||
OrderedNode *Src3;
|
||||
} ThreeSource;
|
||||
|
||||
// LSHLI, LSHRI, ASHRI, RORI, ROLI
|
||||
struct {
|
||||
OrderedNode *Src1;
|
||||
@@ -1715,13 +1735,13 @@ private:
|
||||
OrderedNode *LoadAF();
|
||||
void FixupAF();
|
||||
void CalculatePF(OrderedNode *Res);
|
||||
void CalculateAF(OpSize OpSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2);
|
||||
void CalculateAF(OrderedNode *Src1, OrderedNode *Src2);
|
||||
|
||||
void CalculateOF(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool Sub);
|
||||
void CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF);
|
||||
void CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF);
|
||||
void CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true);
|
||||
void CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true);
|
||||
OrderedNode *CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2);
|
||||
OrderedNode *CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2);
|
||||
OrderedNode *CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true);
|
||||
OrderedNode *CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true);
|
||||
void CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, OrderedNode *High);
|
||||
void CalculateFlags_UMUL(OrderedNode *High);
|
||||
void CalculateFlags_Logical(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2);
|
||||
@@ -1752,37 +1772,7 @@ private:
|
||||
*
|
||||
* Depending on the operation it may force a RFLAGs calculation before storing the new deferred state.
|
||||
* @{ */
|
||||
void GenerateFlags_ADC(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF) {
|
||||
CurrentDeferredFlags = DeferredFlagData {
|
||||
.Type = FlagsGenerationType::TYPE_ADC,
|
||||
.SrcSize = GetSrcSize(Op),
|
||||
.Res = Res,
|
||||
.Sources = {
|
||||
.ThreeSource = {
|
||||
.Src1 = Src1,
|
||||
.Src2 = Src2,
|
||||
.Src3 = CF,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void GenerateFlags_SBB(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF) {
|
||||
CurrentDeferredFlags = DeferredFlagData {
|
||||
.Type = FlagsGenerationType::TYPE_SBB,
|
||||
.SrcSize = GetSrcSize(Op),
|
||||
.Res = Res,
|
||||
.Sources = {
|
||||
.ThreeSource = {
|
||||
.Src1 = Src1,
|
||||
.Src2 = Src2,
|
||||
.Src3 = CF,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void GenerateFlags_SUB(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true) {
|
||||
void GenerateFlags_SUB(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true) {
|
||||
if (!UpdateCF) {
|
||||
// If we aren't updating CF then we need to calculate flags. Invalidation mask would make this not required.
|
||||
CalculateDeferredFlags();
|
||||
@@ -1790,26 +1780,6 @@ private:
|
||||
CurrentDeferredFlags = DeferredFlagData {
|
||||
.Type = FlagsGenerationType::TYPE_SUB,
|
||||
.SrcSize = GetSrcSize(Op),
|
||||
.Res = Res,
|
||||
.Sources = {
|
||||
.TwoSrcImmediate = {
|
||||
.Src1 = Src1,
|
||||
.Src2 = Src2,
|
||||
.UpdateCF = UpdateCF,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void GenerateFlags_ADD(FEXCore::X86Tables::DecodedOp Op, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF = true) {
|
||||
if (!UpdateCF) {
|
||||
// If we aren't updating CF then we need to calculate flags. Invalidation mask would make this not required.
|
||||
CalculateDeferredFlags();
|
||||
}
|
||||
CurrentDeferredFlags = DeferredFlagData {
|
||||
.Type = FlagsGenerationType::TYPE_ADD,
|
||||
.SrcSize = GetSrcSize(Op),
|
||||
.Res = Res,
|
||||
.Sources = {
|
||||
.TwoSrcImmediate = {
|
||||
.Src1 = Src1,
|
||||
|
||||
@@ -282,19 +282,25 @@ void OpDispatchBuilder::CalculatePF(OrderedNode *Res) {
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_PF_RAW_LOC>(Res);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateAF(OpSize OpSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2) {
|
||||
void OpDispatchBuilder::CalculateAF(OrderedNode *Src1, OrderedNode *Src2) {
|
||||
// We only care about bit 4 in the subsequent XOR. If we'll XOR with 0,
|
||||
// there's no sense XOR'ing at all. This affects INC.
|
||||
// there's no sense XOR'ing at all. If we'll XOR with 1, that's just
|
||||
// inverting.
|
||||
uint64_t Const;
|
||||
if (IsValueConstant(WrapNode(Src2), &Const) && (Const & (1u << 4)) == 0) {
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_AF_RAW_LOC>(Src1);
|
||||
if (IsValueConstant(WrapNode(Src2), &Const)) {
|
||||
if (Const & (1u << 4)) {
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_AF_RAW_LOC>(_Not(OpSize::i32Bit, Src1));
|
||||
} else {
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_AF_RAW_LOC>(Src1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We store the XOR of the arguments. At read time, we XOR with the
|
||||
// appropriate bit of the result (available as the PF flag) and extract the
|
||||
// appropriate bit.
|
||||
OrderedNode *XorRes = _Xor(OpSize, Src1, Src2);
|
||||
OrderedNode *XorRes = _Xor(OpSize::i32Bit, Src1, Src2);
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_AF_RAW_LOC>(XorRes);
|
||||
}
|
||||
|
||||
@@ -310,34 +316,9 @@ void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) {
|
||||
}
|
||||
|
||||
switch (CurrentDeferredFlags.Type) {
|
||||
case FlagsGenerationType::TYPE_ADC:
|
||||
CalculateFlags_ADC(
|
||||
CurrentDeferredFlags.SrcSize,
|
||||
CurrentDeferredFlags.Res,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src1,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src2,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src3);
|
||||
break;
|
||||
case FlagsGenerationType::TYPE_SBB:
|
||||
CalculateFlags_SBB(
|
||||
CurrentDeferredFlags.SrcSize,
|
||||
CurrentDeferredFlags.Res,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src1,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src2,
|
||||
CurrentDeferredFlags.Sources.ThreeSource.Src3);
|
||||
break;
|
||||
case FlagsGenerationType::TYPE_SUB:
|
||||
CalculateFlags_SUB(
|
||||
CurrentDeferredFlags.SrcSize,
|
||||
CurrentDeferredFlags.Res,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.Src1,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.Src2,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.UpdateCF);
|
||||
break;
|
||||
case FlagsGenerationType::TYPE_ADD:
|
||||
CalculateFlags_ADD(
|
||||
CurrentDeferredFlags.SrcSize,
|
||||
CurrentDeferredFlags.Res,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.Src1,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.Src2,
|
||||
CurrentDeferredFlags.Sources.TwoSrcImmediate.UpdateCF);
|
||||
@@ -486,150 +467,126 @@ void OpDispatchBuilder::CalculateDeferredFlags(uint32_t FlagsToCalculateMask) {
|
||||
NZCVDirty = false;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF) {
|
||||
OrderedNode *OpDispatchBuilder::CalculateFlags_ADC(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2) {
|
||||
auto Zero = _Constant(0);
|
||||
auto One = _Constant(1);
|
||||
auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
OrderedNode *Res;
|
||||
|
||||
CalculateAF(OpSize, Res, Src1, Src2);
|
||||
CalculatePF(Res);
|
||||
CalculateAF(Src1, Src2);
|
||||
|
||||
if (SrcSize >= 4) {
|
||||
if (NZCVDirty && CachedNZCV)
|
||||
_StoreNZCV(CachedNZCV);
|
||||
CachedNZCV = nullptr;
|
||||
|
||||
_AdcNZCV(OpSize, Src1, Src2);
|
||||
PossiblySetNZCVBits = ~0;
|
||||
HandleNZCV_RMW();
|
||||
Res = _AdcWithFlags(OpSize, Src1, Src2);
|
||||
} else {
|
||||
// SF/ZF
|
||||
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
Res = _Adc(OpSize, Src1, Src2);
|
||||
Res = _Bfe(OpSize, SrcSize * 8, 0, Res);
|
||||
|
||||
auto SelectOpLT = _Select(FEXCore::IR::COND_ULT, Res, Src2, One, Zero);
|
||||
auto SelectOpLE = _Select(FEXCore::IR::COND_ULE, Res, Src2, One, Zero);
|
||||
auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT);
|
||||
|
||||
SetNZ_ZeroCV(SrcSize, Res);
|
||||
|
||||
// CF
|
||||
// Unsigned
|
||||
{
|
||||
auto SelectOpLT = _Select(FEXCore::IR::COND_ULT, Res, Src2, One, Zero);
|
||||
auto SelectOpLE = _Select(FEXCore::IR::COND_ULE, Res, Src2, One, Zero);
|
||||
auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT);
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(SelectCF);
|
||||
}
|
||||
|
||||
// Signed
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(SelectCF);
|
||||
CalculateOF(SrcSize, Res, Src1, Src2, false);
|
||||
}
|
||||
|
||||
CalculatePF(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, OrderedNode *CF) {
|
||||
OrderedNode *OpDispatchBuilder::CalculateFlags_SBB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2) {
|
||||
auto Zero = _Constant(0);
|
||||
auto One = _Constant(1);
|
||||
auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
|
||||
CalculateAF(OpSize, Res, Src1, Src2);
|
||||
CalculatePF(Res);
|
||||
CalculateAF(Src1, Src2);
|
||||
|
||||
OrderedNode *Res;
|
||||
if (SrcSize >= 4) {
|
||||
// Rectify input carry
|
||||
CarryInvert();
|
||||
|
||||
if (NZCVDirty && CachedNZCV)
|
||||
_StoreNZCV(CachedNZCV);
|
||||
CachedNZCV = nullptr;
|
||||
NZCVDirty = false;
|
||||
|
||||
_SbbNZCV(OpSize, Src1, Src2);
|
||||
PossiblySetNZCVBits = ~0;
|
||||
HandleNZCV_RMW();
|
||||
Res = _SbbWithFlags(OpSize, Src1, Src2);
|
||||
|
||||
// Rectify output carry
|
||||
CarryInvert();
|
||||
} else {
|
||||
// SF/ZF
|
||||
auto CF = GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
Res = _Sub(OpSize, Src1, _Add(OpSize, Src2, CF));
|
||||
Res = _Bfe(OpSize, SrcSize * 8, 0, Res);
|
||||
|
||||
auto SelectOpLT = _Select(FEXCore::IR::COND_UGT, Res, Src1, One, Zero);
|
||||
auto SelectOpLE = _Select(FEXCore::IR::COND_UGE, Res, Src1, One, Zero);
|
||||
auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT);
|
||||
|
||||
SetNZ_ZeroCV(SrcSize, Res);
|
||||
|
||||
// CF
|
||||
// Unsigned
|
||||
{
|
||||
auto SelectOpLT = _Select(FEXCore::IR::COND_UGT, Res, Src1, One, Zero);
|
||||
auto SelectOpLE = _Select(FEXCore::IR::COND_UGE, Res, Src1, One, Zero);
|
||||
auto SelectCF = _Select(FEXCore::IR::COND_EQ, CF, One, SelectOpLE, SelectOpLT);
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(SelectCF);
|
||||
}
|
||||
|
||||
// Signed
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(SelectCF);
|
||||
CalculateOF(SrcSize, Res, Src1, Src2, true);
|
||||
}
|
||||
|
||||
CalculatePF(Res);
|
||||
return Res;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) {
|
||||
auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
|
||||
CalculateAF(OpSize, Res, Src1, Src2);
|
||||
CalculatePF(Res);
|
||||
|
||||
OrderedNode *OpDispatchBuilder::CalculateFlags_SUB(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) {
|
||||
// Stash CF before stomping over it
|
||||
auto OldCF = UpdateCF ? nullptr : GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
|
||||
// TODO: Could do this path for small sources if we have FEAT_FlagM
|
||||
HandleNZCVWrite();
|
||||
|
||||
CalculateAF(Src1, Src2);
|
||||
|
||||
OrderedNode *Res;
|
||||
if (SrcSize >= 4) {
|
||||
_SubNZCV(OpSize, Src1, Src2);
|
||||
CachedNZCV = nullptr;
|
||||
NZCVDirty = false;
|
||||
PossiblySetNZCVBits = ~0;
|
||||
|
||||
// We only bother inverting CF if we're actually going to update CF.
|
||||
if (UpdateCF)
|
||||
CarryInvert();
|
||||
Res = _SubWithFlags(IR::SizeToOpSize(SrcSize), Src1, Src2);
|
||||
} else {
|
||||
// SF/ZF
|
||||
SetNZ_ZeroCV(SrcSize, Res);
|
||||
|
||||
// CF
|
||||
if (UpdateCF) {
|
||||
// Grab carry bit from unmasked output.
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(Res, SrcSize * 8, true);
|
||||
}
|
||||
|
||||
CalculateOF(SrcSize, Res, Src1, Src2, true);
|
||||
_SubNZCV(IR::SizeToOpSize(SrcSize), Src1, Src2);
|
||||
Res = _Sub(OpSize::i32Bit, Src1, Src2);
|
||||
}
|
||||
|
||||
CalculatePF(Res);
|
||||
|
||||
// If we're updating CF, we need to invert it for correctness. If we're not
|
||||
// updating CF, we need to restore the CF since we stomped over it.
|
||||
if (UpdateCF)
|
||||
CarryInvert();
|
||||
else
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(OldCF);
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
OrderedNode *OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) {
|
||||
// Stash CF before stomping over it
|
||||
auto OldCF = UpdateCF ? nullptr : GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
|
||||
HandleNZCVWrite();
|
||||
|
||||
CalculateAF(Src1, Src2);
|
||||
|
||||
OrderedNode *Res;
|
||||
if (SrcSize >= 4) {
|
||||
Res = _AddWithFlags(IR::SizeToOpSize(SrcSize), Src1, Src2);
|
||||
} else {
|
||||
_AddNZCV(IR::SizeToOpSize(SrcSize), Src1, Src2);
|
||||
Res = _Add(OpSize::i32Bit, Src1, Src2);
|
||||
}
|
||||
|
||||
CalculatePF(Res);
|
||||
|
||||
// We stomped over CF while calculation flags, restore it.
|
||||
if (!UpdateCF)
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(OldCF);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_ADD(uint8_t SrcSize, OrderedNode *Res, OrderedNode *Src1, OrderedNode *Src2, bool UpdateCF) {
|
||||
auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;
|
||||
|
||||
CalculateAF(OpSize, Res, Src1, Src2);
|
||||
CalculatePF(Res);
|
||||
|
||||
// Stash CF before stomping over it
|
||||
auto OldCF = UpdateCF ? nullptr : GetRFLAG(FEXCore::X86State::RFLAG_CF_RAW_LOC);
|
||||
|
||||
// TODO: Could do this path for small sources if we have FEAT_FlagM
|
||||
if (SrcSize >= 4) {
|
||||
_AddNZCV(OpSize, Src1, Src2);
|
||||
CachedNZCV = nullptr;
|
||||
NZCVDirty = false;
|
||||
PossiblySetNZCVBits = ~0;
|
||||
} else {
|
||||
// SF/ZF
|
||||
SetNZ_ZeroCV(SrcSize, Res);
|
||||
|
||||
// CF
|
||||
if (UpdateCF) {
|
||||
// Grab carry bit from unmasked output
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(Res, SrcSize * 8, true);
|
||||
}
|
||||
|
||||
CalculateOF(SrcSize, Res, Src1, Src2, false);
|
||||
}
|
||||
|
||||
// We stomped over CF while calculation flags, restore it.
|
||||
if (!UpdateCF)
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_CF_RAW_LOC>(OldCF);
|
||||
return Res;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, OrderedNode *High) {
|
||||
HandleNZCVWrite();
|
||||
|
||||
// PF/AF/ZF/SF
|
||||
// Undefined
|
||||
{
|
||||
@@ -648,13 +605,12 @@ void OpDispatchBuilder::CalculateFlags_MUL(uint8_t SrcSize, OrderedNode *Res, Or
|
||||
// undefined, this does what we need.
|
||||
auto Zero = _Constant(0);
|
||||
_CondAddNZCV(OpSize::i64Bit, Zero, Zero, CondClassType{COND_EQ}, 0x3 /* nzCV */);
|
||||
CachedNZCV = nullptr;
|
||||
NZCVDirty = false;
|
||||
PossiblySetNZCVBits = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::CalculateFlags_UMUL(OrderedNode *High) {
|
||||
HandleNZCVWrite();
|
||||
|
||||
auto Zero = _Constant(0);
|
||||
OpSize Size = IR::SizeToOpSize(GetOpSize(High));
|
||||
|
||||
@@ -674,9 +630,6 @@ void OpDispatchBuilder::CalculateFlags_UMUL(OrderedNode *High) {
|
||||
// If High = 0, then sets to nZcv. Else sets to nzCV. Since SF/ZF undefined,
|
||||
// this does what we need.
|
||||
_CondAddNZCV(Size, Zero, Zero, CondClassType{COND_EQ}, 0x3 /* nzCV */);
|
||||
CachedNZCV = nullptr;
|
||||
NZCVDirty = false;
|
||||
PossiblySetNZCVBits = ~0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3422,15 +3422,12 @@ void OpDispatchBuilder::VPALIGNROp(OpcodeArgs) {
|
||||
|
||||
template<size_t ElementSize>
|
||||
void OpDispatchBuilder::UCOMISxOp(OpcodeArgs) {
|
||||
InvalidateDeferredFlags();
|
||||
|
||||
const auto SrcSize = Op->Src[0].IsGPR() ? GetGuestVectorLength() : GetSrcSize(Op);
|
||||
OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetGuestVectorLength(), Op->Flags);
|
||||
OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags);
|
||||
|
||||
CachedNZCV = nullptr;
|
||||
HandleNZCVWrite();
|
||||
_FCmp(ElementSize, Src1, Src2);
|
||||
PossiblySetNZCVBits = ~0;
|
||||
ConvertNZCVToSSE();
|
||||
|
||||
// Zero AF. Note that the comparison sets the raw PF to 0/1 above, so PF[4] is
|
||||
|
||||
@@ -181,23 +181,11 @@ namespace FEXCore {
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDI] = (uintptr_t)arg0;
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSI] = (uintptr_t)arg1;
|
||||
} else {
|
||||
// The argument pointer comes from the host stack, so it's not
|
||||
// accessible by the guest. Allocate a thread-local chunk of memory
|
||||
// to relocate the argument data.
|
||||
// TODO: Directly store the arguments in a guest-accessible location instead
|
||||
// TODO: FEXCore::Allocator::malloc() still returns pointers inaccessible from 32-bit guests here
|
||||
thread_local void* local_args =
|
||||
mmap( 0, 128, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
// We don't know how much argument data is on the stack, so we
|
||||
// unconditionally copy a fixed amount and leave everything else
|
||||
// uninitialized.
|
||||
// TODO: This breaks functions with large argument counts.
|
||||
memcpy(local_args, arg1, 128);
|
||||
|
||||
if ((reinterpret_cast<uintptr_t>(arg1) >> 32) != 0) {
|
||||
ERROR_AND_DIE_FMT("Tried to call guest function with arguments packed to a 64-bit address");
|
||||
}
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RCX] = (uintptr_t)arg0;
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)local_args;
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)arg1;
|
||||
}
|
||||
|
||||
Thread->CTX->HandleCallback(Thread, (uintptr_t)callback);
|
||||
@@ -499,6 +487,26 @@ namespace FEXCore {
|
||||
}
|
||||
}
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void* GetGuestStack() {
|
||||
if (!Thread) {
|
||||
ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously");
|
||||
}
|
||||
|
||||
return (void*)(uintptr_t)((Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]));
|
||||
}
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void MoveGuestStack(uintptr_t NewAddress) {
|
||||
if (!Thread) {
|
||||
ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously");
|
||||
}
|
||||
|
||||
if (NewAddress >> 32) {
|
||||
ERROR_AND_DIE_FMT("Tried to set stack pointer for 32-bit guest to a 64-bit address");
|
||||
}
|
||||
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = NewAddress;
|
||||
}
|
||||
|
||||
#else
|
||||
fextl::unique_ptr<ThunkHandler> ThunkHandler::Create() {
|
||||
ERROR_AND_DIE_FMT("Unsupported");
|
||||
|
||||
@@ -951,6 +951,24 @@
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"GPR = Adc OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": [ "Integer Add with carry",
|
||||
"Will truncate to 64 or 32bits"
|
||||
],
|
||||
"DestSize": "Size",
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"GPR = Sbb OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": [ "Integer Subtract with carry/borrow",
|
||||
"Will truncate to 64 or 32bits"
|
||||
],
|
||||
"DestSize": "Size",
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"GPR = AddShift OpSize:#Size, GPR:$Src1, GPR:$Src2, ShiftType:$Shift{ShiftType::LSL}, u8:$ShiftAmount{0}": {
|
||||
"Desc": [ "Integer Add with shifted register",
|
||||
"Will truncate to 64 or 32bits"
|
||||
@@ -961,12 +979,25 @@
|
||||
"_Shift != ShiftType::ROR"
|
||||
]
|
||||
},
|
||||
"GPR = AddWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": [ "Integer add. Truncates and sets NZCV per AddNZCV"],
|
||||
"DestSize": "Size",
|
||||
"HasSideEffects": true,
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"AddNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Set NZCV for the sum of two GPRs"],
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size"
|
||||
},
|
||||
"SetSmallNZV OpSize:#Size, GPR:$Src": {
|
||||
"Desc": ["Set NZV with a SETF instruction. Preserves CF."],
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size",
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
"Size == FEXCore::IR::OpSize::i8Bit || Size == FEXCore::IR::OpSize::i16Bit"
|
||||
]
|
||||
},
|
||||
"CarryInvert": {
|
||||
@@ -989,6 +1020,22 @@
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"GPR = AdcWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Adds and set NZCV for the sum of two GPRs and carry-in given as NZCV"],
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size",
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"GPR = SbbWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Subtracts and set NZCV for the difference of two GPRs and carry-in given as NZCV"],
|
||||
"HasSideEffects": true,
|
||||
"DestSize": "Size",
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"AdcNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Set NZCV for the sum of two GPRs and carry-in given as NZCV"],
|
||||
"HasSideEffects": true,
|
||||
@@ -1024,16 +1071,21 @@
|
||||
"_Shift != ShiftType::ROR"
|
||||
]
|
||||
},
|
||||
"SubNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Set NZCV for the difference of two GPRs. ",
|
||||
"Carry flag uses arm64 definition, inverted x86.",
|
||||
""],
|
||||
"GPR = SubWithFlags OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": [ "Integer Sub. Truncates and sets NZCV per SubNZCV"],
|
||||
"DestSize": "Size",
|
||||
"HasSideEffects": true,
|
||||
"EmitValidation": [
|
||||
"Size == FEXCore::IR::OpSize::i32Bit || Size == FEXCore::IR::OpSize::i64Bit"
|
||||
]
|
||||
},
|
||||
"SubNZCV OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Set NZCV for the difference of two GPRs. ",
|
||||
"Carry flag uses arm64 definition, inverted x86.",
|
||||
""],
|
||||
"DestSize": "Size",
|
||||
"HasSideEffects": true
|
||||
},
|
||||
"GPR = Or OpSize:#Size, GPR:$Src1, GPR:$Src2": {
|
||||
"Desc": ["Integer binary or"
|
||||
],
|
||||
|
||||
@@ -965,20 +965,24 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR)
|
||||
case OP_SUB:
|
||||
case OP_ADDNZCV:
|
||||
case OP_SUBNZCV:
|
||||
case OP_ADDWITHFLAGS:
|
||||
case OP_SUBWITHFLAGS:
|
||||
{
|
||||
auto Op = IROp->C<IR::IROp_Add>();
|
||||
|
||||
uint64_t Constant2{};
|
||||
if (IREmit->IsValueConstant(Op->Header.Args[1], &Constant2)) {
|
||||
if (IsImmAddSub(Constant2)) {
|
||||
// We don't allow 8/16-bit operations to have constants, since no
|
||||
// constant would be in bounds after the JIT's 24/16 shift.
|
||||
if (IsImmAddSub(Constant2) && Op->Header.Size >= 4) {
|
||||
IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[1]));
|
||||
|
||||
IREmit->ReplaceNodeArgument(CodeNode, 1, CreateInlineConstant(IREmit, Constant2));
|
||||
|
||||
Changed = true;
|
||||
}
|
||||
} else if (IROp->Op == OP_SUBNZCV) {
|
||||
// If the first source is zero, we can use a NEGS instruction.
|
||||
} else if (IROp->Op == OP_SUBNZCV || IROp->Op == OP_SUBWITHFLAGS || IROp->Op == OP_SUB) {
|
||||
// TODO: Generalize this
|
||||
uint64_t Constant1{};
|
||||
if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) {
|
||||
if (Constant1 == 0) {
|
||||
@@ -991,6 +995,22 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR)
|
||||
|
||||
break;
|
||||
}
|
||||
case OP_ADC:
|
||||
case OP_ADCWITHFLAGS:
|
||||
{
|
||||
auto Op = IROp->C<IR::IROp_Adc>();
|
||||
|
||||
uint64_t Constant1{};
|
||||
if (IREmit->IsValueConstant(Op->Header.Args[0], &Constant1)) {
|
||||
if (Constant1 == 0) {
|
||||
IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Header.Args[0]));
|
||||
IREmit->ReplaceNodeArgument(CodeNode, 0, CreateInlineConstant(IREmit, 0));
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OP_CONDADDNZCV:
|
||||
{
|
||||
auto Op = IROp->C<IR::IROp_CondAddNZCV>();
|
||||
|
||||
@@ -128,6 +128,36 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp)
|
||||
.Replacement = OP_AND,
|
||||
};
|
||||
|
||||
case OP_ADDWITHFLAGS:
|
||||
return {
|
||||
.Write = FLAG_NZCV,
|
||||
.CanReplace = true,
|
||||
.Replacement = OP_ADD,
|
||||
};
|
||||
|
||||
case OP_SUBWITHFLAGS:
|
||||
return {
|
||||
.Write = FLAG_NZCV,
|
||||
.CanReplace = true,
|
||||
.Replacement = OP_SUB,
|
||||
};
|
||||
|
||||
case OP_ADCWITHFLAGS:
|
||||
return {
|
||||
.Read = FLAG_C,
|
||||
.Write = FLAG_NZCV,
|
||||
.CanReplace = true,
|
||||
.Replacement = OP_ADC,
|
||||
};
|
||||
|
||||
case OP_SBBWITHFLAGS:
|
||||
return {
|
||||
.Read = FLAG_C,
|
||||
.Write = FLAG_NZCV,
|
||||
.CanReplace = true,
|
||||
.Replacement = OP_SBB,
|
||||
};
|
||||
|
||||
case OP_ADDNZCV:
|
||||
case OP_SUBNZCV:
|
||||
case OP_TESTNZ:
|
||||
@@ -153,9 +183,19 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp)
|
||||
.CanEliminate = true,
|
||||
};
|
||||
|
||||
case OP_SETSMALLNZV:
|
||||
return {
|
||||
.Write = FLAG_N | FLAG_Z | FLAG_V,
|
||||
.CanEliminate = true,
|
||||
};
|
||||
|
||||
case OP_LOADNZCV:
|
||||
return {.Read = FLAG_NZCV};
|
||||
|
||||
case OP_ADC:
|
||||
case OP_SBB:
|
||||
return {.Read = FLAG_C};
|
||||
|
||||
case OP_ADCNZCV:
|
||||
case OP_SBBNZCV:
|
||||
return {
|
||||
@@ -169,6 +209,11 @@ DeadFlagCalculationEliminination::Classify(IROp_Header *IROp)
|
||||
return {.Read = FlagsForCondClassType(Op->Cond)};
|
||||
}
|
||||
|
||||
case OP_NEG: {
|
||||
auto Op = IROp->CW<IR::IROp_Neg>();
|
||||
return {.Read = FlagsForCondClassType(Op->Cond)};
|
||||
}
|
||||
|
||||
case OP_CONDJUMP: {
|
||||
auto Op = IROp->CW<IR::IROp_CondJump>();
|
||||
if (!Op->FromNZCV)
|
||||
@@ -286,42 +331,53 @@ bool DeadFlagCalculationEliminination::Run(IREmitter *IREmit) {
|
||||
while (1) {
|
||||
auto [CodeNode, IROp] = CodeLast();
|
||||
|
||||
// Optimiation algorithm: For each flag written...
|
||||
// Optimizing flags can cause earlier flag reads to become dead but dead
|
||||
// flag reads should not impede optimiation of earlier dead flag writes.
|
||||
// We must DCE as we go to ensure we converge in a single iteration.
|
||||
//
|
||||
// If the flag has a later read (per FlagsRead), remove the flag from
|
||||
// FlagsRead, since the reader is covered by this write.
|
||||
//
|
||||
// Else, there is no later read, so remove the flag write (if we can).
|
||||
// This is the active part of the optimization.
|
||||
//
|
||||
// Then, add each flag read to FlagsRead.
|
||||
//
|
||||
// This order is important: instructions that read-modify-write flags
|
||||
// (like adcs) first read flags, then write flags. Since we're iterating
|
||||
// the block backwards, that means we handle the write first.
|
||||
struct FlagInfo Info = Classify(IROp);
|
||||
// TODO: This whole pass could be merged with DCE?
|
||||
bool HasSideEffects = IR::HasSideEffects(IROp->Op);
|
||||
if (!HasSideEffects && CodeNode->GetUses() == 0) {
|
||||
Changed = true;
|
||||
IREmit->Remove(CodeNode);
|
||||
} else {
|
||||
// Optimiation algorithm: For each flag written...
|
||||
//
|
||||
// If the flag has a later read (per FlagsRead), remove the flag from
|
||||
// FlagsRead, since the reader is covered by this write.
|
||||
//
|
||||
// Else, there is no later read, so remove the flag write (if we can).
|
||||
// This is the active part of the optimization.
|
||||
//
|
||||
// Then, add each flag read to FlagsRead.
|
||||
//
|
||||
// This order is important: instructions that read-modify-write flags
|
||||
// (like adcs) first read flags, then write flags. Since we're iterating
|
||||
// the block backwards, that means we handle the write first.
|
||||
struct FlagInfo Info = Classify(IROp);
|
||||
|
||||
if (!Info.Trivial) {
|
||||
bool Eliminated = false;
|
||||
if (!Info.Trivial) {
|
||||
bool Eliminated = false;
|
||||
|
||||
if ((FlagsRead & Info.Write) == 0) {
|
||||
if (Info.CanEliminate) {
|
||||
IREmit->Remove(CodeNode);
|
||||
Eliminated = true;
|
||||
Changed = true;
|
||||
} else if (Info.CanReplace) {
|
||||
IROp->Op = Info.Replacement;
|
||||
Changed = true;
|
||||
if ((FlagsRead & Info.Write) == 0) {
|
||||
if (Info.CanEliminate) {
|
||||
IREmit->Remove(CodeNode);
|
||||
Eliminated = true;
|
||||
Changed = true;
|
||||
} else if (Info.CanReplace) {
|
||||
IROp->Op = Info.Replacement;
|
||||
Changed = true;
|
||||
}
|
||||
} else {
|
||||
FlagsRead &= ~Info.Write;
|
||||
}
|
||||
} else {
|
||||
FlagsRead &= ~Info.Write;
|
||||
}
|
||||
|
||||
// If we eliminated the instruction, we eliminate its read too. This
|
||||
// check is required to ensure the pass converges locally in a single
|
||||
// iteration.
|
||||
if (!Eliminated)
|
||||
FlagsRead |= Info.Read;
|
||||
// If we eliminated the instruction, we eliminate its read too. This
|
||||
// check is required to ensure the pass converges locally in a single
|
||||
// iteration.
|
||||
if (!Eliminated)
|
||||
FlagsRead |= Info.Read;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate in reverse
|
||||
|
||||
@@ -297,6 +297,12 @@ namespace FEXCore::Allocator {
|
||||
if (c == ' ') {
|
||||
STEAL_LOG("[%d] ParseEnd; RegionBegin: %016lX RegionEnd: %016lX\n", __LINE__, RegionBegin, RegionEnd);
|
||||
|
||||
if (RegionEnd > End) {
|
||||
// Early return if we are completely beyond the allocation space.
|
||||
close(MapsFD);
|
||||
return Regions;
|
||||
}
|
||||
|
||||
State = ScanEnd;
|
||||
|
||||
// If the previous map's ending and the region we just parsed overlap the stack then we need to save the stack mapping.
|
||||
|
||||
@@ -39,14 +39,6 @@ namespace Core {
|
||||
public:
|
||||
virtual ~SignalDelegator() = default;
|
||||
|
||||
/**
|
||||
* @brief Registers an emulated thread's object to a TLS object
|
||||
*
|
||||
* Required to know which thread has received the signal when it occurs
|
||||
*/
|
||||
virtual void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) = 0;
|
||||
virtual void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) = 0;
|
||||
|
||||
struct SignalDelegatorConfig {
|
||||
bool SupportsAVX{};
|
||||
|
||||
@@ -55,6 +47,7 @@ namespace Core {
|
||||
uint64_t DispatcherEnd;
|
||||
|
||||
// Dispatcher entrypoint.
|
||||
uint64_t AbsoluteLoopTopAddress{};
|
||||
uint64_t AbsoluteLoopTopAddressFillSRA{};
|
||||
|
||||
// Signal return pointers.
|
||||
|
||||
@@ -139,6 +139,9 @@ namespace FEXCore::Core {
|
||||
// Async signals aren't guaranteed to be delivered in any particular order, but FEX treats them as FILO.
|
||||
fextl::vector<DeferredSignalState> DeferredSignalFrames;
|
||||
|
||||
///< Data pointer for exclusive use by the frontend
|
||||
void* FrontendPtr;
|
||||
|
||||
// BaseFrameState should always be at the end, directly before the interrupt fault page
|
||||
alignas(16) FEXCore::Core::CpuStateFrame BaseFrameState{};
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ namespace FEX::FormatCheck {
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return Header.Magic == COOKIE_MAGIC_V1;
|
||||
}
|
||||
}
|
||||
@@ -551,8 +551,8 @@ int main(int argc, char **argv, char **const envp) {
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::DISABLECRYPTO);
|
||||
}
|
||||
|
||||
// Always disable preserve_all abi.
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::DISABLEPRESERVEALLABI);
|
||||
// Always enable preserve_all abi.
|
||||
HostFeatureControl |= static_cast<uint64_t>(FEXCore::Config::HostFeatures::ENABLEPRESERVEALLABI);
|
||||
|
||||
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_HOSTFEATURES, fextl::fmt::format("{}", HostFeatureControl));
|
||||
FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_FORCESVEWIDTH, fextl::fmt::format("{}", SVEWidth));
|
||||
|
||||
@@ -32,8 +32,8 @@ class DummySignalDelegator final : public FEXCore::SignalDelegator, public FEXCo
|
||||
}
|
||||
|
||||
protected:
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) override;
|
||||
void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) override;
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread);
|
||||
void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread);
|
||||
|
||||
private:
|
||||
FEXCore::Core::InternalThreadState *GetTLSThread();
|
||||
|
||||
@@ -417,11 +417,17 @@ int main(int argc, char **argv, char **const envp) {
|
||||
|
||||
fextl::unique_ptr<FEX::HLE::MemAllocator> Allocator;
|
||||
fextl::vector<FEXCore::Allocator::MemoryRegion> Base48Bit;
|
||||
fextl::vector<FEXCore::Allocator::MemoryRegion> Low4GB;
|
||||
|
||||
if (Loader.Is64BitMode()) {
|
||||
// Destroy the 48th bit if it exists
|
||||
Base48Bit = FEXCore::Allocator::Steal48BitVA();
|
||||
} else {
|
||||
// Reserve [0x1_0000_0000, 0x2_0000_0000).
|
||||
// Safety net if 32-bit address calculation overflows in to 64-bit range.
|
||||
constexpr uint64_t First64BitAddr = 0x1'0000'0000ULL;
|
||||
Low4GB = FEXCore::Allocator::StealMemoryRegion(First64BitAddr, First64BitAddr + First64BitAddr);
|
||||
|
||||
// Setup our userspace allocator
|
||||
FEXCore::Allocator::SetupHooks();
|
||||
Allocator = FEX::HLE::CreatePassthroughAllocator();
|
||||
@@ -484,6 +490,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
|
||||
auto ParentThread = SyscallHandler->TM.CreateThread(Loader.DefaultRIP(), Loader.GetStackPointer());
|
||||
SyscallHandler->TM.TrackThread(ParentThread);
|
||||
SignalDelegation->RegisterTLSState(ParentThread);
|
||||
|
||||
// Pass in our VDSO thunks
|
||||
CTX->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions());
|
||||
@@ -561,6 +568,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
|
||||
auto ProgramStatus = ParentThread->StatusCode;
|
||||
|
||||
SignalDelegation->UninstallTLSState(ParentThread);
|
||||
CTX->DestroyThread(ParentThread);
|
||||
|
||||
DebugServer.reset();
|
||||
@@ -578,6 +586,8 @@ int main(int argc, char **argv, char **const envp) {
|
||||
|
||||
FEXCore::Allocator::ClearHooks();
|
||||
FEXCore::Allocator::ReclaimMemoryRegion(Base48Bit);
|
||||
FEXCore::Allocator::ReclaimMemoryRegion(Low4GB);
|
||||
|
||||
// Allocator is now original system allocator
|
||||
FEXCore::Telemetry::Shutdown(Program.ProgramName);
|
||||
FEXCore::Profiler::Shutdown();
|
||||
|
||||
@@ -3,7 +3,7 @@ set(SRCS Main.cpp
|
||||
XXFileHash.cpp)
|
||||
|
||||
add_executable(${NAME} ${SRCS})
|
||||
list(APPEND LIBS FEXCore Common)
|
||||
list(APPEND LIBS FEXCore Common xxHash::xxhash)
|
||||
|
||||
target_include_directories(${NAME} PRIVATE ${CMAKE_SOURCE_DIR}/Source/)
|
||||
|
||||
|
||||
@@ -34,36 +34,23 @@ set (SRCS
|
||||
LinuxSyscalls/x32/IoctlEmulation.cpp
|
||||
LinuxSyscalls/x64/EPoll.cpp
|
||||
LinuxSyscalls/x64/FD.cpp
|
||||
LinuxSyscalls/x64/IO.cpp
|
||||
LinuxSyscalls/x64/Ioctl.cpp
|
||||
LinuxSyscalls/x64/Info.cpp
|
||||
LinuxSyscalls/x64/Memory.cpp
|
||||
LinuxSyscalls/x64/Msg.cpp
|
||||
LinuxSyscalls/x64/NotImplemented.cpp
|
||||
LinuxSyscalls/x64/Semaphore.cpp
|
||||
LinuxSyscalls/x64/Sched.cpp
|
||||
LinuxSyscalls/x64/Signals.cpp
|
||||
LinuxSyscalls/x64/Socket.cpp
|
||||
LinuxSyscalls/x64/Thread.cpp
|
||||
LinuxSyscalls/x64/Syscalls.cpp
|
||||
LinuxSyscalls/x64/Time.cpp
|
||||
LinuxSyscalls/Syscalls/EPoll.cpp
|
||||
LinuxSyscalls/Syscalls/FD.cpp
|
||||
LinuxSyscalls/Syscalls/FS.cpp
|
||||
LinuxSyscalls/Syscalls/Passthrough.cpp
|
||||
LinuxSyscalls/Syscalls/Info.cpp
|
||||
LinuxSyscalls/Syscalls/IO.cpp
|
||||
LinuxSyscalls/Syscalls/IOUring.cpp
|
||||
LinuxSyscalls/Syscalls/Key.cpp
|
||||
LinuxSyscalls/Syscalls/Memory.cpp
|
||||
LinuxSyscalls/Syscalls/Msg.cpp
|
||||
LinuxSyscalls/Syscalls/Namespace.cpp
|
||||
LinuxSyscalls/Syscalls/Sched.cpp
|
||||
LinuxSyscalls/Syscalls/Semaphore.cpp
|
||||
LinuxSyscalls/Syscalls/SHM.cpp
|
||||
LinuxSyscalls/Syscalls/Signals.cpp
|
||||
LinuxSyscalls/Syscalls/Socket.cpp
|
||||
LinuxSyscalls/Syscalls/Thread.cpp
|
||||
LinuxSyscalls/Syscalls/Time.cpp
|
||||
LinuxSyscalls/Syscalls/Timer.cpp
|
||||
LinuxSyscalls/Syscalls/NotImplemented.cpp
|
||||
LinuxSyscalls/Syscalls/Stubs.cpp)
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace FEX::HLE {
|
||||
// Called from the signal trampoline function.
|
||||
void HandleSignal(int Signal, void *Info, void *UContext);
|
||||
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) override;
|
||||
void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread) override;
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread);
|
||||
void UninstallTLSState(FEXCore::Core::InternalThreadState *Thread);
|
||||
|
||||
/**
|
||||
* @brief Registers a signal handler for the host to handle a signal
|
||||
|
||||
@@ -393,22 +393,27 @@ struct StackFramePlusRet {
|
||||
uint64_t Pad;
|
||||
};
|
||||
|
||||
[[noreturn]]
|
||||
static void CloneBody(StackFrameData *Data, bool NeedsDataFree) {
|
||||
uint64_t Result = FEX::HLE::HandleNewClone(Data->Thread, Data->CTX, &Data->NewFrame, &Data->GuestArgs);
|
||||
auto Stack = Data->GuestArgs.NewStack;
|
||||
if (NeedsDataFree) {
|
||||
FEXCore::Allocator::free(Data);
|
||||
}
|
||||
|
||||
FEX::LinuxEmulation::Threads::DeallocateStackObjectAndExit(Stack, Result);
|
||||
FEX_UNREACHABLE;
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
static void Clone3HandlerRet() {
|
||||
StackFrameData *Data = (StackFrameData*)alloca(0);
|
||||
uint64_t Result = FEX::HLE::HandleNewClone(Data->Thread, Data->CTX, &Data->NewFrame, &Data->GuestArgs);
|
||||
FEX::LinuxEmulation::Threads::DeallocateStackObject(Data->GuestArgs.NewStack);
|
||||
// To behave like a real clone, we now just need to call exit here
|
||||
exit(Result);
|
||||
FEX_UNREACHABLE;
|
||||
CloneBody(Data, false);
|
||||
}
|
||||
|
||||
static int Clone2HandlerRet(void *arg) {
|
||||
StackFrameData *Data = (StackFrameData*)arg;
|
||||
uint64_t Result = FEX::HLE::HandleNewClone(Data->Thread, Data->CTX, &Data->NewFrame, &Data->GuestArgs);
|
||||
FEX::LinuxEmulation::Threads::DeallocateStackObject(Data->GuestArgs.NewStack);
|
||||
FEXCore::Allocator::free(arg);
|
||||
return Result;
|
||||
CloneBody(Data, true);
|
||||
}
|
||||
|
||||
// Clone3 flags
|
||||
@@ -975,7 +980,7 @@ fextl::unique_ptr<FEXCore::HLE::SourcecodeMap> SyscallHandler::GenerateMap(const
|
||||
fextl::istringstream Stream(SourceData);
|
||||
|
||||
constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int IndexStream = ::open(GuestSourceFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, USER_PERMS);
|
||||
int IndexStream = ::open(GuestIndexFile.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, USER_PERMS);
|
||||
|
||||
if (IndexStream == -1) {
|
||||
LogMan::Msg::DFmt("GenerateMap: Failed to open '{}' for writing", GuestIndexFile);
|
||||
|
||||
@@ -38,9 +38,11 @@ $end_info$
|
||||
#define SYSCALL_ARCH_NAME Arm64
|
||||
#endif
|
||||
|
||||
#include "LinuxSyscalls/x64/SyscallsEnum.h"
|
||||
|
||||
#define CONCAT_(a, b) a ## b
|
||||
#define CONCAT(a, b) CONCAT_(a, b)
|
||||
#define SYSCALL_DEF(name) ( SYSCALL_ARCH_NAME::CONCAT(CONCAT(SYSCALL_, SYSCALL_ARCH_NAME), _##name))
|
||||
#define SYSCALL_DEF(name) ( HLE::SYSCALL_ARCH_NAME::CONCAT(CONCAT(SYSCALL_, SYSCALL_ARCH_NAME), _##name))
|
||||
|
||||
// #define DEBUG_STRACE
|
||||
|
||||
@@ -63,19 +65,10 @@ class SignalDelegator;
|
||||
void RegisterFS(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterInfo(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterIO(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterIOUring(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterKey(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterMemory(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterMsg(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterNamespace(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterNuma(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSched(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSHM(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSignals(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSocket(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterThread(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterTime(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterTimer(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterStubs(FEX::HLE::SyscallHandler *Handler);
|
||||
@@ -634,9 +627,6 @@ bool IsFaultLocation(uint64_t PC);
|
||||
#define REGISTER_SYSCALL_IMPL(name, lambda) \
|
||||
REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, FEXCore::IR::SyscallFlags::DEFAULT, lambda)
|
||||
|
||||
#define REGISTER_SYSCALL_IMPL_PASS(name, lambda) \
|
||||
REGISTER_SYSCALL_IMPL_INTERNAL(name, SYSCALL_DEF(name), FEXCore::IR::SyscallFlags::DEFAULT, lambda)
|
||||
|
||||
#define REGISTER_SYSCALL_IMPL_FLAGS(name, flags, lambda) \
|
||||
REGISTER_SYSCALL_IMPL_INTERNAL(name, ~0, flags, lambda)
|
||||
|
||||
|
||||
@@ -19,16 +19,10 @@ namespace FEX::HLE {
|
||||
void RegisterEpoll(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(epoll_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(epoll_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int size) -> uint64_t {
|
||||
uint64_t Result = epoll_create(size);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(epoll_create1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t {
|
||||
uint64_t Result = epoll_create1(flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,18 +32,6 @@ namespace FEX::HLE {
|
||||
void RegisterFD(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(read, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, size_t count) -> uint64_t {
|
||||
uint64_t Result = ::read(fd, buf, count);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(write, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, size_t count) -> uint64_t {
|
||||
uint64_t Result = ::write(fd, buf, count);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, int flags, uint32_t mode) -> uint64_t {
|
||||
flags = FEX::HLE::RemapFromX86Flags(flags);
|
||||
@@ -57,37 +45,25 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(chown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::chown(pathname, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::fchown(fd, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(lchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(lchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::lchown(pathname, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(lseek, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, uint64_t offset, int whence) -> uint64_t {
|
||||
uint64_t Result = ::lseek(fd, offset, whence);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(access, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, int mode) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Access(pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pipe, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(pipe, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pipefd[2]) -> uint64_t {
|
||||
uint64_t Result = ::pipe(pipefd);
|
||||
SYSCALL_ERRNO();
|
||||
@@ -100,60 +76,12 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(flock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, int operation) -> uint64_t {
|
||||
uint64_t Result = ::flock(fd, operation);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd) -> uint64_t {
|
||||
uint64_t Result = ::fsync(fd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fdatasync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd) -> uint64_t {
|
||||
uint64_t Result = ::fdatasync(fd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ftruncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, off_t length) -> uint64_t {
|
||||
uint64_t Result = ::ftruncate(fd, length);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, int mode) -> uint64_t {
|
||||
uint64_t Result = ::fchmod(fd, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fadvise64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, off_t offset, off_t len, int advice) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fadvise64), fd, offset, len, advice);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(inotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::inotify_init();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_add_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, const char *pathname, uint32_t mask) -> uint64_t {
|
||||
uint64_t Result = ::inotify_add_watch(fd, pathname, mask);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_rm_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, int wd) -> uint64_t {
|
||||
uint64_t Result = ::inotify_rm_watch(fd, wd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(openat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfs, const char *pathname, int flags, uint32_t mode) -> uint64_t {
|
||||
flags = FEX::HLE::RemapFromX86Flags(flags);
|
||||
@@ -161,63 +89,12 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mkdirat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, mode_t mode) -> uint64_t {
|
||||
uint64_t Result = ::mkdirat(dirfd, pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mknodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, mode_t mode, dev_t dev) -> uint64_t {
|
||||
uint64_t Result = ::mknodat(dirfd, pathname, mode, dev);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchownat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, uid_t owner, gid_t group, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::fchownat(dirfd, pathname, owner, group, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(unlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::unlinkat(dirfd, pathname, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int olddirfd, const char *oldpath, int newdirfd, const char *newpath) -> uint64_t {
|
||||
uint64_t Result = ::renameat(olddirfd, oldpath, newdirfd, newpath);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(linkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::linkat(olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(symlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *target, int newdirfd, const char *linkpath) -> uint64_t {
|
||||
uint64_t Result = ::symlinkat(target, newdirfd, linkpath);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(readlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, char *buf, size_t bufsiz) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Readlinkat(dirfd, pathname, buf, bufsiz);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, mode_t mode) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(fchmodat), dirfd, pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(faccessat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int mode) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.FAccessat(dirfd, pathname, mode);
|
||||
@@ -232,12 +109,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_getfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pidfd, int fd, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_getfd), pidfd, fd, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(openat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfs, const char *pathname, struct open_how *how, size_t usize) -> uint64_t {
|
||||
open_how HostHow{};
|
||||
@@ -251,32 +122,10 @@ namespace FEX::HLE {
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(faccessat2, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(pidfd_getfd, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(openat2, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(splice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::splice(fd_in, off_in, fd_out, off_out, len, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tee, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd_in, int fd_out, size_t len, unsigned int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::tee(fd_in, fd_out, len, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timerfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int32_t clockid, int32_t flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::timerfd_create(clockid, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(eventfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(eventfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t count) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(eventfd2), count, 0);
|
||||
SYSCALL_ERRNO();
|
||||
@@ -289,27 +138,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_init1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::inotify_init1(flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = FHU::Syscalls::renameat2(olddirfd, oldpath, newdirfd, newpath, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *name, uint32_t flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(memfd_create), name, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(statx, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, int flags, uint32_t mask, struct statx *statxbuf) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
@@ -317,45 +145,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(name_to_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, struct file_handle *handle, int *mount_id, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(name_to_handle_at), dirfd, pathname, handle, mount_id, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_by_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int mount_fd, struct file_handle *handle, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(open_by_handle_at), mount_fd, handle, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(eventfd2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int count, int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(eventfd2), count, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(copy_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(copy_file_range), fd_in, off_in, fd_out, off_out, len, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 3, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_open), pid, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(pidfd_open, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 9, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(close_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int first, unsigned int last, unsigned int flags) -> uint64_t {
|
||||
@@ -366,72 +155,5 @@ namespace FEX::HLE {
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(close_range, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_create_ruleset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *const rule_attr, size_t size, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(landlock_create_ruleset), rule_attr, size, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_add_rule, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t ruleset_fd, uint64_t rule_type, void *const rule_attr, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(landlock_add_rule), ruleset_fd, rule_type, rule_attr, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_restrict_self, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t ruleset_fd, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(landlock_restrict_self), ruleset_fd, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(landlock_create_ruleset, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(landlock_add_rule, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(landlock_restrict_self, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_secret, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(memfd_secret), flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(memfd_secret, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 15, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(process_mrelease, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pidfd, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(process_mrelease), pidfd, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(process_mrelease, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(6, 5, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(cachestat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, void* cstat_range, void* cstat, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(cachestat), fd, cstat_range, cstat, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(cachestat, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmodat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, mode_t mode, uint32_t flags) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(fchmodat2), dirfd, pathname, mode, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(fchmodat2, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,55 +25,37 @@ namespace FEX::HLE {
|
||||
void RegisterFS(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcwd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, char *buf, size_t size) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(getcwd), buf, size);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path) -> uint64_t {
|
||||
uint64_t Result = ::chdir(path);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd) -> uint64_t {
|
||||
uint64_t Result = ::fchdir(fd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(rename, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(rename, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *oldpath, const char *newpath) -> uint64_t {
|
||||
uint64_t Result = ::rename(oldpath, newpath);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mkdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(mkdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t {
|
||||
uint64_t Result = ::mkdir(pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(rmdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(rmdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname) -> uint64_t {
|
||||
uint64_t Result = ::rmdir(pathname);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(link, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(link, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *oldpath, const char *newpath) -> uint64_t {
|
||||
uint64_t Result = ::link(oldpath, newpath);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname) -> uint64_t {
|
||||
uint64_t Result = ::unlink(pathname);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(symlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(symlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *target, const char *linkpath) -> uint64_t {
|
||||
uint64_t Result = ::symlink(target, linkpath);
|
||||
SYSCALL_ERRNO();
|
||||
@@ -85,103 +67,24 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(chmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t {
|
||||
uint64_t Result = ::chmod(pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(umask, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, mode_t mask) -> uint64_t {
|
||||
uint64_t Result = ::umask(mask);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(mknod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode, dev_t dev) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Mknod(pathname, mode, dev);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ustat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, dev_t dev, struct ustat *ubuf) -> uint64_t {
|
||||
// Doesn't exist on AArch64, will return -ENOSYS
|
||||
// Since version 2.28 of GLIBC it has stopped providing a wrapper for this syscall
|
||||
uint64_t Result = syscall(SYSCALL_DEF(ustat), dev, ubuf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
/*
|
||||
arg1 is one of: void, unsigned int fs_index, const char *fsname
|
||||
arg2 is one of: void, char *buf
|
||||
*/
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sysfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int option, uint64_t arg1, uint64_t arg2) -> uint64_t {
|
||||
// Doesn't exist on AArch64, will return -ENOSYS
|
||||
uint64_t Result = syscall(SYSCALL_DEF(sysfs), option, arg1, arg2);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(truncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, off_t length) -> uint64_t {
|
||||
uint64_t Result = ::truncate(path, length);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(creat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(creat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, mode_t mode) -> uint64_t {
|
||||
uint64_t Result = ::creat(pathname, mode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chroot, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path) -> uint64_t {
|
||||
uint64_t Result = ::chroot(path);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
sync();
|
||||
return 0; // always successful
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(acct, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *filename) -> uint64_t {
|
||||
uint64_t Result = ::acct(filename);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data) -> uint64_t {
|
||||
uint64_t Result = ::mount(source, target, filesystemtype, mountflags, data);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(umount2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *target, int flags) -> uint64_t {
|
||||
uint64_t Result = ::umount2(target, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapon, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, int swapflags) -> uint64_t {
|
||||
uint64_t Result = ::swapon(path, swapflags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapoff, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path) -> uint64_t {
|
||||
uint64_t Result = ::swapoff(path);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(syncfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(syncfs), fd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(setxattr,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, const void *value, size_t size, int flags) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Setxattr(path, name, value, size, flags);
|
||||
@@ -194,12 +97,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, const char *name, const void *value, size_t size, int flags) -> uint64_t {
|
||||
uint64_t Result = ::fsetxattr(fd, name, value, size, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(getxattr,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name, void *value, size_t size) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Getxattr(path, name, value, size);
|
||||
@@ -212,12 +109,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fgetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, const char *name, void *value, size_t size) -> uint64_t {
|
||||
uint64_t Result = ::fgetxattr(fd, name, value, size);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(listxattr,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, char *list, size_t size) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Listxattr(path, list, size);
|
||||
@@ -230,12 +121,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(flistxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, char *list, size_t size) -> uint64_t {
|
||||
uint64_t Result = ::flistxattr(fd, list, size);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL(removexattr,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *path, const char *name) -> uint64_t {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Removexattr(path, name);
|
||||
@@ -247,40 +132,5 @@ namespace FEX::HLE {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.LRemovexattr(path, name);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fremovexattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, const char *name) -> uint64_t {
|
||||
uint64_t Result = ::fremovexattr(fd, name);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int flags, unsigned int event_f_flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fanotify_init), flags, event_f_flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_mark, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fanotify_fd, unsigned int flags, uint64_t mask, int dirfd, const char *pathname) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fanotify_mark), fanotify_fd, flags, mask, dirfd, pathname);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pivot_root, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *new_root, const char *put_old) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pivot_root), new_root, put_old);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(quotactl_fd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t fd, uint32_t cmd, uint32_t id, void* addr) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(quotactl_fd), fd, cmd, id, addr);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(quotactl_fd, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,52 +19,16 @@ namespace FEX::HLE {
|
||||
void RegisterIO(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(iopl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(iopl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int level) -> uint64_t {
|
||||
// Just claim we don't have permission
|
||||
return -EPERM;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioperm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(ioperm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned long from, unsigned long num, int turn_on) -> uint64_t {
|
||||
// ioperm not available on our architecture
|
||||
return -EPERM;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned nr_events, aio_context_t *ctx_idp) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_setup), nr_events, ctx_idp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_destroy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_destroy), ctx_id);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_submit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, long nr, struct iocb **iocbpp) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_submit), ctx_id, nr, iocbpp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_cancel, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, struct iocb *iocb, struct io_event *result) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_cancel), ctx_id, iocb, result);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_set, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int which, int who) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(ioprio_set), which, who);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_get, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int which, int who, int ioprio) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(ioprio_get), which, who, ioprio);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/Syscalls/Thread.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace SignalDelegator {
|
||||
struct GuestSigAction;
|
||||
}
|
||||
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterIOUring(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint32_t entries, void* params) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_uring_setup), entries, params);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_enter, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int fd, uint32_t to_submit, uint32_t min_complete, uint32_t flags, void *argp, size_t argsz) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_uring_enter), fd, to_submit, min_complete, flags, argp, argsz);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_register, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int fd, unsigned int opcode, void *arg, uint32_t nr_args) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_uring_register), fd, opcode, arg, nr_args);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(io_uring_setup, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(io_uring_enter, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(io_uring_register, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,44 +63,6 @@ namespace FEX::HLE {
|
||||
return 0;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(syslog, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int type, char *bufp, int len) -> uint64_t {
|
||||
uint64_t Result = ::klogctl(type, bufp, len);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getrandom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *buf, size_t buflen, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(getrandom), buf, buflen, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(capget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, cap_user_header_t hdrp, cap_user_data_t datap) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(capget), hdrp, datap);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(capset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, cap_user_header_t hdrp, const cap_user_data_t datap) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(capset), hdrp, datap);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(getcpu, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) -> uint64_t {
|
||||
// tcache is ignored
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(getcpu), cpu, node, nullptr);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
//compare two processes to determine if they share a kernel resource
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(kcmp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(kcmp), pid1, pid2, type, idx1, idx2);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(seccomp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int operation, unsigned int flags, void *args) -> uint64_t {
|
||||
// FEX doesn't support seccomp
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/Types.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterKey(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(add_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *type, const char *description, const void *payload, size_t plen, key_serial_t keyring) -> uint64_t {
|
||||
uint64_t Result = syscall(SYS_add_key, type, description, payload, plen, keyring);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(request_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *type, const char *description, const char *callout_info, key_serial_t dest_keyring) -> uint64_t {
|
||||
uint64_t Result = syscall(SYS_request_key, type, description, callout_info, dest_keyring);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(keyctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int operation, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) -> uint64_t {
|
||||
uint64_t Result = syscall(SYS_keyctl, operation, arg2, arg3, arg4, arg5);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t len, int prot, int pkey) -> uint64_t {
|
||||
// Added in Linux 4.9
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pkey_mprotect), addr, len, prot, pkey);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_alloc, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int flags, unsigned int access_rights) -> uint64_t {
|
||||
// Added in Linux 4.9
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pkey_alloc), flags, access_rights);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_free, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pkey) -> uint64_t {
|
||||
// Added in Linux 4.9
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pkey_free), pkey);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,18 +28,6 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length, int32_t flags) -> uint64_t {
|
||||
uint64_t Result = ::msync(addr, length, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mincore, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length, uint8_t *vec) -> uint64_t {
|
||||
uint64_t Result = ::mincore(addr, length, vec);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t length, int32_t advice) -> uint64_t {
|
||||
uint64_t Result = ::madvise(addr, length, advice);
|
||||
@@ -49,77 +37,5 @@ namespace FEX::HLE {
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const void *addr, size_t len) -> uint64_t {
|
||||
uint64_t Result = ::mlock(addr, len);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(munlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const void *addr, size_t len) -> uint64_t {
|
||||
uint64_t Result = ::munlock(addr, len);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const void *addr, size_t len, int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mlock2), addr, len, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(remap_file_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, size_t size, int prot, size_t pgoff, int flags) -> uint64_t {
|
||||
// This syscall is deprecated, not sure when it will end up being removed
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(remap_file_pages), addr, size, prot, pgoff, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mbind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *addr, unsigned long len, int mode, const unsigned long *nodemask, unsigned long maxnode, unsigned flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mbind), addr, len, mode, nodemask, maxnode, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(get_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(get_mempolicy), mode, nodemask, maxnode, addr, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int mode, const unsigned long *nodemask, unsigned long maxnode) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(set_mempolicy), mode, nodemask, maxnode);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(migrate_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pid, unsigned long maxnode, const unsigned long *old_nodes, const unsigned long *new_nodes) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(migrate_pages), pid, maxnode, old_nodes, new_nodes);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pid, unsigned long count, void **pages, const int *nodes, int *status, int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(move_pages), pid, count, pages, nodes, status, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(membarrier, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int cmd, int flags) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(membarrier), cmd, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 17, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy_home_node, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint64_t start, uint64_t len, uint64_t home_node, uint64_t flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(set_mempolicy_home_node), start, len, home_node, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(set_mempolicy_home_node, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterMsg(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, key_t key, int msgflg) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(msgget), key, msgflg);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgsnd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int msqid, const void *msgp, size_t msgsz, int msgflg) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(msgsnd), msqid, msgp, msgsz, msgflg);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgrcv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(msgrcv), msqid, msgp, msgsz, msgtyp, msgflg);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int msqid, int cmd, struct msqid_ds *buf) -> uint64_t {
|
||||
// A quirk of this syscall
|
||||
// On 32-bit this syscall ONLY supports IPC_64 msqid_ds encoding
|
||||
// If an application want to use the old style encoding then it needs to use the ipc syscall with MSGCTL command
|
||||
// ipc syscall supports both IPC_64 and old encoding
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(msgctl), msqid, cmd, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
// last two parameters are optional
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mq_unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, const char *name) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_unlink), name);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/Syscalls/Thread.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace SignalDelegator {
|
||||
struct GuestSigAction;
|
||||
}
|
||||
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterNamespace(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 1, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_tree, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dfd, const char *filename, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(open_tree), dfd, filename, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(move_mount), from_dfd, from_pathname, to_dfd, to_pathname, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsopen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dfd, const char *path, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fsopen), dfd, path, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsconfig, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, unsigned int cmd, const char *key, const void *value, int aux) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fsconfig), fd, cmd, key, value, aux);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fs_fd, uint32_t flags, uint32_t attr_flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fsmount), fs_fd, flags, attr_flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fspick, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dfd, const char *path, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(fspick), dfd, path, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(open_tree, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(move_mount, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsopen, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsconfig, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsmount, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fspick, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
if (Handler->GetHostKernelVersion() >= FEX::HLE::SyscallHandler::KernelVersion(5, 12, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int dfd, const char *path, unsigned int flags, void *uattr, size_t usize) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mount_setattr), dfd, path, flags, uattr, usize);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(mount_setattr, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ namespace FEX::HLE {
|
||||
// these are removed/not implemented in the linux kernel we present
|
||||
|
||||
void RegisterNotImplemented(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_NOT_IMPL(ustat);
|
||||
REGISTER_SYSCALL_NOT_IMPL(sysfs);
|
||||
REGISTER_SYSCALL_NOT_IMPL(uselib);
|
||||
REGISTER_SYSCALL_NOT_IMPL(create_module);
|
||||
REGISTER_SYSCALL_NOT_IMPL(get_kernel_syms);
|
||||
|
||||
@@ -0,0 +1,889 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
meta: LinuxSyscalls|syscalls-shared ~ Syscall implementations shared between x86 and x86-64
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
#ifdef _M_ARM_64
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame *Frame) {
|
||||
register uint64_t x0 asm ("x0");
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register uint64_t x2 asm ("x2") = arg3;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
, "r" (x2)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register uint64_t x2 asm ("x2") = arg3;
|
||||
register uint64_t x3 asm ("x3") = arg4;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
, "r" (x2)
|
||||
, "r" (x3)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register uint64_t x2 asm ("x2") = arg3;
|
||||
register uint64_t x3 asm ("x3") = arg4;
|
||||
register uint64_t x4 asm ("x4") = arg5;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
, "r" (x2)
|
||||
, "r" (x3)
|
||||
, "r" (x4)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register uint64_t x2 asm ("x2") = arg3;
|
||||
register uint64_t x3 asm ("x3") = arg4;
|
||||
register uint64_t x4 asm ("x4") = arg5;
|
||||
register uint64_t x5 asm ("x5") = arg6;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
, "r" (x2)
|
||||
, "r" (x3)
|
||||
, "r" (x4)
|
||||
, "r" (x5)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) {
|
||||
register uint64_t x0 asm ("x0") = arg1;
|
||||
register uint64_t x1 asm ("x1") = arg2;
|
||||
register uint64_t x2 asm ("x2") = arg3;
|
||||
register uint64_t x3 asm ("x3") = arg4;
|
||||
register uint64_t x4 asm ("x4") = arg5;
|
||||
register uint64_t x5 asm ("x5") = arg6;
|
||||
register uint64_t x6 asm ("x6") = arg7;
|
||||
register int x8 asm ("x8") = syscall_num;
|
||||
__asm volatile(R"(
|
||||
svc #0;
|
||||
)"
|
||||
: "=r" (x0)
|
||||
: "r" (x8)
|
||||
, "r" (x0)
|
||||
, "r" (x1)
|
||||
, "r" (x2)
|
||||
, "r" (x3)
|
||||
, "r" (x4)
|
||||
, "r" (x5)
|
||||
, "r" (x6)
|
||||
: "memory");
|
||||
return x0;
|
||||
}
|
||||
#else
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough0(FEXCore::Core::CpuStateFrame *Frame) {
|
||||
uint64_t Result = ::syscall(syscall_num);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough1(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough2(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough3(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough4(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough5(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough6(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
|
||||
template<int syscall_num>
|
||||
requires (syscall_num != -1)
|
||||
uint64_t SyscallPassthrough7(FEXCore::Core::CpuStateFrame *Frame, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) {
|
||||
uint64_t Result = ::syscall(syscall_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
SYSCALL_ERRNO();
|
||||
}
|
||||
#endif
|
||||
|
||||
void RegisterCommon(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(read, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(read)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(write, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(write)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(lseek, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(lseek)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_yield, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(sched_yield)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(msync)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mincore, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(mincore)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(_shmget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(_shmget)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(_shmctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(_shmctl)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getpid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(socket, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(socket)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(connect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(connect)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sendto, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(sendto)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(recvfrom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(recvfrom)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(shutdown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(shutdown)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(bind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(bind)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(listen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(listen)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsockname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getsockname)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpeername, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getpeername)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(socketpair, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(socketpair)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(kill, SyscallFlags::DEFAULT,
|
||||
SyscallPassthrough2<SYSCALL_DEF(kill)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(semget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(semget)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(msgget)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgsnd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(msgsnd)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgrcv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(msgrcv)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(msgctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(msgctl)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(flock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(flock)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(fsync)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fdatasync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(fdatasync)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(truncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(truncate)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ftruncate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(ftruncate)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcwd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getcwd)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(chdir)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchdir, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(fchdir)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmod, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(fchmod)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fchown)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(umask, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(umask)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(syslog, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(syslog)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(geteuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getegid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setpgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getppid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getppid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(setsid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setreuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setregid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getgroups)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setgroups)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setresuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getresuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setresgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getresgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(getpgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setfsuid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setfsgid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(getsid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(capget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(capget)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(capset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(capset)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(personality)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getpriority)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setpriority)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(sched_setparam)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(sched_getparam)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(sched_setscheduler)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(sched_getscheduler)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_max, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(sched_get_priority_max)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_min, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(sched_get_priority_min)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(mlock)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(munlock, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(munlock)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pivot_root, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(pivot_root)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(chroot, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(chroot)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sync, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(sync)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(acct, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(acct)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mount)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(umount2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(umount2)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapon, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(swapon)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(swapoff, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(swapoff)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(gettid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(gettid)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(fsetxattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fgetxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(fgetxattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(flistxattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(flistxattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fremovexattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(fremovexattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tkill, SyscallFlags::DEFAULT,
|
||||
SyscallPassthrough2<SYSCALL_DEF(tkill)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(sched_setaffinity)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(sched_getaffinity)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(io_setup)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_destroy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(io_destroy)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_submit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(io_submit)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_cancel, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(io_cancel)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(remap_file_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(remap_file_pages)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fadvise64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(fadvise64)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_getoverrun, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(timer_getoverrun)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_delete, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(timer_delete)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tgkill, SyscallFlags::DEFAULT,
|
||||
SyscallPassthrough3<SYSCALL_DEF(tgkill)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mbind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(mbind)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(set_mempolicy)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(get_mempolicy, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(get_mempolicy)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mq_unlink, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(mq_unlink)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(add_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(add_key)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(request_key, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(request_key)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(keyctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(keyctl)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_set, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(ioprio_set)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(ioprio_get, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(ioprio_get)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_add_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(inotify_add_watch)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_rm_watch, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(inotify_rm_watch)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(migrate_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(migrate_pages)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mkdirat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(mkdirat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mknodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(mknodat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchownat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(fchownat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(unlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(unlinkat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(renameat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(linkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(linkat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(symlinkat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(symlinkat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fchmodat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fchmodat)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(unshare, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(unshare)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(splice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(splice)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tee, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(tee)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_pages, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(move_pages)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timerfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(timerfd_create)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(accept4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(accept4)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(eventfd2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(eventfd2)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(epoll_create1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(epoll_create1)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(inotify_init1, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(inotify_init1)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_init, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(fanotify_init)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fanotify_mark, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(fanotify_mark)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(prlimit_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(prlimit_64)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(name_to_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(name_to_handle_at)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_by_handle_at, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(open_by_handle_at)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(syncfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(syncfs)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setns, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setns)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getcpu, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getcpu)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(kcmp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(kcmp)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(sched_setattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(sched_getattr)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(renameat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(renameat2)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getrandom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getrandom)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(memfd_create)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(membarrier, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(membarrier)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mlock2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(mlock2)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(copy_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(copy_file_range)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_mprotect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(pkey_mprotect)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_alloc, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(pkey_alloc)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pkey_free, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(pkey_free)>);
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_setup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(io_uring_setup)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_enter, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(io_uring_enter)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(io_uring_register, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(io_uring_register)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(open_tree, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(open_tree)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(move_mount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(move_mount)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsopen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fsopen)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsconfig, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(fsconfig)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fsmount, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fsmount)>);
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(fspick, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fspick)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(io_uring_setup, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(io_uring_enter, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(io_uring_register, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(open_tree, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(move_mount, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsopen, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsconfig, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fsmount, UnimplementedSyscallSafe);
|
||||
REGISTER_SYSCALL_IMPL(fspick, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 3, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(pidfd_open)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(pidfd_open, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 8, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pidfd_getfd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(pidfd_getfd)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(pidfd_getfd, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 12, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(mount_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mount_setattr)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(mount_setattr, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(quotactl_fd, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(quotactl_fd)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(quotactl_fd, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_create_ruleset, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(landlock_create_ruleset)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(landlock_create_ruleset, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_add_rule, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(landlock_add_rule)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(landlock_add_rule, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 13, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(landlock_restrict_self, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(landlock_restrict_self)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(landlock_restrict_self, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 14, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(memfd_secret, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(memfd_secret)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(memfd_secret, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 15, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(process_mrelease, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(process_mrelease)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(process_mrelease, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 16, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_waitv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(futex_waitv)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(futex_waitv, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 17, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_mempolicy_home_node, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(set_mempolicy_home_node)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(set_mempolicy_home_node, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
|
||||
namespace x64 {
|
||||
void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
RegisterCommon(Handler);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ioctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(ioctl)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pread_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(pread_64)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwrite_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(pwrite_64)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(readv)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(writev)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(dup, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(dup)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(nanosleep)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getitimer)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setitimer, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setitimer)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(sendfile)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(accept, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(accept)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(sendmsg)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(recvmsg)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(setsockopt)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getsockopt, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(getsockopt)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(wait4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(wait4)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(semop)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(gettimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(gettimeofday)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getrlimit)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getrusage, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getrusage)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sysinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(sysinfo)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(times, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(times)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_sigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(rt_sigqueueinfo)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fstatfs, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(fstatfs)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sched_rr_get_interval, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(sched_rr_get_interval)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(mlockall)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(munlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(munlockall)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(adjtimex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(adjtimex)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(setrlimit, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setrlimit)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(settimeofday, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(settimeofday)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(readahead, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(readahead)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(futex)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_getevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(io_getevents)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(getdents64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getdents64)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(semtimedop)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_create, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(timer_create)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(timer_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(timer_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_getres)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(clock_nanosleep)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_open, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(mq_open)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mq_timedsend)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_timedreceive, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mq_timedreceive)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_notify, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(mq_notify)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mq_getsetattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(mq_getsetattr)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(waitid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(waitid)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pselect6, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(pselect6)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(ppoll)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(set_robust_list)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(get_robust_list)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sync_file_range, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(sync_file_range)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(vmsplice, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(vmsplice)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(utimensat)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fallocate, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(fallocate)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(timerfd_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(timerfd_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(preadv)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(pwritev)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(rt_tgsigqueueinfo, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(rt_tgsigqueueinfo)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(recvmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(recvmmsg)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_adjtime)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(sendmmsg, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(sendmmsg)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_readv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(process_vm_readv)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_vm_writev, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(process_vm_writev)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(preadv2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(preadv2)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pwritev2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(pwritev2)>);
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(io_pgetevents)>);
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(pidfd_send_signal, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(pidfd_send_signal)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(pidfd_send_signal, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 10, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(process_madvise)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(process_madvise, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(6, 5, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(cachestat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(cachestat)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(cachestat, UnimplementedSyscallSafe);
|
||||
}
|
||||
if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(fchmodat2, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(fchmodat2)>);
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(fchmodat2, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace x32 {
|
||||
void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
RegisterCommon(Handler);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getuid32, getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgid32, getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getgid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(geteuid32, geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(geteuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getegid32, getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough0<SYSCALL_DEF(getegid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setreuid32, setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setreuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setregid32, setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setregid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getgroups32, getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(getgroups)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgroups32, setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(setgroups)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(fchown32, fchown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(fchown)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresuid32, setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setresuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresuid32, getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getresuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setresgid32, setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(setresgid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(getresgid32, getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough3<SYSCALL_DEF(getresgid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setuid32, setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setgid32, setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setgid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsuid32, setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setfsuid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(setfsgid32, setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough1<SYSCALL_DEF(setfsgid)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sendfile64, sendfile, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(sendfile)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_gettime64, clock_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_settime64, clock_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_adjtime64, clock_adjtime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_adjtime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_getres_time64, clock_getres, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(clock_getres)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(clock_nanosleep_time64, clock_nanosleep, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(clock_nanosleep)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_gettime64, timer_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(timer_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timer_settime64, timer_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(timer_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_gettime64, timerfd_gettime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(timerfd_gettime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(timerfd_settime64, timerfd_settime, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(timerfd_settime)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(utimensat_time64, utimensat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(utimensat)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(ppoll_time64, ppoll, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(ppoll)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(io_pgetevents_time64, io_pgetevents, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(io_pgetevents)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedsend_time64, mq_timedsend, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mq_timedsend)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(mq_timedreceive_time64, mq_timedreceive, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough5<SYSCALL_DEF(mq_timedreceive)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(semtimedop_time64, semtimedop, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough4<SYSCALL_DEF(semtimedop)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(futex_time64, futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough6<SYSCALL_DEF(futex)>);
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL_FLAGS(sched_rr_get_interval_time64, sched_rr_get_interval, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
SyscallPassthrough2<SYSCALL_DEF(sched_rr_get_interval)>);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterSHM(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(_shmget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, key_t key, size_t size, int shmflg) -> uint64_t {
|
||||
uint64_t Result = shmget(key, size, shmflg);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
// XXX: shmid_ds is definitely not correct for 32-bit
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(_shmctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int shmid, int cmd, struct shmid_ds *buf) -> uint64_t {
|
||||
uint64_t Result = ::shmctl(shmid, cmd, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterSched(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_yield, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::sched_yield();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int which, int who) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(getpriority), which, who);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpriority, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int which, int who, int prio) -> uint64_t {
|
||||
uint64_t Result = ::setpriority(which, who, prio);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, const struct sched_param *param) -> uint64_t {
|
||||
uint64_t Result = ::sched_setparam(pid, param);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getparam, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct sched_param *param) -> uint64_t {
|
||||
uint64_t Result = ::sched_getparam(pid, param);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int policy, const struct sched_param *param) -> uint64_t {
|
||||
uint64_t Result = ::sched_setscheduler(pid, policy, param);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getscheduler, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid) -> uint64_t {
|
||||
uint64_t Result = ::sched_getscheduler(pid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_max, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int policy) -> uint64_t {
|
||||
uint64_t Result = ::sched_get_priority_max(policy);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_get_priority_min, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int policy) -> uint64_t {
|
||||
uint64_t Result = ::sched_get_priority_min(policy);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(sched_setaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NOSIDEEFFECTS,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, size_t cpusetsize, const unsigned long *mask) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(sched_setaffinity), pid, cpusetsize, mask);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(sched_getaffinity, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, size_t cpusetsize, unsigned char *mask) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(sched_getaffinity), pid, cpusetsize, mask);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_setattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct sched_attr *attr, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(sched_setattr), pid, attr, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sched_getattr, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(sched_getattr), pid, attr, size, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
#include <FEXHeaderUtils/Syscalls.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(semget, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, key_t key, int nsems, int semflg) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(semget), key, nsems, semflg);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterSocket(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(socket, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int domain, int type, int protocol) -> uint64_t {
|
||||
uint64_t Result = ::socket(domain, type, protocol);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(connect, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, const struct sockaddr *addr, socklen_t addrlen) -> uint64_t {
|
||||
uint64_t Result = ::connect(sockfd, addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(accept4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) -> uint64_t {
|
||||
uint64_t Result = ::accept4(sockfd, addr, addrlen, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(sendto, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) -> uint64_t {
|
||||
uint64_t Result = ::sendto(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(recvfrom, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) -> uint64_t {
|
||||
uint64_t Result = ::recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(shutdown, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int how) -> uint64_t {
|
||||
uint64_t Result = ::shutdown(sockfd, how);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(bind, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, const struct sockaddr *addr, socklen_t addrlen) -> uint64_t {
|
||||
uint64_t Result = ::bind(sockfd, addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(listen, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int backlog) -> uint64_t {
|
||||
uint64_t Result = ::listen(sockfd, backlog);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsockname, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct sockaddr *addr, socklen_t *addrlen) -> uint64_t {
|
||||
uint64_t Result = ::getsockname(sockfd, addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpeername, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct sockaddr *addr, socklen_t *addrlen) -> uint64_t {
|
||||
uint64_t Result = ::getpeername(sockfd, addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(socketpair, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int domain, int type, int protocol, int sv[2]) -> uint64_t {
|
||||
uint64_t Result = ::socketpair(domain, type, protocol, sv);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,10 @@ namespace FEX::HLE {
|
||||
auto CTX = Handler->CTX;
|
||||
auto Thread = Handler->Thread;
|
||||
FEXCore::Allocator::free(Handler);
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread);
|
||||
CTX->ExecutionThread(Thread);
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->TM.DestroyThread(Thread);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -220,10 +223,14 @@ namespace FEX::HLE {
|
||||
FEX::HLE::_SyscallHandler->TM.TrackThread(Thread);
|
||||
}
|
||||
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread);
|
||||
|
||||
// Start exuting the thread directly
|
||||
// Our host clone starts in a new stack space, so it can't return back to the JIT space
|
||||
CTX->ExecutionThread(Thread);
|
||||
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread);
|
||||
|
||||
// The rest of the context remains as is and the thread will continue executing
|
||||
return Thread->StatusCode;
|
||||
}
|
||||
@@ -356,12 +363,6 @@ namespace FEX::HLE {
|
||||
FEX_UNREACHABLE;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getpid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(fork, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
return ForkGuest(Frame->Thread, Frame, 0, 0, 0, 0, 0, 0);
|
||||
});
|
||||
@@ -370,6 +371,12 @@ namespace FEX::HLE {
|
||||
return ForkGuest(Frame->Thread, Frame, CLONE_VFORK, 0, 0, 0, 0, 0);
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(getpgrp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getpgrp();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(clone3, SyscallFlags::DEFAULT, ([](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::kernel_clone3_args *cl_args, size_t size) -> uint64_t {
|
||||
FEX::HLE::clone3_args args{};
|
||||
args.Type = TypeOfClone::TYPE_CLONE3;
|
||||
@@ -403,130 +410,6 @@ namespace FEX::HLE {
|
||||
return 0;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(kill, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int sig) -> uint64_t {
|
||||
uint64_t Result = ::kill(pid, sig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tkill, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame, int tid, int sig) -> uint64_t {
|
||||
// Can't actually use tgkill here, kernel rejects tgkill of tgid == 0
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(tkill), tid, sig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(tgkill, SyscallFlags::DEFAULT, [](FEXCore::Core::CpuStateFrame *Frame, int tgid, int tid, int sig) -> uint64_t {
|
||||
uint64_t Result = FHU::Syscalls::tgkill(tgid, tid, sig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getuid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getgid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t uid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setuid), uid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, gid_t gid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setgid), gid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(geteuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::geteuid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getegid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getegid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getppid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getppid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpgrp, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getpgrp();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::setsid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setreuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t ruid, uid_t euid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setreuid), ruid, euid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setregid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, gid_t rgid, gid_t egid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setregid), rgid, egid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int size, gid_t list[]) -> uint64_t {
|
||||
uint64_t Result = ::getgroups(size, list);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setgroups, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, size_t size, const gid_t *list) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setgroups), size, list);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t ruid, uid_t euid, uid_t suid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setresuid), ruid, euid, suid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t *ruid, uid_t *euid, uid_t *suid) -> uint64_t {
|
||||
uint64_t Result = ::getresuid(ruid, euid, suid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, gid_t rgid, gid_t egid, gid_t sgid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(setresgid), rgid, egid, sgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getresgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, gid_t *rgid, gid_t *egid, gid_t *sgid) -> uint64_t {
|
||||
uint64_t Result = ::getresgid(rgid, egid, sgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(personality, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint64_t persona) -> uint64_t {
|
||||
uint64_t Result = ::personality(persona);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(prctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) -> uint64_t {
|
||||
uint64_t Result{};
|
||||
@@ -610,20 +493,14 @@ namespace FEX::HLE {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(gettid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = FHU::Syscalls::gettid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(set_tid_address, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(set_tid_address, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int *tidptr) -> uint64_t {
|
||||
auto Thread = Frame->Thread;
|
||||
Thread->ThreadManager.clear_child_tid = tidptr;
|
||||
return Thread->ThreadManager.GetTID();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(exit_group, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(exit_group, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY | SyscallFlags::NORETURN,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int status) -> uint64_t {
|
||||
|
||||
// Save telemetry if we're exiting.
|
||||
@@ -633,64 +510,5 @@ namespace FEX::HLE {
|
||||
// This will never be reached
|
||||
std::terminate();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(prlimit_64, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(prlimit_64), pid, resource, new_limit, old_limit);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, pid_t pgid) -> uint64_t {
|
||||
uint64_t Result = ::setpgid(pid, pgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getpgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid) -> uint64_t {
|
||||
uint64_t Result = ::getpgid(pid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsuid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t fsuid) -> uint64_t {
|
||||
uint64_t Result = ::setfsuid(fsuid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setfsgid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uid_t fsgid) -> uint64_t {
|
||||
uint64_t Result = ::setfsgid(fsgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(getsid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid) -> uint64_t {
|
||||
uint64_t Result = ::getsid(pid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(unshare, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t {
|
||||
uint64_t Result = ::unshare(flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(setns, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int fd, int nstype) -> uint64_t {
|
||||
uint64_t Result = ::setns(fd, nstype);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 16, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(futex_waitv, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, void *waiters, uint32_t nr_futexes, uint32_t flags, struct timespec *timeout, clockid_t clockid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(futex_waitv), waiters, nr_futexes, flags, timeout, clockid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL(futex_waitv, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-shared
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Syscalls.h"
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX::HLE {
|
||||
void RegisterTime(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(pause, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::pause();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,21 +24,15 @@ namespace FEX::HLE {
|
||||
void RegisterTimer(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(alarm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(alarm, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, unsigned int seconds) -> uint64_t {
|
||||
uint64_t Result = ::alarm(seconds);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_getoverrun, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_getoverrun), timerid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_PASS_FLAGS(timer_delete, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_delete), timerid);
|
||||
REGISTER_SYSCALL_IMPL_FLAGS(pause, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::pause();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "LinuxSyscalls/Utils/Threads.h"
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
|
||||
#include <FEXCore/Core/Context.h>
|
||||
#include <FEXCore/Utils/Threads.h>
|
||||
@@ -12,33 +13,53 @@ namespace FEX::LinuxEmulation::Threads {
|
||||
void *Ptr;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
struct DeadStackPoolItem {
|
||||
void *Ptr;
|
||||
size_t Size;
|
||||
bool ReadyToBeReaped;
|
||||
};
|
||||
|
||||
std::mutex DeadStackPoolMutex{};
|
||||
std::mutex LiveStackPoolMutex{};
|
||||
|
||||
static fextl::deque<StackPoolItem> DeadStackPool{};
|
||||
static fextl::deque<DeadStackPoolItem> DeadStackPool{};
|
||||
static fextl::deque<StackPoolItem> LiveStackPool{};
|
||||
|
||||
void *AllocateStackObject() {
|
||||
std::lock_guard lk{DeadStackPoolMutex};
|
||||
if (DeadStackPool.size() == 0) {
|
||||
// Nothing in the pool, just allocate
|
||||
return FEXCore::Allocator::mmap(nullptr, FEX::LinuxEmulation::Threads::STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
// Keep the first item in the stack pool
|
||||
auto Result = DeadStackPool.front().Ptr;
|
||||
DeadStackPool.pop_front();
|
||||
void *Ptr{};
|
||||
|
||||
// Erase the rest as a garbage collection step
|
||||
for (auto &Item : DeadStackPool) {
|
||||
FEXCore::Allocator::munmap(Item.Ptr, Item.Size);
|
||||
for (auto it = DeadStackPool.begin(); it != DeadStackPool.end();) {
|
||||
auto Ready = std::atomic_ref<bool>(it->ReadyToBeReaped);
|
||||
bool ReadyToBeReaped = Ready.load();
|
||||
if (Ptr == nullptr && ReadyToBeReaped) {
|
||||
Ptr = it->Ptr;
|
||||
it = DeadStackPool.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ReadyToBeReaped) {
|
||||
FEXCore::Allocator::munmap(it->Ptr, it->Size);
|
||||
it = DeadStackPool.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
return Result;
|
||||
|
||||
if (Ptr == nullptr) {
|
||||
Ptr = FEXCore::Allocator::mmap(nullptr, FEX::LinuxEmulation::Threads::STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
void AddStackToDeadPool(void *Ptr) {
|
||||
bool *AddStackToDeadPool(void *Ptr) {
|
||||
std::lock_guard lk{DeadStackPoolMutex};
|
||||
DeadStackPool.emplace_back(StackPoolItem{Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE});
|
||||
auto &it = DeadStackPool.emplace_back(DeadStackPoolItem{Ptr, FEX::LinuxEmulation::Threads::STACK_SIZE, false});
|
||||
return &it.ReadyToBeReaped;
|
||||
}
|
||||
|
||||
void AddStackToLivePool(void *Ptr) {
|
||||
@@ -61,6 +82,31 @@ namespace FEX::LinuxEmulation::Threads {
|
||||
AddStackToDeadPool(Ptr);
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void DeallocateStackObjectAndExit(void *Ptr, int Status) {
|
||||
RemoveStackFromLivePool(Ptr);
|
||||
auto ReadyToBeReaped = AddStackToDeadPool(Ptr);
|
||||
*ReadyToBeReaped = true;
|
||||
|
||||
#ifdef _M_ARM_64
|
||||
__asm volatile(
|
||||
"mov x8, %[SyscallNum];"
|
||||
"mov w0, %w[Result];"
|
||||
"svc #0;"
|
||||
:: [SyscallNum] "i" (SYSCALL_DEF(exit))
|
||||
, [Result] "r" (Status)
|
||||
: "memory", "x0", "x8");
|
||||
#else
|
||||
__asm volatile(
|
||||
"mov %[Result], %%edi;"
|
||||
"syscall;"
|
||||
:: "a" (SYSCALL_DEF(exit))
|
||||
, [Result] "r" (Status)
|
||||
: "memory", "rdi");
|
||||
#endif
|
||||
FEX_UNREACHABLE;
|
||||
}
|
||||
|
||||
namespace PThreads {
|
||||
void *InitializeThread(void *Ptr);
|
||||
|
||||
@@ -154,7 +200,7 @@ namespace FEX::LinuxEmulation::Threads {
|
||||
|
||||
auto ClearStackPool = [&](auto &StackPool) {
|
||||
for (auto it = StackPool.begin(); it != StackPool.end(); ) {
|
||||
StackPoolItem &Item = *it;
|
||||
auto &Item = *it;
|
||||
uintptr_t ItemStack = reinterpret_cast<uintptr_t>(Item.Ptr);
|
||||
if (ItemStack <= StackLocation && (ItemStack + Item.Size) > StackLocation) {
|
||||
// This is our stack item, skip it
|
||||
|
||||
@@ -20,8 +20,10 @@ namespace FEX::LinuxEmulation::Threads {
|
||||
* Will not free the memory immediately, instead saving for reuse temporarily to solve race conditions on stack usage while stack tears down.
|
||||
*
|
||||
* @param Ptr The stack base from `AllocateStackObject`
|
||||
* @param Status The status to pass to the exit syscall.
|
||||
*/
|
||||
void DeallocateStackObject(void *Ptr);
|
||||
[[noreturn]]
|
||||
void DeallocateStackObjectAndExit(void *Ptr, int Status);
|
||||
|
||||
/**
|
||||
* @brief Registers thread creation handlers with FEXCore.
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace FEX::HLE::x32 {
|
||||
};
|
||||
|
||||
void RegisterFD(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X32(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t {
|
||||
uint64_t Result = ::poll(fds, nfds, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -292,17 +292,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(ppoll_time64, ppoll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, struct timespec *timeout_ts, const uint64_t *sigmask, size_t sigsetsize) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(ppoll),
|
||||
fds,
|
||||
nfds,
|
||||
timeout_ts,
|
||||
sigmask,
|
||||
sigsetsize);
|
||||
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(_llseek, [](FEXCore::Core::CpuStateFrame *Frame, uint32_t fd, uint32_t offset_high, uint32_t offset_low, loff_t *result, uint32_t whence) -> uint64_t {
|
||||
uint64_t Offset = offset_high;
|
||||
Offset <<= 32;
|
||||
@@ -326,17 +315,12 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(chown32, chown, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X32(chown32, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::chown(pathname, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(fchown32, fchown, [](FEXCore::Core::CpuStateFrame *Frame, int fd, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::fchown(fd, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(lchown32, lchown, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X32(lchown32, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, uid_t owner, gid_t group) -> uint64_t {
|
||||
uint64_t Result = ::lchown(pathname, owner, group);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -740,16 +724,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(timerfd_settime64, timerfd_settime, [](FEXCore::Core::CpuStateFrame *Frame, int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) -> uint64_t {
|
||||
uint64_t Result = ::timerfd_settime(fd, flags, new_value, old_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(timerfd_gettime64, timerfd_gettime, [](FEXCore::Core::CpuStateFrame *Frame, int fd, struct itimerspec *curr_value) -> uint64_t {
|
||||
uint64_t Result = ::timerfd_gettime(fd, curr_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(timerfd_settime, [](FEXCore::Core::CpuStateFrame *Frame,
|
||||
int fd,
|
||||
int flags,
|
||||
@@ -896,14 +870,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(sendfile64, sendfile, [](FEXCore::Core::CpuStateFrame *Frame, int out_fd, int in_fd, off_t *offset, compat_size_t count) -> uint64_t {
|
||||
// Linux definition for this is a bit confusing
|
||||
// Defines offset as compat_loff_t* but loads loff_t worth of data
|
||||
// count is defined as compat_size_t still
|
||||
uint64_t Result = ::sendfile(out_fd, in_fd, offset, count);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(pread_64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, uint32_t count, uint32_t offset_low, uint32_t offset_high) -> uint64_t {
|
||||
uint64_t Offset = offset_high;
|
||||
Offset <<= 32;
|
||||
|
||||
@@ -40,17 +40,5 @@ namespace FEX::HLE::x32 {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout_ptr, usig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS(io_pgetevents_time64,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame,
|
||||
aio_context_t ctx_id,
|
||||
long min_nr,
|
||||
long nr,
|
||||
struct io_event *events,
|
||||
struct timespec *timeout,
|
||||
const struct io_sigset *usig) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout, usig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -45,16 +45,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(mq_timedsend_time64, mq_timedsend, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedsend), mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(mq_timedreceive_time64, mq_timedreceive, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedreceive), mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(mq_open, [](FEXCore::Core::CpuStateFrame *Frame, const char *name, int oflag, mode_t mode, compat_ptr<FEX::HLE::x32::mq_attr32> attr) -> uint64_t {
|
||||
mq_attr HostAttr{};
|
||||
mq_attr *HostAttr_p{};
|
||||
|
||||
@@ -29,10 +29,5 @@ namespace FEX::HLE::x32 {
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS(sched_rr_get_interval_time64, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::sched_rr_get_interval(pid, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -385,11 +385,6 @@ namespace FEX::HLE::x32 {
|
||||
void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X32(ipc, _ipc);
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(semtimedop_time64, semtimedop, [](FEXCore::Core::CpuStateFrame *Frame, int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(semtimedop), semid, sops, nsops, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(semctl, [](FEXCore::Core::CpuStateFrame *Frame, int semid, int semnum, int cmd, semun_32 *semun) -> uint64_t {
|
||||
uint64_t Result{};
|
||||
bool IPC64 = cmd & 0x100;
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace FEX::HLE::x32 {
|
||||
REGISTER_SYSCALL_IMPL_X32(pidfd_send_signal, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS(rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int sig, compat_ptr<FEXCore::x86::siginfo_t> info) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X32(rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int sig, compat_ptr<FEXCore::x86::siginfo_t> info) -> uint64_t {
|
||||
siginfo_t info64{};
|
||||
siginfo_t *info64_p{};
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS(rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t tgid, pid_t tid, int sig, compat_ptr<FEXCore::x86::siginfo_t> info) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X32(rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t tgid, pid_t tid, int sig, compat_ptr<FEXCore::x86::siginfo_t> info) -> uint64_t {
|
||||
siginfo_t info64{};
|
||||
siginfo_t *info64_p{};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace FEX::HLE::x32 {
|
||||
void RegisterThread(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterTime(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterTimer(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterPassthrough(FEX::HLE::SyscallHandler *Handler);
|
||||
|
||||
x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator)
|
||||
: SyscallHandler{ctx, _SignalDelegation}, AllocHandler{std::move(Allocator)} {
|
||||
@@ -67,18 +68,9 @@ namespace FEX::HLE::x32 {
|
||||
FEX::HLE::RegisterFS(this);
|
||||
FEX::HLE::RegisterInfo(this);
|
||||
FEX::HLE::RegisterIO(this);
|
||||
FEX::HLE::RegisterIOUring(this);
|
||||
FEX::HLE::RegisterKey(this);
|
||||
FEX::HLE::RegisterMemory(this);
|
||||
FEX::HLE::RegisterMsg(this);
|
||||
FEX::HLE::RegisterNamespace(this);
|
||||
FEX::HLE::RegisterSched(this);
|
||||
FEX::HLE::RegisterSemaphore(this);
|
||||
FEX::HLE::RegisterSHM(this);
|
||||
FEX::HLE::RegisterSignals(this);
|
||||
FEX::HLE::RegisterSocket(this);
|
||||
FEX::HLE::RegisterThread(this);
|
||||
FEX::HLE::RegisterTime(this);
|
||||
FEX::HLE::RegisterTimer(this);
|
||||
FEX::HLE::RegisterNotImplemented(this);
|
||||
FEX::HLE::RegisterStubs(this);
|
||||
@@ -100,6 +92,7 @@ namespace FEX::HLE::x32 {
|
||||
FEX::HLE::x32::RegisterThread(this);
|
||||
FEX::HLE::x32::RegisterTime(this);
|
||||
FEX::HLE::x32::RegisterTimer(this);
|
||||
FEX::HLE::x32::RegisterPassthrough(this);
|
||||
|
||||
FEX::HLE::x32::InitializeStaticIoctlHandlers();
|
||||
|
||||
|
||||
@@ -214,86 +214,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getgroups32, getgroups, [](FEXCore::Core::CpuStateFrame *Frame, int size, gid_t list[]) -> uint64_t {
|
||||
uint64_t Result = ::getgroups(size, list);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setgroups32, setgroups, [](FEXCore::Core::CpuStateFrame *Frame, size_t size, const gid_t *list) -> uint64_t {
|
||||
uint64_t Result = ::setgroups(size, list);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getuid32, getuid, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getuid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getgid32, getgid, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getgid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setuid32, setuid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t uid) -> uint64_t {
|
||||
uint64_t Result = ::setuid(uid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setgid32, setgid, [](FEXCore::Core::CpuStateFrame *Frame, gid_t gid) -> uint64_t {
|
||||
uint64_t Result = ::setgid(gid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(geteuid32, geteuid, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::geteuid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getegid32, getegid, [](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::getegid();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setfsuid32, setfsuid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t fsuid) -> uint64_t {
|
||||
uint64_t Result = ::setfsuid(fsuid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setfsgid32, setfsgid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t fsgid) -> uint64_t {
|
||||
uint64_t Result = ::setfsgid(fsgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setreuid32, setreuid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t ruid, uid_t euid) -> uint64_t {
|
||||
uint64_t Result = ::setreuid(ruid, euid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setresuid32, setresuid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t ruid, uid_t euid, uid_t suid) -> uint64_t {
|
||||
uint64_t Result = ::setresuid(ruid, euid, suid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getresuid32, getresuid, [](FEXCore::Core::CpuStateFrame *Frame, uid_t *ruid, uid_t *euid, uid_t *suid) -> uint64_t {
|
||||
uint64_t Result = ::getresuid(ruid, euid, suid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setresgid32, setresgid, [](FEXCore::Core::CpuStateFrame *Frame, gid_t rgid, gid_t egid, gid_t sgid) -> uint64_t {
|
||||
uint64_t Result = ::setresgid(rgid, egid, sgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(getresgid32, getresgid, [](FEXCore::Core::CpuStateFrame *Frame, gid_t *rgid, gid_t *egid, gid_t *sgid) -> uint64_t {
|
||||
uint64_t Result = ::getresgid(rgid, egid, sgid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(setregid32, setregid, [](FEXCore::Core::CpuStateFrame *Frame, gid_t rgid, gid_t egid) -> uint64_t {
|
||||
uint64_t Result = ::setregid(rgid, egid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(sigaltstack, [](FEXCore::Core::CpuStateFrame *Frame, const compat_ptr<stack_t32> ss, compat_ptr<stack_t32> old_ss) -> uint64_t {
|
||||
stack_t ss64{};
|
||||
stack_t old64{};
|
||||
@@ -421,16 +341,5 @@ namespace FEX::HLE::x32 {
|
||||
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(futex_time64, futex, [](FEXCore::Core::CpuStateFrame *Frame, int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, uint32_t val3) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(futex),
|
||||
uaddr,
|
||||
futex_op,
|
||||
val,
|
||||
timeout,
|
||||
uaddr2,
|
||||
val3);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -197,36 +197,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(clock_gettime64, clock_gettime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_gettime(clk_id, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(clock_adjtime64, clock_adjtime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, struct timex *buf) -> uint64_t {
|
||||
uint64_t Result = ::clock_adjtime(clk_id, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(clock_settime64, clock_settime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, const struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_settime(clockid, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(clock_getres_time64, clock_getres, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_getres(clk_id, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(clock_nanosleep_time64, clock_nanosleep, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain) -> uint64_t {
|
||||
uint64_t Result = ::clock_nanosleep(clockid, flags, request, remain);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(utimensat_time64, utimensat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const struct timespec times[2], int flags) -> uint64_t {
|
||||
uint64_t Result = ::utimensat(dirfd, pathname, times, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(utimes, [](FEXCore::Core::CpuStateFrame *Frame, const char *filename, const timeval32 times[2]) -> uint64_t {
|
||||
uint64_t Result = 0;
|
||||
if (times) {
|
||||
|
||||
@@ -54,16 +54,6 @@ namespace FEX::HLE::x32 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(timer_settime64, timer_settime, [](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, new_value, old_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32_PASS_MANUAL(timer_gettime64, timer_gettime, [](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid, struct itimerspec *curr_value) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(getitimer, [](FEXCore::Core::CpuStateFrame *Frame, int which, FEX::HLE::x32::itimerval32 *curr_value) -> uint64_t {
|
||||
itimerval val{};
|
||||
itimerval *val_p{};
|
||||
|
||||
@@ -29,12 +29,12 @@ $end_info$
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterFD(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(poll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, int timeout) -> uint64_t {
|
||||
uint64_t Result = ::poll(fds, nfds, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(select, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(select, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) -> uint64_t {
|
||||
uint64_t Result = ::select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -58,21 +58,11 @@ namespace FEX::HLE::x64 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(futimesat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const struct timeval times[2]) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(futimesat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const struct timeval times[2]) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(futimesat), dirfd, pathname, times);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(utimensat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, const struct timespec times[2], int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(utimensat), dirfd, pathname, times, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pselect6, [](FEXCore::Core::CpuStateFrame *Frame, int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const void *sigmaskpack) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pselect6), nfds, readfds, writefds, exceptfds, timeout, sigmaskpack);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(stat, [](FEXCore::Core::CpuStateFrame *Frame, const char *pathname, FEX::HLE::x64::guest_stat *buf) -> uint64_t {
|
||||
struct stat host_stat;
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Stat(pathname, &host_stat);
|
||||
@@ -100,21 +90,6 @@ namespace FEX::HLE::x64 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(readv, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec *iov, int iovcnt) -> uint64_t {
|
||||
uint64_t Result = ::readv(fd, iov, iovcnt);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(writev, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec *iov, int iovcnt) -> uint64_t {
|
||||
uint64_t Result = ::writev(fd, iov, iovcnt);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(readahead, [](FEXCore::Core::CpuStateFrame *Frame, int fd, off64_t offset, size_t count) -> uint64_t {
|
||||
uint64_t Result = ::readahead(fd, offset, count);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(newfstatat, [](FEXCore::Core::CpuStateFrame *Frame, int dirfd, const char *pathname, FEX::HLE::x64::guest_stat *buf, int flag) -> uint64_t {
|
||||
struct stat host_stat;
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.NewFSStatAt(dirfd, pathname, &host_stat, flag);
|
||||
@@ -124,102 +99,11 @@ namespace FEX::HLE::x64 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(vmsplice, [](FEXCore::Core::CpuStateFrame *Frame, int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::vmsplice(fd, iov, nr_segs, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(preadv, [](FEXCore::Core::CpuStateFrame *Frame,
|
||||
int fd,
|
||||
const struct iovec *iov,
|
||||
uint64_t vlen,
|
||||
uint64_t pos_l,
|
||||
uint64_t pos_h) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(preadv), fd, iov, vlen, pos_l, pos_h);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pwritev, [](FEXCore::Core::CpuStateFrame *Frame,
|
||||
int fd,
|
||||
const struct iovec *iov,
|
||||
uint64_t vlen,
|
||||
uint64_t pos_l,
|
||||
uint64_t pos_h) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pwritev), fd, iov, vlen, pos_l, pos_h);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(preadv2, [](FEXCore::Core::CpuStateFrame *Frame,
|
||||
int fd,
|
||||
const struct iovec *iov,
|
||||
uint64_t vlen,
|
||||
uint64_t pos_l,
|
||||
uint64_t pos_h,
|
||||
int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(preadv2), fd, iov, vlen, pos_l, pos_h, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pwritev2, [](FEXCore::Core::CpuStateFrame *Frame,
|
||||
int fd,
|
||||
const struct iovec *iov,
|
||||
uint64_t vlen,
|
||||
uint64_t pos_l,
|
||||
uint64_t pos_h,
|
||||
int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pwritev2), fd, iov, vlen, pos_l, pos_h, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pread_64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, size_t count, off_t offset) -> uint64_t {
|
||||
uint64_t Result = ::pread64(fd, buf, count, offset);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pwrite_64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *buf, size_t count, off_t offset) -> uint64_t {
|
||||
uint64_t Result = ::pwrite64(fd, buf, count, offset);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(process_vm_readv, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t {
|
||||
uint64_t Result = ::process_vm_readv(pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(process_vm_writev, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags) -> uint64_t {
|
||||
uint64_t Result = ::process_vm_writev(pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(ppoll, [](FEXCore::Core::CpuStateFrame *Frame, struct pollfd *fds, nfds_t nfds, struct timespec *timeout_ts, const uint64_t *sigmask, size_t sigsetsize) -> uint64_t {
|
||||
// glibc wrapper doesn't allow timeout_ts to be modified like the kernel does
|
||||
int Result = ::syscall(SYSCALL_DEF(ppoll), fds, nfds, timeout_ts, sigmask, sigsetsize);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(getdents, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *dirp, uint32_t count) -> uint64_t {
|
||||
return GetDentsEmulation<false>(fd, reinterpret_cast<FEX::HLE::x64::linux_dirent*>(dirp), count);
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(getdents64, [](FEXCore::Core::CpuStateFrame *Frame, int fd, void *dirp, uint32_t count) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(getdents64),
|
||||
static_cast<uint64_t>(fd),
|
||||
reinterpret_cast<uint64_t>(dirp),
|
||||
static_cast<uint64_t>(count));
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sendfile, [](FEXCore::Core::CpuStateFrame *Frame, int out_fd, int in_fd, off_t *offset, size_t count) -> uint64_t {
|
||||
uint64_t Result = ::sendfile(out_fd, in_fd, offset, count);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(dup, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd) -> uint64_t {
|
||||
uint64_t Result = ::dup(oldfd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(dup2, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd, int newfd) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(dup2, [](FEXCore::Core::CpuStateFrame *Frame, int oldfd, int newfd) -> uint64_t {
|
||||
uint64_t Result = ::dup2(oldfd, newfd);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -228,32 +112,5 @@ namespace FEX::HLE::x64 {
|
||||
uint64_t Result = FEX::HLE::_SyscallHandler->FM.Statfs(path, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(fstatfs, [](FEXCore::Core::CpuStateFrame *Frame, int fd, struct statfs *buf) -> uint64_t {
|
||||
uint64_t Result = ::fstatfs(fd, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sync_file_range, [](FEXCore::Core::CpuStateFrame *Frame, int fd, off64_t offset, off64_t nbytes, unsigned int flags) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(sync_file_range), fd, offset, nbytes, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(fallocate, [](FEXCore::Core::CpuStateFrame *Frame, int fd, int mode, off_t offset, off_t len) -> uint64_t {
|
||||
uint64_t Result = ::fallocate(fd, mode, offset, len);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(timerfd_settime, [](FEXCore::Core::CpuStateFrame *Frame, int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) -> uint64_t {
|
||||
// Flags don't need remapped
|
||||
uint64_t Result = ::timerfd_settime(fd, flags, new_value, old_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(timerfd_gettime, [](FEXCore::Core::CpuStateFrame *Frame, int fd, struct itimerspec *curr_value) -> uint64_t {
|
||||
uint64_t Result = ::timerfd_gettime(fd, curr_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-x86-64
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
|
||||
#include <linux/aio_abi.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct CpuStateFrame;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterIO(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(io_getevents, [](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_getevents), ctx_id, min_nr, nr, events, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(io_pgetevents, [](FEXCore::Core::CpuStateFrame *Frame, aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout, const struct io_sigset *usig) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(io_pgetevents), ctx_id, min_nr, nr, events, timeout, usig);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,28 +18,8 @@ namespace FEX::HLE::x64 {
|
||||
void RegisterInfo(FEX::HLE::SyscallHandler *Handler) {
|
||||
using namespace FEXCore::IR;
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sysinfo, [](FEXCore::Core::CpuStateFrame *Frame, struct sysinfo *info) -> uint64_t {
|
||||
uint64_t Result = ::sysinfo(info);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(getrusage, [](FEXCore::Core::CpuStateFrame *Frame, int who, struct rusage *usage) -> uint64_t {
|
||||
uint64_t Result = ::getrusage(who, usage);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(getrlimit, [](FEXCore::Core::CpuStateFrame *Frame, int resource, struct rlimit *rlim) -> uint64_t {
|
||||
uint64_t Result = ::getrlimit(resource, rlim);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(setrlimit, [](FEXCore::Core::CpuStateFrame *Frame, int resource, const struct rlimit *rlim) -> uint64_t {
|
||||
uint64_t Result = ::setrlimit(resource, rlim);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(6, 6, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(map_shadow_stack, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
REGISTER_SYSCALL_IMPL_X64_FLAGS(map_shadow_stack, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, uint64_t addr, uint64_t size, uint32_t flags) -> uint64_t {
|
||||
// Claim that shadow stack isn't supported.
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-x86-64
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct CpuStateFrame;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterIoctl(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(ioctl, [](FEXCore::Core::CpuStateFrame *Frame, int fd, uint64_t request, void *args) -> uint64_t {
|
||||
uint64_t Result = ::ioctl(fd, request, args);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -103,18 +103,6 @@ namespace FEX::HLE::x64 {
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(mlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int flags) -> uint64_t {
|
||||
uint64_t Result = ::mlockall(flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(munlockall, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame) -> uint64_t {
|
||||
uint64_t Result = ::munlockall();
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_FLAGS(_shmat, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int shmid, const void *shmaddr, int shmflg) -> uint64_t {
|
||||
uint64_t Result = reinterpret_cast<uint64_t>(shmat(shmid, shmaddr, shmflg));
|
||||
@@ -134,16 +122,5 @@ namespace FEX::HLE::x64 {
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 10, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(process_madvise, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pidfd, const struct iovec *iovec, size_t vlen, int advice, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(process_madvise), pidfd, iovec, vlen, advice, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(process_madvise, UnimplementedSyscallSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-x86-64
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Types.h"
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct CpuStateFrame;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterMsg(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(mq_timedsend, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedsend), mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(mq_timedreceive, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_timedreceive), mqdes, msg_ptr, msg_len, msg_prio, abs_timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(mq_open, [](FEXCore::Core::CpuStateFrame *Frame, const char *name, int oflag, mode_t mode, struct mq_attr *attr) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_open), name, oflag, mode, attr);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(mq_notify, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, const struct sigevent *sevp) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_notify), mqdes, sevp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(mq_getsetattr, [](FEXCore::Core::CpuStateFrame *Frame, FEX::HLE::mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(mq_getsetattr), mqdes, newattr, oldattr);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-x86-64
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct CpuStateFrame;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterSched(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sched_rr_get_interval, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::sched_rr_get_interval(pid, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,6 @@ ARG_TO_STR(FEX::HLE::x64::semun, "%lx")
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterSemaphore(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(semop, [](FEXCore::Core::CpuStateFrame *Frame, int semid, struct sembuf *sops, size_t nsops) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(semop), semid, sops, nsops);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(semtimedop, [](FEXCore::Core::CpuStateFrame *Frame, int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(semtimedop), semid, sops, nsops, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(semctl, [](FEXCore::Core::CpuStateFrame *Frame, int semid, int semnum, int cmd, FEX::HLE::x64::semun semun) -> uint64_t {
|
||||
uint64_t Result{};
|
||||
switch (cmd) {
|
||||
|
||||
@@ -31,26 +31,6 @@ namespace FEX::HLE::x64 {
|
||||
REGISTER_SYSCALL_IMPL_X64(rt_sigtimedwait, [](FEXCore::Core::CpuStateFrame *Frame, uint64_t *set, siginfo_t *info, const struct timespec* timeout, size_t sigsetsize) -> uint64_t {
|
||||
return FEX::HLE::_SyscallHandler->GetSignalDelegator()->GuestSigTimedWait(set, info, timeout, sigsetsize);
|
||||
});
|
||||
|
||||
if (Handler->IsHostKernelVersionAtLeast(5, 1, 0)) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(pidfd_send_signal, [](FEXCore::Core::CpuStateFrame *Frame, int pidfd, int sig, siginfo_t *info, unsigned int flags) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(pidfd_send_signal), pidfd, sig, info, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
else {
|
||||
REGISTER_SYSCALL_IMPL_X64(pidfd_send_signal, UnimplementedSyscallSafe);
|
||||
}
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(rt_sigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int sig, siginfo_t *info) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(rt_sigqueueinfo), pid, sig, info);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(rt_tgsigqueueinfo, [](FEXCore::Core::CpuStateFrame *Frame, pid_t tgid, pid_t tid, int sig, siginfo_t *info) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(rt_tgsigqueueinfo), tgid, tid, sig, info);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
$info$
|
||||
tags: LinuxSyscalls|syscalls-x86-64
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct CpuStateFrame;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterSocket(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(accept, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct sockaddr *addr, socklen_t *addrlen) -> uint64_t {
|
||||
uint64_t Result = ::accept(sockfd, addr, addrlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(recvmmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) -> uint64_t {
|
||||
uint64_t Result = ::recvmmsg(sockfd, msgvec, vlen, flags, timeout);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sendmmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct mmsghdr *msgvec, uint32_t vlen, int flags) -> uint64_t {
|
||||
uint64_t Result = ::sendmmsg(sockfd, msgvec, vlen, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(sendmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, const struct msghdr *msg, int flags) -> uint64_t {
|
||||
uint64_t Result = ::sendmsg(sockfd, msg, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(recvmsg, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, struct msghdr *msg, int flags) -> uint64_t {
|
||||
uint64_t Result = ::recvmsg(sockfd, msg, flags);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(setsockopt, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int level, int optname, const void *optval, socklen_t optlen) -> uint64_t {
|
||||
uint64_t Result = ::setsockopt(sockfd, level, optname, optval, optlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(getsockopt, [](FEXCore::Core::CpuStateFrame *Frame, int sockfd, int level, int optname, void *optval, socklen_t *optlen) -> uint64_t {
|
||||
uint64_t Result = ::getsockopt(sockfd, level, optname, optval, optlen);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,13 @@ namespace FEX::HLE::x64 {
|
||||
void RegisterEpoll(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterFD(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterInfo(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterIO(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterIoctl(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterMemory(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterMsg(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSched(FEX::HLE::SyscallHandler *Handler);
|
||||
void RegisterSocket(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} {
|
||||
@@ -54,18 +50,9 @@ namespace FEX::HLE::x64 {
|
||||
FEX::HLE::RegisterFS(this);
|
||||
FEX::HLE::RegisterInfo(this);
|
||||
FEX::HLE::RegisterIO(this);
|
||||
FEX::HLE::RegisterIOUring(this);
|
||||
FEX::HLE::RegisterKey(this);
|
||||
FEX::HLE::RegisterMemory(this);
|
||||
FEX::HLE::RegisterMsg(this);
|
||||
FEX::HLE::RegisterNamespace(this);
|
||||
FEX::HLE::RegisterSched(this);
|
||||
FEX::HLE::RegisterSemaphore(this);
|
||||
FEX::HLE::RegisterSHM(this);
|
||||
FEX::HLE::RegisterSignals(this);
|
||||
FEX::HLE::RegisterSocket(this);
|
||||
FEX::HLE::RegisterThread(this);
|
||||
FEX::HLE::RegisterTime(this);
|
||||
FEX::HLE::RegisterTimer(this);
|
||||
FEX::HLE::RegisterNotImplemented(this);
|
||||
FEX::HLE::RegisterStubs(this);
|
||||
@@ -74,17 +61,13 @@ namespace FEX::HLE::x64 {
|
||||
FEX::HLE::x64::RegisterEpoll(this);
|
||||
FEX::HLE::x64::RegisterFD(this);
|
||||
FEX::HLE::x64::RegisterInfo(this);
|
||||
FEX::HLE::x64::RegisterIO(this);
|
||||
FEX::HLE::x64::RegisterIoctl(this);
|
||||
FEX::HLE::x64::RegisterMemory(this);
|
||||
FEX::HLE::x64::RegisterMsg(this);
|
||||
FEX::HLE::x64::RegisterSched(this);
|
||||
FEX::HLE::x64::RegisterSocket(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
|
||||
|
||||
@@ -30,8 +30,6 @@ struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
#include "SyscallsEnum.h"
|
||||
|
||||
class x64SyscallHandler final : public FEX::HLE::SyscallHandler {
|
||||
public:
|
||||
x64SyscallHandler(FEXCore::Context::Context *ctx, FEX::HLE::SignalDelegator *_SignalDelegation);
|
||||
|
||||
@@ -6,6 +6,7 @@ $end_info$
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
///< Enum containing all x86-64 linux syscalls for the guest kernel version
|
||||
enum Syscalls_x64 {
|
||||
SYSCALL_x64_read = 0,
|
||||
@@ -479,4 +480,4 @@ enum Syscalls_x64 {
|
||||
SYSCALL_x64_futex_time64 = ~0,
|
||||
SYSCALL_x64_sched_rr_get_interval_time64 = ~0,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -57,40 +57,6 @@ namespace FEX::HLE::x64 {
|
||||
return CloneHandler(Frame, &args);
|
||||
}));
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(futex, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, uint32_t val3) -> uint64_t {
|
||||
uint64_t Result = syscall(SYSCALL_DEF(futex),
|
||||
uaddr,
|
||||
futex_op,
|
||||
val,
|
||||
timeout,
|
||||
uaddr2,
|
||||
val3);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_FLAGS(set_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, struct robust_list_head *head, size_t len) -> uint64_t {
|
||||
auto Thread = Frame->Thread;
|
||||
Thread->ThreadManager.robust_list_head = reinterpret_cast<uint64_t>(head);
|
||||
#ifdef TERMUX_BUILD
|
||||
// Termux/Android doesn't support `set_robust_list` syscall.
|
||||
// The seccomp filter that the OS installs explicitly blocks this syscall from working
|
||||
// glibc uses this syscall for tls and thread data so almost every application uses it
|
||||
// Return success since we have stored the pointer ourselves.
|
||||
return 0;
|
||||
#else
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(set_robust_list), head, len);
|
||||
SYSCALL_ERRNO();
|
||||
#endif
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(get_robust_list, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int pid, struct robust_list_head **head, size_t *len_ptr) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(get_robust_list), pid, head, len_ptr);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(sigaltstack, [](FEXCore::Core::CpuStateFrame *Frame, const stack_t *ss, stack_t *old_ss) -> uint64_t {
|
||||
return FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterGuestSigAltStack(ss, old_ss);
|
||||
});
|
||||
@@ -156,17 +122,5 @@ namespace FEX::HLE::x64 {
|
||||
auto* const* EnvpPtr = envp ? const_cast<char* const*>(Envp.data()) : nullptr;
|
||||
return FEX::HLE::ExecveHandler(pathname, ArgsPtr, EnvpPtr, AtArgs);
|
||||
}));
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(wait4, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, pid_t pid, int *wstatus, int options, struct rusage *rusage) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(wait4), pid, wstatus, options, rusage);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS_FLAGS(waitid, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
|
||||
[](FEXCore::Core::CpuStateFrame *Frame, int which, pid_t upid, siginfo_t *infop, int options, struct rusage *rusage) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(waitid), which, upid, infop, options, rusage);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -21,95 +21,21 @@ $end_info$
|
||||
|
||||
namespace FEX::HLE::x64 {
|
||||
void RegisterTime(FEX::HLE::SyscallHandler *Handler) {
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(time, [](FEXCore::Core::CpuStateFrame *Frame, time_t *tloc) -> uint64_t {
|
||||
using namespace FEXCore::IR;
|
||||
REGISTER_SYSCALL_IMPL_X64_FLAGS(time, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY, [](FEXCore::Core::CpuStateFrame *Frame, time_t *tloc) -> uint64_t {
|
||||
uint64_t Result = ::time(tloc);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(times, [](FEXCore::Core::CpuStateFrame *Frame, struct tms *buf) -> uint64_t {
|
||||
uint64_t Result = ::times(buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(utime, [](FEXCore::Core::CpuStateFrame *Frame, char* filename, const struct utimbuf* times) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(utime, [](FEXCore::Core::CpuStateFrame *Frame, char* filename, const struct utimbuf* times) -> uint64_t {
|
||||
uint64_t Result = ::utime(filename, times);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(gettimeofday, [](FEXCore::Core::CpuStateFrame *Frame, struct timeval *tv, struct timezone *tz) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(gettimeofday), tv, tz);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(nanosleep, [](FEXCore::Core::CpuStateFrame *Frame, const struct timespec *req, struct timespec *rem) -> uint64_t {
|
||||
uint64_t Result = ::nanosleep(req, rem);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(clock_gettime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_gettime(clk_id, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(clock_getres, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_getres(clk_id, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(clock_nanosleep, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(clock_nanosleep), clockid, flags, request, remain);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(clock_settime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, const struct timespec *tp) -> uint64_t {
|
||||
uint64_t Result = ::clock_settime(clockid, tp);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(settimeofday, [](FEXCore::Core::CpuStateFrame *Frame, const struct timeval *tv, const struct timezone *tz) -> uint64_t {
|
||||
uint64_t Result = ::settimeofday(tv, tz);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(utimes, [](FEXCore::Core::CpuStateFrame *Frame, const char *filename, const struct timeval times[2]) -> uint64_t {
|
||||
REGISTER_SYSCALL_IMPL_X64(utimes, [](FEXCore::Core::CpuStateFrame *Frame, const char *filename, const struct timeval times[2]) -> uint64_t {
|
||||
uint64_t Result = ::utimes(filename, times);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(getitimer, [](FEXCore::Core::CpuStateFrame *Frame, int which, struct itimerval *curr_value) -> uint64_t {
|
||||
uint64_t Result = ::getitimer(which, curr_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(setitimer, [](FEXCore::Core::CpuStateFrame *Frame, int which, const struct itimerval *new_value, struct itimerval *old_value) -> uint64_t {
|
||||
uint64_t Result = ::setitimer(which, new_value, old_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(timer_settime, [](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_settime), timerid, flags, new_value, old_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(timer_gettime, [](FEXCore::Core::CpuStateFrame *Frame, kernel_timer_t timerid, struct itimerspec *curr_value) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_gettime), timerid, curr_value);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(adjtimex, [](FEXCore::Core::CpuStateFrame *Frame, struct timex *buf) -> uint64_t {
|
||||
uint64_t Result = ::adjtimex(buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(clock_adjtime, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clk_id, struct timex *buf) -> uint64_t {
|
||||
uint64_t Result = ::clock_adjtime(clk_id, buf);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64_PASS(timer_create, [](FEXCore::Core::CpuStateFrame *Frame, clockid_t clockid, struct sigevent *sevp, kernel_timer_t *timerid) -> uint64_t {
|
||||
uint64_t Result = ::syscall(SYSCALL_DEF(timer_create), clockid, sevp, timerid);
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace FEX::VDSO {
|
||||
|
||||
using HandlerPtr = void(*)(void*);
|
||||
namespace x64 {
|
||||
static uint64_t SyscallRet(int Result) {
|
||||
static uint64_t SyscallRet(uint64_t Result) {
|
||||
if (Result == -1) {
|
||||
return -errno;
|
||||
}
|
||||
@@ -45,20 +45,20 @@ namespace FEX::VDSO {
|
||||
// glibc handlers
|
||||
namespace glibc {
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
time_t *a_0;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
int Result = ::time(args->a_0);
|
||||
uint64_t Result = ::time(args->a_0);
|
||||
args->rv = SyscallRet(Result);
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
struct timeval *tv;
|
||||
struct timezone *tz;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
int Result = ::gettimeofday(args->tv, args->tz);
|
||||
@@ -66,10 +66,10 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
int Result = ::clock_gettime(args->clk_id, args->tp);
|
||||
@@ -77,10 +77,10 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
int Result = ::clock_getres(args->clk_id, args->tp);
|
||||
@@ -88,10 +88,10 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
uint32_t *cpu;
|
||||
uint32_t *node;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
int Result = FHU::Syscalls::getcpu(args->cpu, args->node);
|
||||
@@ -102,7 +102,7 @@ namespace FEX::VDSO {
|
||||
namespace VDSO {
|
||||
// VDSO handlers
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
time_t *a_0;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
@@ -111,40 +111,40 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
struct timeval *tv;
|
||||
struct timezone *tz;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = VDSOHandlers::GetTimeOfDayPtr(args->tv, args->tz);
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = VDSOHandlers::ClockGetTimePtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = VDSOHandlers::ClockGetResPtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
uint32_t *cpu;
|
||||
uint32_t *node;
|
||||
uint64_t rv;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = VDSOHandlers::GetCPUPtr(args->cpu, args->node);
|
||||
@@ -168,7 +168,7 @@ namespace FEX::VDSO {
|
||||
|
||||
// glibc handlers
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<FEX::HLE::x32::old_time32_t> a_0;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
@@ -182,7 +182,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<FEX::HLE::x32::timeval32> tv;
|
||||
HLE::x32::compat_ptr<struct timezone> tz;
|
||||
int rv;
|
||||
@@ -203,7 +203,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<HLE::x32::timespec32> tp;
|
||||
int rv;
|
||||
@@ -219,7 +219,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_gettime64(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<struct timespec> tp;
|
||||
int rv;
|
||||
@@ -230,7 +230,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<HLE::x32::timespec32> tp;
|
||||
int rv;
|
||||
@@ -247,7 +247,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<uint32_t> cpu;
|
||||
HLE::x32::compat_ptr<uint32_t> node;
|
||||
int rv;
|
||||
@@ -265,7 +265,7 @@ namespace FEX::VDSO {
|
||||
|
||||
// VDSO handlers
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<FEX::HLE::x32::old_time32_t> a_0;
|
||||
int rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
@@ -279,7 +279,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<FEX::HLE::x32::timeval32> tv;
|
||||
HLE::x32::compat_ptr<struct timezone> tz;
|
||||
int rv;
|
||||
@@ -300,7 +300,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<HLE::x32::timespec32> tp;
|
||||
int rv;
|
||||
@@ -316,7 +316,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_gettime64(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<struct timespec> tp;
|
||||
int rv;
|
||||
@@ -326,7 +326,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
HLE::x32::compat_ptr<HLE::x32::timespec32> tp;
|
||||
int rv;
|
||||
@@ -343,7 +343,7 @@ namespace FEX::VDSO {
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct __attribute__((packed)) ArgsRV_t {
|
||||
HLE::x32::compat_ptr<uint32_t> cpu;
|
||||
HLE::x32::compat_ptr<uint32_t> node;
|
||||
int rv;
|
||||
|
||||
@@ -309,6 +309,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
return 1;
|
||||
}
|
||||
auto ParentThread = CTX->CreateThread(Loader.DefaultRIP(), Loader.GetStackPointer());
|
||||
SignalDelegation->RegisterTLSState(ParentThread);
|
||||
|
||||
if (!ParentThread) {
|
||||
return 1;
|
||||
@@ -324,6 +325,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
|
||||
SyscallHandler.reset();
|
||||
|
||||
SignalDelegation->UninstallTLSState(ParentThread);
|
||||
CTX->DestroyThread(ParentThread, true);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -366,6 +366,13 @@ void AnalysisAction::ParseInterface(clang::ASTContext& context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip pointers-to-structs passed through to the host in guest_layout.
|
||||
// This avoids pulling in member types that can't be processed.
|
||||
if (data.param_annotations[param_idx].is_passthrough &&
|
||||
param_type->isPointerType() && param_type->getPointeeType()->isStructureType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto check_struct_type = [&](const clang::Type* type) {
|
||||
if (type->isIncompleteType()) {
|
||||
throw report_error(type->getAsTagDecl()->getBeginLoc(), "Unannotated pointer with incomplete struct type; consider using an opaque_type annotation")
|
||||
|
||||
+11
-10
@@ -164,7 +164,7 @@ void GenerateThunkLibsAction::EmitLayoutWrappers(
|
||||
}
|
||||
|
||||
if (type->isEnumeralType()) {
|
||||
fmt::print(file, "template<>\nstruct guest_layout<{}> {{\n", struct_name);
|
||||
fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name);
|
||||
fmt::print(file, " using type = {}int{}_t;\n",
|
||||
type->isUnsignedIntegerOrEnumerationType() ? "u" : "",
|
||||
guest_abi.at(struct_name).get_if_simple_or_struct()->size_bits);
|
||||
@@ -182,12 +182,13 @@ void GenerateThunkLibsAction::EmitLayoutWrappers(
|
||||
}
|
||||
|
||||
// Guest layout definition
|
||||
fmt::print(file, "template<>\nstruct guest_layout<{}> {{\n", struct_name);
|
||||
// NOTE: uint64_t has lower alignment requirements on 32-bit than on 64-bit, so we require tightly packed structs
|
||||
// TODO: Now we must emit padding bytes explicitly, though!
|
||||
fmt::print(file, "template<>\nstruct __attribute__((packed)) guest_layout<{}> {{\n", struct_name);
|
||||
if (type_compat.at(type) == TypeCompatibility::Full) {
|
||||
fmt::print(file, " using type = {};\n", struct_name);
|
||||
} else {
|
||||
fmt::print(file, " struct type {{\n");
|
||||
// TODO: Insert any required padding bytes
|
||||
for (auto& member : guest_abi.at(struct_name).get_if_struct()->members) {
|
||||
fmt::print( file, " guest_layout<{}{}> {};\n",
|
||||
member.type_name,
|
||||
@@ -454,7 +455,7 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {
|
||||
}
|
||||
// Using trailing return type as it makes handling function pointer returns much easier
|
||||
file << ") -> " << data.return_type.getAsString() << " {\n";
|
||||
file << " struct {\n";
|
||||
file << " struct __attribute__((packed)) {\n";
|
||||
for (std::size_t idx = 0; idx < data.param_types.size(); ++idx) {
|
||||
auto& type = data.param_types[idx];
|
||||
file << " " << format_decl(type.getUnqualifiedType(), fmt::format("a_{}", idx)) << ";\n";
|
||||
@@ -587,11 +588,11 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {
|
||||
if (!param_type->isPointerType() || !param_type->getPointeeType()->isStructureType()) {
|
||||
continue;
|
||||
}
|
||||
auto type = param_type->getPointeeType();
|
||||
if (!types.at(context.getCanonicalType(type.getTypePtr())).assumed_compatible && type_compat.at(context.getCanonicalType(type.getTypePtr())) == TypeCompatibility::None) {
|
||||
// TODO: Factor in "assume_compatible_layout" annotations here
|
||||
// That annotation should cause the type to be treated as TypeCompatibility::Full
|
||||
if (!thunk.param_annotations[param_idx].is_passthrough) {
|
||||
if (!thunk.param_annotations[param_idx].is_passthrough) {
|
||||
auto type = param_type->getPointeeType();
|
||||
if (!types.at(context.getCanonicalType(type.getTypePtr())).assumed_compatible && type_compat.at(context.getCanonicalType(type.getTypePtr())) == TypeCompatibility::None) {
|
||||
// TODO: Factor in "assume_compatible_layout" annotations here
|
||||
// That annotation should cause the type to be treated as TypeCompatibility::Full
|
||||
throw report_error(thunk.decl->getLocation(), "Unsupported parameter type %0").AddTaggedVal(param_type);
|
||||
}
|
||||
}
|
||||
@@ -600,7 +601,7 @@ void GenerateThunkLibsAction::OnAnalysisComplete(clang::ASTContext& context) {
|
||||
// Packed argument structs used in fexfn_unpack_*
|
||||
auto GeneratePackedArgs = [&](const auto &function_name, const ThunkedFunction &thunk) -> std::string {
|
||||
std::string struct_name = "fexfn_packed_args_" + libname + "_" + function_name;
|
||||
file << "struct " << struct_name << " {\n";
|
||||
file << "struct __attribute__((packed)) " << struct_name << " {\n";
|
||||
|
||||
for (std::size_t idx = 0; idx < thunk.param_types.size(); ++idx) {
|
||||
fmt::print(file, " guest_layout<{}> a_{};\n", get_guest_type_name(thunk.param_types[idx]), idx);
|
||||
|
||||
@@ -232,9 +232,6 @@ if (BITNESS EQUAL 64)
|
||||
target_compile_definitions(libxcb-guest-deps INTERFACE -DXCB_VERSION_MINOR=${XCB_VERSION_MINOR})
|
||||
target_compile_definitions(libxcb-guest-deps INTERFACE -DXCB_VERSION_PATCH=${XCB_VERSION_PATCH})
|
||||
|
||||
generate(libwayland-client ${CMAKE_CURRENT_SOURCE_DIR}/../libwayland-client/libwayland-client_interface.cpp)
|
||||
add_guest_lib(wayland-client "libwayland-client.so.0.20.0")
|
||||
|
||||
generate(libxcb-dri2 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri2/libxcb-dri2_interface.cpp)
|
||||
add_guest_lib(xcb-dri2 "libxcb-dri2.so.0")
|
||||
|
||||
@@ -268,6 +265,9 @@ if (BITNESS EQUAL 64)
|
||||
add_guest_lib(drm "libdrm.so.2")
|
||||
endif()
|
||||
|
||||
generate(libwayland-client ${CMAKE_CURRENT_SOURCE_DIR}/../libwayland-client/libwayland-client_interface.cpp)
|
||||
add_guest_lib(wayland-client "libwayland-client.so.0.20.0")
|
||||
|
||||
generate(libVDSO ${CMAKE_CURRENT_SOURCE_DIR}/../libVDSO/libVDSO_interface.cpp)
|
||||
add_guest_lib(VDSO "linux-vdso.so.1")
|
||||
# Can't use a stack protector because otherwise cross-compiling fails
|
||||
|
||||
@@ -163,9 +163,6 @@ foreach(GUEST_BITNESS IN LISTS BITNESS_LIST)
|
||||
target_compile_definitions(libxcb-${GUEST_BITNESS}-deps INTERFACE -DXCB_VERSION_MINOR=${XCB_VERSION_MINOR})
|
||||
target_compile_definitions(libxcb-${GUEST_BITNESS}-deps INTERFACE -DXCB_VERSION_PATCH=${XCB_VERSION_PATCH})
|
||||
|
||||
generate(libwayland-client ${CMAKE_CURRENT_SOURCE_DIR}/../libwayland-client/libwayland-client_interface.cpp ${GUEST_BITNESS})
|
||||
add_host_lib(wayland-client ${GUEST_BITNESS})
|
||||
|
||||
generate(libxcb-dri2 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri2/libxcb-dri2_interface.cpp ${GUEST_BITNESS})
|
||||
add_host_lib(xcb-dri2 ${GUEST_BITNESS})
|
||||
|
||||
@@ -203,6 +200,9 @@ set (BITNESS_LIST "32;64")
|
||||
foreach(GUEST_BITNESS IN LISTS BITNESS_LIST)
|
||||
generate(libfex_thunk_test ${CMAKE_CURRENT_SOURCE_DIR}/../libfex_thunk_test/libfex_thunk_test_interface.cpp ${GUEST_BITNESS})
|
||||
add_host_lib(fex_thunk_test ${GUEST_BITNESS})
|
||||
|
||||
generate(libwayland-client ${CMAKE_CURRENT_SOURCE_DIR}/../libwayland-client/libwayland-client_interface.cpp ${GUEST_BITNESS})
|
||||
add_host_lib(wayland-client ${GUEST_BITNESS})
|
||||
endforeach()
|
||||
|
||||
add_library(fex_thunk_test SHARED ../libfex_thunk_test/lib.cpp)
|
||||
|
||||
@@ -30,6 +30,12 @@ namespace FEXCore {
|
||||
__attribute__((weak))
|
||||
HostToGuestTrampolinePtr*
|
||||
FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr*, void* HostPacker);
|
||||
|
||||
__attribute__((weak))
|
||||
void* GetGuestStack();
|
||||
|
||||
__attribute__((weak))
|
||||
void MoveGuestStack(uintptr_t NewAddress);
|
||||
}
|
||||
|
||||
template<typename Fn>
|
||||
@@ -121,7 +127,7 @@ template<> inline constexpr bool has_compatible_data_layout<const void**> = true
|
||||
|
||||
// Placeholder type to indicate the given data is in guest-layout
|
||||
template<typename T>
|
||||
struct guest_layout {
|
||||
struct __attribute__((packed)) guest_layout {
|
||||
static_assert(!std::is_class_v<T>, "No guest layout defined for this non-opaque struct type. This may be a bug in the thunk generator.");
|
||||
static_assert(!std::is_union_v<T>, "No guest layout defined for this non-opaque union type. This may be a bug in the thunk generator.");
|
||||
static_assert(!std::is_enum_v<T>, "No guest layout defined for this enum type. This is a bug in the thunk generator.");
|
||||
@@ -161,6 +167,14 @@ struct guest_layout<T*> {
|
||||
const guest_layout<T>* get_pointer() const {
|
||||
return reinterpret_cast<const guest_layout<T>*>(uintptr_t { data });
|
||||
}
|
||||
|
||||
T* force_get_host_pointer() {
|
||||
return reinterpret_cast<T*>(uintptr_t { data });
|
||||
}
|
||||
|
||||
const T* force_get_host_pointer() const {
|
||||
return reinterpret_cast<const T*>(uintptr_t { data });
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -447,16 +461,53 @@ auto Projection(guest_layout<T>& data) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IS_32BIT_THUNK
|
||||
/**
|
||||
* Helper class to manage guest stack memory from a host function.
|
||||
*
|
||||
* The current guest stack position is saved upon construction and bumped
|
||||
* for each object construction. Upon destruction, the old guest stack is
|
||||
* restored.
|
||||
*/
|
||||
class GuestStackBumpAllocator final {
|
||||
uintptr_t Top = reinterpret_cast<uintptr_t>(FEXCore::GetGuestStack());
|
||||
uintptr_t Next = Top;
|
||||
|
||||
public:
|
||||
~GuestStackBumpAllocator() {
|
||||
FEXCore::MoveGuestStack(Top);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T* New(Args&&... args) {
|
||||
Next -= sizeof(T);
|
||||
Next &= ~uintptr_t { alignof(T) - 1 };
|
||||
FEXCore::MoveGuestStack(Next);
|
||||
return new (reinterpret_cast<void*>(Next)) T {
|
||||
std::forward<Args>(args)...
|
||||
};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Result, typename... Args>
|
||||
struct CallbackUnpack<Result(Args...)> {
|
||||
static Result CallGuestPtr(Args... args) {
|
||||
GuestcallInfo *guestcall;
|
||||
LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(guestcall);
|
||||
|
||||
#ifndef IS_32BIT_THUNK
|
||||
PackedArguments<Result, guest_layout<Args>...> packed_args = {
|
||||
to_guest(to_host_layout(args))...
|
||||
};
|
||||
#else
|
||||
GuestStackBumpAllocator GuestStack;
|
||||
auto& packed_args = *GuestStack.New<PackedArguments<Result, guest_layout<Args>...>>(
|
||||
to_guest(to_host_layout(args))...
|
||||
);
|
||||
#endif
|
||||
guestcall->CallCallback(guestcall->GuestUnpacker, guestcall->GuestTarget, &packed_args);
|
||||
|
||||
if constexpr (!std::is_void_v<Result>) {
|
||||
return packed_args.rv;
|
||||
}
|
||||
|
||||
@@ -5,45 +5,45 @@
|
||||
#include <utility>
|
||||
|
||||
template<typename Result, typename... Args>
|
||||
struct PackedArguments;
|
||||
struct __attribute__((packed)) PackedArguments;
|
||||
|
||||
template<typename R>
|
||||
struct PackedArguments<R> { R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R> { R rv; };
|
||||
template<typename R, typename A0>
|
||||
struct PackedArguments<R, A0> { A0 a0; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0> { A0 a0; R rv; };
|
||||
template<typename R, typename A0, typename A1>
|
||||
struct PackedArguments<R, A0, A1> { A0 a0; A1 a1; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1> { A0 a0; A1 a1; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2>
|
||||
struct PackedArguments<R, A0, A1, A2> { A0 a0; A1 a1; A2 a2; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2> { A0 a0; A1 a1; A2 a2; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3>
|
||||
struct PackedArguments<R, A0, A1, A2, A3> { A0 a0; A1 a1; A2 a2; A3 a3; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3> { A0 a0; A1 a1; A2 a2; A3 a3; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; R rv; };
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; R rv; };
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; R rv; };
|
||||
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9,
|
||||
typename A10, typename A11, typename A12, typename A13, typename A14, typename A15, typename A16, typename A17, typename A18, typename A19,
|
||||
typename A20, typename A21, typename A22>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
A10, A11, A12, A13, A14, A15, A16, A17, A18, A19,
|
||||
A20, A21, A22> {
|
||||
A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9;
|
||||
@@ -54,7 +54,7 @@ struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
template<typename R, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9,
|
||||
typename A10, typename A11, typename A12, typename A13, typename A14, typename A15, typename A16, typename A17, typename A18, typename A19,
|
||||
typename A20, typename A21, typename A22, typename A23>
|
||||
struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
struct __attribute__((packed)) PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
A10, A11, A12, A13, A14, A15, A16, A17, A18, A19,
|
||||
A20, A21, A22, A23> {
|
||||
A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9;
|
||||
@@ -63,45 +63,45 @@ struct PackedArguments<R, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9,
|
||||
};
|
||||
|
||||
template<>
|
||||
struct PackedArguments<void> { };
|
||||
struct __attribute__((packed)) PackedArguments<void> { };
|
||||
template<typename A0>
|
||||
struct PackedArguments<void, A0> { A0 a0; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0> { A0 a0; };
|
||||
template<typename A0, typename A1>
|
||||
struct PackedArguments<void, A0, A1> { A0 a0; A1 a1; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1> { A0 a0; A1 a1; };
|
||||
template<typename A0, typename A1, typename A2>
|
||||
struct PackedArguments<void, A0, A1, A2> { A0 a0; A1 a1; A2 a2; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2> { A0 a0; A1 a1; A2 a2; };
|
||||
template<typename A0, typename A1, typename A2, typename A3>
|
||||
struct PackedArguments<void, A0, A1, A2, A3> { A0 a0; A1 a1; A2 a2; A3 a3; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3> { A0 a0; A1 a1; A2 a2; A3 a3; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15, typename A16>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15, typename A16, typename A17>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; };
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15, typename A16, typename A17, typename A18>
|
||||
struct PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; A18 a18; };
|
||||
struct __attribute__((packed)) PackedArguments<void, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18> { A0 a0; A1 a1; A2 a2; A3 a3; A4 a4; A5 a5; A6 a6; A7 a7; A8 a8; A9 a9; A10 a10; A11 a11; A12 a12; A13 a13; A14 a14; A15 a15; A16 a16; A17 a17; A18 a18; };
|
||||
|
||||
// Helper struct that allows assigning the result of a function to a variable, even if that result is a void type.
|
||||
//
|
||||
|
||||
@@ -400,6 +400,8 @@ template<> struct fex_gen_config<vkWaitSemaphoresKHR> {};
|
||||
template<> struct fex_gen_config<vkSignalSemaphoreKHR> {};
|
||||
template<> struct fex_gen_config<vkGetPhysicalDeviceFragmentShadingRatesKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetFragmentShadingRateKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetRenderingAttachmentLocationsKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetRenderingInputAttachmentIndicesKHR> {};
|
||||
template<> struct fex_gen_config<vkWaitForPresentKHR> {};
|
||||
template<> struct fex_gen_config<vkGetBufferDeviceAddressKHR> {};
|
||||
template<> struct fex_gen_config<vkGetBufferOpaqueCaptureAddressKHR> {};
|
||||
@@ -414,6 +416,9 @@ template<> struct fex_gen_config<vkGetPipelineExecutableStatisticsKHR> {};
|
||||
template<> struct fex_gen_config<vkGetPipelineExecutableInternalRepresentationsKHR> {};
|
||||
template<> struct fex_gen_config<vkMapMemory2KHR> {};
|
||||
template<> struct fex_gen_config<vkUnmapMemory2KHR> {};
|
||||
template<> struct fex_gen_config<vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR> {};
|
||||
template<> struct fex_gen_config<vkGetEncodedVideoSessionParametersKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdEncodeVideoKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetEvent2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdResetEvent2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdWaitEvents2KHR> {};
|
||||
@@ -437,6 +442,15 @@ template<> struct fex_gen_config<vkGetRenderingAreaGranularityKHR> {};
|
||||
template<> struct fex_gen_config<vkGetDeviceImageSubresourceLayoutKHR> {};
|
||||
template<> struct fex_gen_config<vkGetImageSubresourceLayout2KHR> {};
|
||||
template<> struct fex_gen_config<vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetLineStippleKHR> {};
|
||||
template<> struct fex_gen_config<vkGetPhysicalDeviceCalibrateableTimeDomainsKHR> {};
|
||||
template<> struct fex_gen_config<vkGetCalibratedTimestampsKHR> {};
|
||||
template<> struct fex_gen_config<vkCmdBindDescriptorSets2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdPushConstants2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdPushDescriptorSet2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdPushDescriptorSetWithTemplate2KHR> {};
|
||||
template<> struct fex_gen_config<vkCmdSetDescriptorBufferOffsets2EXT> {};
|
||||
template<> struct fex_gen_config<vkCmdBindDescriptorBufferEmbeddedSamplers2EXT> {};
|
||||
template<> struct fex_gen_config<vkCreateDebugReportCallbackEXT> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<vkCreateDebugReportCallbackEXT, 1, const VkDebugReportCallbackCreateInfoEXT*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_config<vkDestroyDebugReportCallbackEXT> : fexgen::custom_host_impl {};
|
||||
@@ -579,6 +593,12 @@ template<> struct fex_gen_config<vkCreatePrivateDataSlotEXT> {};
|
||||
template<> struct fex_gen_config<vkDestroyPrivateDataSlotEXT> {};
|
||||
template<> struct fex_gen_config<vkSetPrivateDataEXT> {};
|
||||
template<> struct fex_gen_config<vkGetPrivateDataEXT> {};
|
||||
template<> struct fex_gen_config<vkCreateCudaModuleNV> {};
|
||||
template<> struct fex_gen_config<vkGetCudaModuleCacheNV> {};
|
||||
template<> struct fex_gen_config<vkCreateCudaFunctionNV> {};
|
||||
template<> struct fex_gen_config<vkDestroyCudaModuleNV> {};
|
||||
template<> struct fex_gen_config<vkDestroyCudaFunctionNV> {};
|
||||
template<> struct fex_gen_config<vkCmdCudaLaunchKernelNV> {};
|
||||
template<> struct fex_gen_config<vkGetDescriptorSetLayoutSizeEXT> {};
|
||||
template<> struct fex_gen_config<vkGetDescriptorSetLayoutBindingOffsetEXT> {};
|
||||
template<> struct fex_gen_config<vkGetDescriptorEXT> {};
|
||||
@@ -633,7 +653,6 @@ template<> struct fex_gen_config<vkCmdDecompressMemoryIndirectCountNV> {};
|
||||
template<> struct fex_gen_config<vkGetPipelineIndirectMemoryRequirementsNV> {};
|
||||
template<> struct fex_gen_config<vkCmdUpdatePipelineIndirectBufferNV> {};
|
||||
template<> struct fex_gen_config<vkGetPipelineIndirectDeviceAddressNV> {};
|
||||
template<> struct fex_gen_config<vkCmdSetTessellationDomainOriginEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetDepthClampEnableEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetPolygonModeEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetRasterizationSamplesEXT> {};
|
||||
@@ -644,6 +663,7 @@ template<> struct fex_gen_config<vkCmdSetLogicOpEnableEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetColorBlendEnableEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetColorBlendEquationEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetColorWriteMaskEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetTessellationDomainOriginEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetRasterizationStreamEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetConservativeRasterizationModeEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdSetExtraPrimitiveOverestimationSizeEXT> {};
|
||||
@@ -677,6 +697,11 @@ template<> struct fex_gen_config<vkGetShaderBinaryDataEXT> {};
|
||||
template<> struct fex_gen_config<vkCmdBindShadersEXT> {};
|
||||
template<> struct fex_gen_config<vkGetFramebufferTilePropertiesQCOM> {};
|
||||
template<> struct fex_gen_config<vkGetDynamicRenderingTilePropertiesQCOM> {};
|
||||
template<> struct fex_gen_config<vkSetLatencySleepModeNV> {};
|
||||
template<> struct fex_gen_config<vkLatencySleepNV> {};
|
||||
template<> struct fex_gen_config<vkSetLatencyMarkerNV> {};
|
||||
template<> struct fex_gen_config<vkGetLatencyTimingsNV> {};
|
||||
template<> struct fex_gen_config<vkQueueNotifyOutOfBandNV> {};
|
||||
template<> struct fex_gen_config<vkCmdSetAttachmentFeedbackLoopEnableEXT> {};
|
||||
template<> struct fex_gen_config<vkCreateAccelerationStructureKHR> {};
|
||||
template<> struct fex_gen_config<vkDestroyAccelerationStructureKHR> {};
|
||||
|
||||
@@ -33,17 +33,11 @@ extern "C" const wl_interface wl_callback_interface {};
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/Guest.h"
|
||||
|
||||
#include "thunkgen_guest_libwayland-client.inl"
|
||||
|
||||
struct wl_proxy_private {
|
||||
wl_interface* interface;
|
||||
// Other data members omitted
|
||||
};
|
||||
|
||||
// See wayland-util.h for documentation on protocol message signatures
|
||||
template<char> struct ArgType;
|
||||
template<> struct ArgType<'s'> { using type = const char*; };
|
||||
@@ -56,37 +50,31 @@ template<> struct ArgType<'f'> { using type = wl_fixed_t; };
|
||||
template<> struct ArgType<'h'> { using type = int32_t; }; // fd?
|
||||
|
||||
template<char... Signature>
|
||||
static void* WaylandAllocateHostTrampolineForGuestListener(void (*callback)()) {
|
||||
static uint64_t WaylandAllocateHostTrampolineForGuestListener(void (*callback)()) {
|
||||
using cb = void(void*, wl_proxy*, typename ArgType<Signature>::type...);
|
||||
return (void*)AllocateHostTrampolineForGuestFunction((cb*)callback);
|
||||
return (uint64_t)(uintptr_t)(void*)AllocateHostTrampolineForGuestFunction((cb*)callback);
|
||||
}
|
||||
|
||||
#define WL_CLOSURE_MAX_ARGS 20
|
||||
|
||||
// Per-proxy list of callbacks set up via wl_proxy_add_listener.
|
||||
// These tables store the host-callable trampolines to the actual listener
|
||||
// callbacks provided by the guest application.
|
||||
// NOTE: There can only be one listener per proxy. Wayland will return an error
|
||||
// if wl_proxy_add_listener is called twice.
|
||||
// NOTE: Entries should be removed in wl_destroy_proxy. Since proxy wrappers do
|
||||
// not use their own listeners, wl_proxy_wrapper_destroy does not need to
|
||||
// be customized.
|
||||
static std::unordered_map<wl_proxy*, std::array<void*, WL_CLOSURE_MAX_ARGS>> proxy_listeners;
|
||||
|
||||
extern "C" int wl_proxy_add_listener(wl_proxy *proxy,
|
||||
void (**callback)(void), void *data) {
|
||||
auto interface = ((wl_proxy_private*)proxy)->interface;
|
||||
// Replace guest-provided callback table with host-callable function pointers
|
||||
// NOTE: A reference to this table is stored in the wl_proxy, so the data
|
||||
// must remain valid until the proxy is destroyed (or another listener
|
||||
// is added)
|
||||
delete[] (uint64_t*)wl_proxy_get_listener(proxy); // Delete previous substitute, if any
|
||||
auto host_callbacks = new uint64_t[WL_CLOSURE_MAX_ARGS];
|
||||
|
||||
// NOTE: This table must remain valid past the return of this function.
|
||||
auto& host_callbacks = proxy_listeners[proxy];
|
||||
|
||||
for (int i = 0; i < ((wl_proxy_private*)proxy)->interface->event_count; ++i) {
|
||||
auto signature_view = std::string_view { interface->events[i].signature };
|
||||
for (int i = 0; i < fex_wl_get_interface_event_count(proxy); ++i) {
|
||||
char event_signature[16];
|
||||
fex_wl_get_interface_event_signature(proxy, i, event_signature);
|
||||
auto signature2 = std::string_view { event_signature };
|
||||
|
||||
// A leading number indicates the minimum protocol version
|
||||
uint32_t since_version = 0;
|
||||
auto [ptr, res] = std::from_chars(signature_view.begin(), signature_view.end(), since_version, 10);
|
||||
std::string signature { ptr, &*signature_view.end() };
|
||||
auto [ptr, res] = std::from_chars(signature2.begin(), signature2.end(), since_version, 10);
|
||||
auto signature = std::string { signature2.substr(ptr - signature2.begin()) };
|
||||
|
||||
// ? just indicates that the argument may be null, so it doesn't change the signature
|
||||
signature.erase(std::remove(signature.begin(), signature.end(), '?'), signature.end());
|
||||
@@ -185,17 +173,18 @@ extern "C" int wl_proxy_add_listener(wl_proxy *proxy,
|
||||
// E.g. zwp_text_input_v3::preedit_string
|
||||
host_callbacks[i] = WaylandAllocateHostTrampolineForGuestListener<'s', 'i', 'i'>(callback[i]);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown wayland signature descriptor \"%s\" for event \"%s\" in interface \"%s\"\n", signature.data(), interface->events[i].name, interface->name);
|
||||
fprintf(stderr, "TODO: Unknown wayland event signature descriptor %s\n", signature.data());
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
return fexfn_pack_wl_proxy_add_listener(proxy, (void(**)())host_callbacks.data(), data);
|
||||
return fexfn_pack_wl_proxy_add_listener(proxy, (void(**)())host_callbacks, data);
|
||||
}
|
||||
|
||||
extern "C" void wl_proxy_destroy(struct wl_proxy *proxy) {
|
||||
proxy_listeners.erase(proxy);
|
||||
return fexfn_pack_wl_proxy_destroy(proxy);
|
||||
extern "C" void wl_proxy_destroy(wl_proxy *proxy) {
|
||||
// Delete substitute callback table (if any), then the proxy itself
|
||||
delete[] (uint64_t*)wl_proxy_get_listener(proxy);
|
||||
fexfn_pack_wl_proxy_destroy(proxy);
|
||||
}
|
||||
|
||||
// Adapted from the Wayland sources
|
||||
@@ -266,18 +255,48 @@ extern "C" void wl_proxy_marshal(wl_proxy *proxy, uint32_t opcode, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, opcode);
|
||||
#ifdef IS_32BIT_THUNK
|
||||
// Must extract signature from host due to different data layout on 32-bit
|
||||
#error Not implemented
|
||||
#else
|
||||
wl_argument_from_va_list(((wl_proxy_private*)proxy)->interface->methods[opcode].signature,
|
||||
args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
#endif
|
||||
// This is equivalent to reading proxy->interface->methods[opcode].signature on 64-bit.
|
||||
// On 32-bit, the data layout differs between host and guest however, so we let the host extract the data.
|
||||
char signature[64];
|
||||
fex_wl_get_method_signature(proxy, opcode, signature);
|
||||
wl_argument_from_va_list(signature, args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
va_end(ap);
|
||||
|
||||
wl_proxy_marshal_array(proxy, opcode, args);
|
||||
}
|
||||
|
||||
extern "C" wl_proxy *wl_proxy_marshal_constructor(wl_proxy *proxy, uint32_t opcode,
|
||||
const wl_interface *interface, ...) {
|
||||
wl_argument args[WL_CLOSURE_MAX_ARGS];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, interface);
|
||||
// This is equivalent to reading ((wl_proxy_private*)proxy)->interface->methods[opcode].signature on 64-bit.
|
||||
// On 32-bit, the data layout differs between host and guest however, so we let the host extract the data.
|
||||
char signature[64];
|
||||
fex_wl_get_method_signature(proxy, opcode, signature);
|
||||
wl_argument_from_va_list(signature, args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
va_end(ap);
|
||||
|
||||
return wl_proxy_marshal_array_constructor(proxy, opcode, args, interface);
|
||||
}
|
||||
|
||||
extern "C" wl_proxy *wl_proxy_marshal_constructor_versioned(wl_proxy *proxy, uint32_t opcode,
|
||||
const wl_interface *interface, uint32_t version, ...) {
|
||||
wl_argument args[WL_CLOSURE_MAX_ARGS];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, version);
|
||||
// This is equivalent to reading ((wl_proxy_private*)proxy)->interface->methods[opcode].signature on 64-bit.
|
||||
// On 32-bit, the data layout differs between host and guest however, so we let the host extract the data.
|
||||
char signature[64];
|
||||
fex_wl_get_method_signature(proxy, opcode, signature);
|
||||
wl_argument_from_va_list(signature, args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
va_end(ap);
|
||||
|
||||
return wl_proxy_marshal_array_constructor_versioned(proxy, opcode, args, interface, version);
|
||||
}
|
||||
|
||||
extern "C" wl_proxy *wl_proxy_marshal_flags(wl_proxy *proxy, uint32_t opcode,
|
||||
const wl_interface *interface,
|
||||
uint32_t version,
|
||||
@@ -286,13 +305,11 @@ extern "C" wl_proxy *wl_proxy_marshal_flags(wl_proxy *proxy, uint32_t opcode,
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, flags);
|
||||
#ifdef IS_32BIT_THUNK
|
||||
// Must extract signature from host due to different data layout on 32-bit
|
||||
#error Not implemented
|
||||
#else
|
||||
wl_argument_from_va_list(((wl_proxy_private*)proxy)->interface->methods[opcode].signature,
|
||||
args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
#endif
|
||||
// This is equivalent to reading proxy->interface->methods[opcode].signature on 64-bit.
|
||||
// On 32-bit, the data layout differs between host and guest however, so we let the host extract the data.
|
||||
char signature[64];
|
||||
fex_wl_get_method_signature(proxy, opcode, signature);
|
||||
wl_argument_from_va_list(signature, args, WL_CLOSURE_MAX_ARGS, ap);
|
||||
va_end(ap);
|
||||
|
||||
// wl_proxy_marshal_array_flags is only available starting from Wayland 1.19.91
|
||||
@@ -304,18 +321,23 @@ extern "C" wl_proxy *wl_proxy_marshal_flags(wl_proxy *proxy, uint32_t opcode,
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void wl_log_set_handler_client(wl_log_func_t handler) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
void OnInit() {
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_output_interface), "wl_output");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_shm_pool_interface), "wl_shm_pool");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_pointer_interface), "wl_pointer");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_compositor_interface), "wl_compositor");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_shm_interface), "wl_shm");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_registry_interface), "wl_registry");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_buffer_interface), "wl_buffer");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_seat_interface), "wl_seat");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_surface_interface), "wl_surface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_keyboard_interface), "wl_keyboard");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_callback_interface), "wl_callback");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_output_interface), "wl_output_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_shm_pool_interface), "wl_shm_pool_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_pointer_interface), "wl_pointer_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_compositor_interface), "wl_compositor_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_shm_interface), "wl_shm_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_registry_interface), "wl_registry_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_buffer_interface), "wl_buffer_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_seat_interface), "wl_seat_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_surface_interface), "wl_surface_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_keyboard_interface), "wl_keyboard_interface");
|
||||
fex_wl_exchange_interface_pointer(const_cast<wl_interface*>(&wl_callback_interface), "wl_callback_interface");
|
||||
}
|
||||
|
||||
LOAD_LIB_INIT(libwayland-client, OnInit)
|
||||
@@ -5,6 +5,7 @@ $end_info$
|
||||
*/
|
||||
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -19,14 +20,272 @@ $end_info$
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
template<>
|
||||
struct guest_layout<wl_argument> {
|
||||
#ifdef IS_32BIT_THUNK
|
||||
using type = uint32_t;
|
||||
#else
|
||||
using type = wl_argument;
|
||||
#endif
|
||||
type data;
|
||||
|
||||
guest_layout& operator=(const wl_argument from) {
|
||||
#ifdef IS_32BIT_THUNK
|
||||
data = from.u;
|
||||
#else
|
||||
data = from;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#include "thunkgen_host_libwayland-client.inl"
|
||||
|
||||
struct wl_proxy_private {
|
||||
wl_interface* interface;
|
||||
// Other data members omitted
|
||||
};
|
||||
// Maps guest interface to host_interfaces
|
||||
static std::unordered_map<guest_layout<const wl_interface>*, wl_interface*> guest_to_host_interface;
|
||||
|
||||
static wl_interface* get_proxy_interface(wl_proxy* proxy) {
|
||||
// wl_proxy is a private struct, but its first member is the wl_interface pointer
|
||||
return *reinterpret_cast<wl_interface**>(proxy);
|
||||
}
|
||||
|
||||
static void assert_is_valid_host_interface(const wl_interface* interface) {
|
||||
// The 32-bit data layout of wl_interface differs from the 64-bit one due to
|
||||
// its pointer members. Our repacking code takes care of these differences.
|
||||
//
|
||||
// To ensure this indeed functions properly, a simple consistency check is
|
||||
// applied here: If any of the message counts are absurdly high, it means
|
||||
// data from pointer members leaked into other members.
|
||||
|
||||
if ((uint32_t)interface->method_count >= 0x1000 || (uint32_t)interface->event_count >= 0x1000) {
|
||||
fprintf(stderr, "ERROR: Expected %p to be a host wl_interface, but it's not\n", interface);
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IS_32BIT_THUNK
|
||||
static void assert_is_valid_guest_interface(guest_layout<const wl_interface*> guest_interface) {
|
||||
// Consistency check for expected data layout.
|
||||
// See assert_is_valid_host_interface for details
|
||||
|
||||
const wl_interface* as_host_interface = (const wl_interface*)guest_interface.force_get_host_pointer();
|
||||
if ((uint32_t)as_host_interface->method_count < 0x1000 && (uint32_t)as_host_interface->event_count < 0x1000) {
|
||||
fprintf(stderr, "ERROR: Expected %p to be a guest wl_interface, but it's not\n", guest_interface.force_get_host_pointer());
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void repack_guest_wl_interface_to_host(guest_layout<const wl_interface*> guest_interface_ptr, wl_interface* host_interface) {
|
||||
auto& guest_interface = *guest_interface_ptr.get_pointer();
|
||||
static_assert(sizeof(guest_interface) == 24);
|
||||
|
||||
*host_interface = host_layout<wl_interface> { guest_interface }.data;
|
||||
fex_apply_custom_repacking_entry(reinterpret_cast<host_layout<wl_interface>&>(*host_interface), guest_interface);
|
||||
}
|
||||
|
||||
// Maps guest interface pointers to host pointers
|
||||
static const wl_interface* lookup_wl_interface(guest_layout<const wl_interface*> interface) {
|
||||
// Used e.g. for wl_shm_pool_destroy
|
||||
if (interface.force_get_host_pointer() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto [host_interface_it, inserted] = guest_to_host_interface.emplace(interface.get_pointer(), nullptr);
|
||||
if (!inserted) {
|
||||
assert_is_valid_host_interface(host_interface_it->second);
|
||||
return host_interface_it->second;
|
||||
}
|
||||
|
||||
assert_is_valid_guest_interface(interface);
|
||||
|
||||
fprintf(stderr, "Unknown wayland interface %p, adding to registry\n", interface.get_pointer());
|
||||
|
||||
host_interface_it->second = new wl_interface;
|
||||
wl_interface* host_interface = host_interface_it->second;
|
||||
repack_guest_wl_interface_to_host(interface, host_interface);
|
||||
return host_interface_it->second;
|
||||
}
|
||||
|
||||
void fex_custom_repack_entry(host_layout<wl_interface>& into, guest_layout<wl_interface> const& from) {
|
||||
// NOTE: These arrays are complements to global symbols in the guest, so we
|
||||
// never explicitly free this memory
|
||||
auto& host_interface = into.data;
|
||||
into.data.methods = new wl_message[into.data.method_count];
|
||||
into.data.events = new wl_message[into.data.event_count];
|
||||
|
||||
memset((void*)host_interface.methods, 0, sizeof(wl_message) * host_interface.method_count);
|
||||
for (int i = 0; i < host_interface.method_count; ++i) {
|
||||
const auto& guest_method { from.data.methods.get_pointer()[i] };
|
||||
host_layout<wl_message> host_method { guest_method };
|
||||
fex_apply_custom_repacking_entry(host_method, guest_method);
|
||||
memcpy((void*)&host_interface.methods[i], &host_method, sizeof(host_method));
|
||||
}
|
||||
|
||||
memset((void*)host_interface.events, 0, sizeof(wl_message) * host_interface.event_count);
|
||||
for (int i = 0; i < host_interface.event_count; ++i) {
|
||||
const auto& guest_event { from.data.events.get_pointer()[i] };
|
||||
host_layout<wl_message> host_event { guest_event };
|
||||
fex_apply_custom_repacking_entry(host_event, guest_event);
|
||||
memcpy((void*)&host_interface.events[i], &host_event, sizeof(host_event));
|
||||
}
|
||||
}
|
||||
|
||||
bool fex_custom_repack_exit(guest_layout<wl_interface>&, host_layout<wl_interface> const&) {
|
||||
fprintf(stderr, "Should not be called: %s\n", __PRETTY_FUNCTION__);
|
||||
std::abort();
|
||||
}
|
||||
void fex_custom_repack_entry(host_layout<wl_message>& into, guest_layout<wl_message> const& from) {
|
||||
auto& host_method = into.data;
|
||||
auto num_types = std::ranges::count_if(std::string_view { host_method.signature }, isalpha);
|
||||
if (num_types) {
|
||||
host_method.types = new const wl_interface*[num_types];
|
||||
for (int type = 0; type < num_types; ++type) {
|
||||
auto guest_interface_addr = from.data.types.get_pointer()[type];
|
||||
host_method.types[type] = guest_interface_addr.force_get_host_pointer() ? lookup_wl_interface(guest_interface_addr) : nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool fex_custom_repack_exit(guest_layout<wl_message>&, host_layout<wl_message> const&) {
|
||||
fprintf(stderr, "Should not be called: %s\n", __PRETTY_FUNCTION__);
|
||||
std::abort();
|
||||
}
|
||||
#else
|
||||
const wl_interface* lookup_wl_interface(guest_layout<const wl_interface*> interface) {
|
||||
return interface.force_get_host_pointer();
|
||||
}
|
||||
#endif
|
||||
|
||||
static wl_proxy* fexfn_impl_libwayland_client_wl_proxy_create(wl_proxy* proxy, guest_layout<const wl_interface*> guest_interface_raw) {
|
||||
auto host_interface = lookup_wl_interface(guest_interface_raw);
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_create(proxy, host_interface);
|
||||
}
|
||||
|
||||
#define WL_CLOSURE_MAX_ARGS 20
|
||||
static auto
|
||||
fex_wl_remap_argument_list(guest_layout<wl_argument*> args, const wl_message& message) {
|
||||
#ifndef IS_32BIT_THUNK
|
||||
// Cast to host layout and return as std::span
|
||||
wl_argument* host_args = host_layout<wl_argument*> { args }.data;
|
||||
return std::span<wl_argument, WL_CLOSURE_MAX_ARGS> { host_args, WL_CLOSURE_MAX_ARGS };
|
||||
#else
|
||||
// Return a new array of elements zero-extended to 64-bit
|
||||
std::array<wl_argument, WL_CLOSURE_MAX_ARGS> host_args;
|
||||
int arg_count = std::ranges::count_if(std::string_view { message.signature }, isalpha);
|
||||
for (int i = 0; i < arg_count; ++i) {
|
||||
// NOTE: wl_argument can store a pointer argument, so for 32-bit guests
|
||||
// we need to make sure the upper 32-bits are explicitly zeroed
|
||||
std::memset(&host_args[i], 0, sizeof(host_args[i]));
|
||||
std::memcpy(&host_args[i], &args.get_pointer()[i], sizeof(args.get_pointer()[i]));
|
||||
}
|
||||
return host_args;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
fexfn_impl_libwayland_client_wl_proxy_marshal_array(
|
||||
wl_proxy *proxy, uint32_t opcode,
|
||||
guest_layout<wl_argument*> args) {
|
||||
auto host_args = fex_wl_remap_argument_list(args, get_proxy_interface(proxy)->methods[opcode]);
|
||||
fexldr_ptr_libwayland_client_wl_proxy_marshal_array(proxy, opcode, host_args.data());
|
||||
}
|
||||
|
||||
static wl_proxy*
|
||||
fex_wl_proxy_marshal_array(
|
||||
wl_proxy *proxy, uint32_t opcode,
|
||||
guest_layout<wl_argument*> args,
|
||||
guest_layout<const wl_interface*> guest_interface,
|
||||
bool constructor, // Call the _constructor variant of the native wayland function
|
||||
std::optional<uint32_t> version,
|
||||
std::optional<uint32_t> flags) {
|
||||
auto interface = lookup_wl_interface(guest_interface);
|
||||
|
||||
assert_is_valid_host_interface(get_proxy_interface(proxy));
|
||||
|
||||
auto host_args = fex_wl_remap_argument_list(args, get_proxy_interface(proxy)->methods[opcode]);
|
||||
|
||||
if (false) {
|
||||
} else if (!constructor && !version && !flags) {
|
||||
return nullptr;
|
||||
} else if (!constructor && version && flags) {
|
||||
// wl_proxy_marshal_array_flags is only available starting from Wayland 1.19.91
|
||||
#if WAYLAND_VERSION_MAJOR * 10000 + WAYLAND_VERSION_MINOR * 100 + WAYLAND_VERSION_MICRO >= 11991
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_marshal_array_flags(proxy, opcode, interface, version.value(), flags.value(), host_args.data());
|
||||
#else
|
||||
fprintf(stderr, "Host Wayland version is too old to support FEX thunking\n");
|
||||
__builtin_trap();
|
||||
#endif
|
||||
} else if (constructor && version && !flags) {
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_marshal_array_constructor_versioned(proxy, opcode, host_args.data(), interface, version.value());
|
||||
} else if (constructor && version && !flags) {
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_marshal_array_constructor(proxy, opcode, host_args.data(), interface);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid configuration\n");
|
||||
__builtin_trap();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" wl_proxy*
|
||||
fexfn_impl_libwayland_client_wl_proxy_marshal_array_constructor_versioned(
|
||||
wl_proxy *proxy, uint32_t opcode,
|
||||
guest_layout<wl_argument*> args,
|
||||
guest_layout<const wl_interface*> interface,
|
||||
uint32_t version) {
|
||||
return fex_wl_proxy_marshal_array(proxy, opcode, args, interface, true, version, std::nullopt);
|
||||
}
|
||||
|
||||
extern "C" wl_proxy*
|
||||
fexfn_impl_libwayland_client_wl_proxy_marshal_array_constructor(
|
||||
wl_proxy *proxy, uint32_t opcode,
|
||||
guest_layout<wl_argument*> args,
|
||||
guest_layout<const wl_interface*> interface) {
|
||||
return fex_wl_proxy_marshal_array(proxy, opcode, args, interface, true, std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
extern "C" wl_proxy*
|
||||
fexfn_impl_libwayland_client_wl_proxy_marshal_array_flags(
|
||||
wl_proxy *proxy, uint32_t opcode,
|
||||
guest_layout<const wl_interface*> interface,
|
||||
uint32_t version, uint32_t flags,
|
||||
guest_layout<wl_argument*> args) {
|
||||
return fex_wl_proxy_marshal_array(proxy, opcode, args, interface, false, version, flags);
|
||||
}
|
||||
|
||||
// Variant of CallbackUnpack::CallGuestPtr that relocates a wl_array parameter
|
||||
// for 32-bit guests. Relocating this parameter is required since it may
|
||||
// reference inaccessible memory regions (presumably due to pointing to data
|
||||
// on the host stack).
|
||||
#ifndef IS_32BIT_THUNK
|
||||
template<typename Result, typename... Args>
|
||||
const auto CallGuestPtrWithWaylandArray = CallbackUnpack<Result(Args..., wl_array*)>::CallGuestPtr;
|
||||
#else
|
||||
template<typename Result, typename... Args>
|
||||
static auto CallGuestPtrWithWaylandArray(Args... args, wl_array *array) -> Result {
|
||||
GuestcallInfo *guestcall;
|
||||
LOAD_INTERNAL_GUESTPTR_VIA_CUSTOM_ABI(guestcall);
|
||||
|
||||
using PackedArgumentsType = PackedArguments<Result, guest_layout<Args>..., guest_layout<wl_array*>>;
|
||||
|
||||
GuestStackBumpAllocator GuestStack;
|
||||
|
||||
auto* guest_array = GuestStack.New<guest_layout<wl_array>>(to_guest(to_host_layout(*array)));
|
||||
guest_layout<wl_array*> guest_array_ptr = { .data = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(guest_array)) };
|
||||
|
||||
auto& packed_args = *GuestStack.New<PackedArgumentsType>(
|
||||
to_guest(to_host_layout(args))..., guest_array_ptr
|
||||
);
|
||||
|
||||
guestcall->CallCallback(guestcall->GuestUnpacker, guestcall->GuestTarget, &packed_args);
|
||||
|
||||
if constexpr (!std::is_void_v<Result>) {
|
||||
return packed_args.rv;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// See wayland-util.h for documentation on protocol message signatures
|
||||
template<char> struct ArgType;
|
||||
@@ -46,28 +305,34 @@ static void WaylandFinalizeHostTrampolineForGuestListener(void (*callback)()) {
|
||||
}
|
||||
|
||||
extern "C" int fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_proxy *proxy,
|
||||
guest_layout<void (**)(void)> callback_raw, void* data) {
|
||||
auto guest_interface = ((wl_proxy_private*)proxy)->interface;
|
||||
guest_layout<void (**)(void)> callback_table_raw, void* data) {
|
||||
auto interface = get_proxy_interface(proxy);
|
||||
|
||||
for (int i = 0; i < guest_interface->event_count; ++i) {
|
||||
auto signature_view = std::string_view { guest_interface->events[i].signature };
|
||||
assert_is_valid_host_interface(interface);
|
||||
|
||||
auto callback_table = callback_table_raw.force_get_host_pointer();
|
||||
|
||||
for (int i = 0; i < interface->event_count; ++i) {
|
||||
auto signature_view = std::string_view { interface->events[i].signature };
|
||||
|
||||
// A leading number indicates the minimum protocol version
|
||||
uint32_t since_version = 0;
|
||||
auto [ptr, res] = std::from_chars(signature_view.begin(), signature_view.end(), since_version, 10);
|
||||
std::string signature { ptr, &*signature_view.end() };
|
||||
auto signature = std::string { signature_view.substr(ptr - signature_view.begin()) };
|
||||
|
||||
// ? just indicates that the argument may be null, so it doesn't change the signature
|
||||
signature.erase(std::remove(signature.begin(), signature.end(), '?'), signature.end());
|
||||
|
||||
auto callback = reinterpret_cast<void(*)()>(uintptr_t { callback_raw.get_pointer()[i].data });
|
||||
auto callback = callback_table[i];
|
||||
|
||||
if (signature == "") {
|
||||
// E.g. xdg_toplevel::close
|
||||
WaylandFinalizeHostTrampolineForGuestListener<>(callback);
|
||||
} else if (signature == "a") {
|
||||
// E.g. xdg_toplevel::wm_capabilities
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'a'>(callback);
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction(
|
||||
(FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*>);
|
||||
} else if (signature == "hu") {
|
||||
// E.g. zwp_linux_dmabuf_feedback_v1::format_table
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'h', 'u'>(callback);
|
||||
@@ -85,7 +350,9 @@ extern "C" int fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_prox
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'i', 'i'>(callback);
|
||||
} else if (signature == "iia") {
|
||||
// E.g. xdg_toplevel::configure
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'i', 'i', 'a'>(callback);
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction(
|
||||
(FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, int32_t, int32_t>);
|
||||
} else if (signature == "iiiiissi") {
|
||||
// E.g. wl_output_listener::geometry
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'i', 'i', 'i', 'i', 'i', 's', 's', 'i'>(callback);
|
||||
@@ -118,7 +385,9 @@ extern "C" int fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_prox
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'u', 'o'>(callback);
|
||||
} else if (signature == "uoa") {
|
||||
// E.g. wl_keyboard_listener::enter
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'u', 'o', 'a'>(callback);
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction(
|
||||
(FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, uint32_t, wl_surface*>);
|
||||
} else if (signature == "uoff") {
|
||||
// E.g. wl_pointer_listener::enter
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'u', 'o', 'f', 'f'>(callback);
|
||||
@@ -162,15 +431,15 @@ extern "C" int fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_prox
|
||||
}
|
||||
|
||||
// Pass the original function pointer table to the host wayland library. This ensures the table is valid until the listener is unregistered.
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_add_listener(proxy,
|
||||
reinterpret_cast<void(**)(void)>(callback_raw.get_pointer()),
|
||||
data);
|
||||
return fexldr_ptr_libwayland_client_wl_proxy_add_listener(proxy, callback_table, data);
|
||||
}
|
||||
|
||||
wl_interface* fexfn_impl_libwayland_client_fex_wl_exchange_interface_pointer(wl_interface* guest_interface, char const* name) {
|
||||
auto host_interface = reinterpret_cast<wl_interface*>(dlsym(fexldr_ptr_libwayland_client_so, (std::string { name } + "_interface").c_str()));
|
||||
void fexfn_impl_libwayland_client_fex_wl_exchange_interface_pointer(guest_layout<wl_interface*> guest_interface_raw, const char* name) {
|
||||
auto& guest_interface = *guest_interface_raw.get_pointer();
|
||||
auto& host_interface = guest_to_host_interface[reinterpret_cast<guest_layout<const wl_interface>*>(&guest_interface)];
|
||||
host_interface = reinterpret_cast<wl_interface*>(dlsym(fexldr_ptr_libwayland_client_so, name));
|
||||
if (!host_interface) {
|
||||
fprintf(stderr, "Could not find host interface corresponding to %p (%s)\n", guest_interface, name);
|
||||
fprintf(stderr, "Could not find host interface corresponding to %p (%s)\n", &guest_interface, name);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
@@ -178,23 +447,50 @@ wl_interface* fexfn_impl_libwayland_client_fex_wl_exchange_interface_pointer(wl_
|
||||
// them into the rodata section of the application itself instead of the
|
||||
// library. To copy the host information to them on startup, we must
|
||||
// temporarily disable write-protection on this data hence.
|
||||
auto page_begin = reinterpret_cast<uintptr_t>(guest_interface) & ~uintptr_t { 0xfff };
|
||||
auto page_begin = reinterpret_cast<uintptr_t>(guest_interface_raw.force_get_host_pointer()) & ~uintptr_t { 0xfff };
|
||||
if (0 != mprotect((void*)page_begin, 0x1000, PROT_READ | PROT_WRITE)) {
|
||||
fprintf(stderr, "ERROR: %s\n", strerror(errno));
|
||||
std::abort();
|
||||
}
|
||||
|
||||
#ifdef IS_32BIT_THUNK
|
||||
// Requires struct repacking for wl_interface
|
||||
#error Not implemented
|
||||
#ifndef IS_32BIT_THUNK
|
||||
memcpy(&guest_interface, host_interface, sizeof(wl_interface));
|
||||
#else
|
||||
memcpy(guest_interface, host_interface, sizeof(wl_interface));
|
||||
guest_interface = to_guest(to_host_layout(*host_interface));
|
||||
|
||||
// NOTE: These arrays are complements to global symbols in the guest, so we
|
||||
// never explicitly free this memory
|
||||
guest_interface.data.methods.data = (uintptr_t)new guest_layout<wl_message>[host_interface->method_count];
|
||||
for (int i = 0; i < host_interface->method_count; ++i) {
|
||||
guest_interface.data.methods.get_pointer()[i] = to_guest(to_host_layout(host_interface->methods[i]));
|
||||
guest_interface.data.methods.get_pointer()[i].data.types = to_guest(to_host_layout(host_interface->methods[i].types));
|
||||
}
|
||||
|
||||
guest_interface.data.events.data = (uintptr_t)new guest_layout<wl_message>[host_interface->event_count];
|
||||
for (int i = 0; i < host_interface->event_count; ++i) {
|
||||
guest_interface.data.events.get_pointer()[i] = to_guest(to_host_layout(host_interface->events[i]));
|
||||
guest_interface.data.events.get_pointer()[i].data.types = to_guest(to_host_layout(host_interface->events[i].types));
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: Disabled until we ensure the interface data is indeed stored in rodata
|
||||
// mprotect((void*)page_begin, 0x1000, PROT_READ);
|
||||
}
|
||||
|
||||
return host_interface;
|
||||
void fexfn_impl_libwayland_client_fex_wl_get_method_signature(wl_proxy* proxy, uint32_t opcode, char* out) {
|
||||
strcpy(out, get_proxy_interface(proxy)->methods[opcode].signature);
|
||||
}
|
||||
|
||||
int fexfn_impl_libwayland_client_fex_wl_get_interface_event_count(wl_proxy* proxy) {
|
||||
return get_proxy_interface(proxy)->event_count;
|
||||
}
|
||||
|
||||
void fexfn_impl_libwayland_client_fex_wl_get_interface_event_name(wl_proxy* proxy, int i, char* out) {
|
||||
strcpy(out, get_proxy_interface(proxy)->events[i].name);
|
||||
}
|
||||
|
||||
void fexfn_impl_libwayland_client_fex_wl_get_interface_event_signature(wl_proxy* proxy, int i, char* out) {
|
||||
strcpy(out, get_proxy_interface(proxy)->events[i].signature);
|
||||
}
|
||||
|
||||
EXPORTS(libwayland_client)
|
||||
@@ -16,30 +16,41 @@ struct fex_gen_param {};
|
||||
|
||||
template<> struct fex_gen_type<wl_display> : fexgen::opaque_type {};
|
||||
template<> struct fex_gen_type<wl_proxy> : fexgen::opaque_type {};
|
||||
template<> struct fex_gen_type<wl_interface> : fexgen::opaque_type {};
|
||||
|
||||
template<> struct fex_gen_type<wl_event_queue> : fexgen::opaque_type {};
|
||||
|
||||
// Passed over Wayland's wire protocol for some functions
|
||||
template<> struct fex_gen_type<wl_array> {};
|
||||
template<> struct fex_gen_type<wl_array> : fexgen::emit_layout_wrappers {};
|
||||
|
||||
#ifdef IS_32BIT_THUNK
|
||||
// wl_interface and wl_message reference each other through pointers
|
||||
template<> struct fex_gen_type<wl_interface> : fexgen::emit_layout_wrappers {};
|
||||
template<> struct fex_gen_config<&wl_interface::methods> : fexgen::custom_repack {};
|
||||
template<> struct fex_gen_config<&wl_interface::events> : fexgen::custom_repack {};
|
||||
template<> struct fex_gen_type<wl_message> : fexgen::emit_layout_wrappers {};
|
||||
template<> struct fex_gen_config<&wl_message::types> : fexgen::custom_repack {};
|
||||
#else
|
||||
template<> struct fex_gen_type<wl_interface> : fexgen::assume_compatible_data_layout {};
|
||||
#endif
|
||||
|
||||
template<> struct fex_gen_config<wl_proxy_destroy> : fexgen::custom_guest_entrypoint {};
|
||||
|
||||
template<> struct fex_gen_config<wl_display_cancel_read> {};
|
||||
template<> struct fex_gen_config<wl_display_connect> {};
|
||||
template<> struct fex_gen_config<wl_display_flush> {};
|
||||
template<> struct fex_gen_config<wl_display_cancel_read> {};
|
||||
template<> struct fex_gen_config<wl_display_create_queue> {};
|
||||
template<> struct fex_gen_config<wl_display_disconnect> {};
|
||||
template<> struct fex_gen_config<wl_display_dispatch> {};
|
||||
template<> struct fex_gen_config<wl_display_dispatch_pending> {};
|
||||
template<> struct fex_gen_config<wl_display_dispatch_queue> {};
|
||||
template<> struct fex_gen_config<wl_display_dispatch_queue_pending> {};
|
||||
template<> struct fex_gen_config<wl_display_flush> {};
|
||||
template<> struct fex_gen_config<wl_display_get_error> {};
|
||||
template<> struct fex_gen_config<wl_display_prepare_read> {};
|
||||
template<> struct fex_gen_config<wl_display_prepare_read_queue> {};
|
||||
template<> struct fex_gen_config<wl_display_read_events> {};
|
||||
template<> struct fex_gen_config<wl_display_roundtrip> {};
|
||||
template<> struct fex_gen_config<wl_display_roundtrip_queue> {};
|
||||
template<> struct fex_gen_config<wl_display_connect_to_fd> {};
|
||||
template<> struct fex_gen_config<wl_display_get_fd> {};
|
||||
|
||||
template<> struct fex_gen_config<wl_event_queue_destroy> {};
|
||||
@@ -49,8 +60,12 @@ template<> struct fex_gen_config<wl_proxy_add_listener> : fexgen::custom_host_im
|
||||
template<> struct fex_gen_param<wl_proxy_add_listener, 1, void(**)()> : fexgen::ptr_passthrough {};
|
||||
// User-provided data pointer (not used in caller-provided callback)
|
||||
template<> struct fex_gen_param<wl_proxy_add_listener, 2, void*> : fexgen::assume_compatible_data_layout {};
|
||||
template<> struct fex_gen_config<wl_proxy_create> {};
|
||||
template<> struct fex_gen_config<wl_proxy_create> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<wl_proxy_create, 1, const wl_interface*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_config<wl_proxy_create_wrapper> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_class> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_id> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_listener> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_tag> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_user_data> {};
|
||||
template<> struct fex_gen_config<wl_proxy_get_version> {};
|
||||
@@ -60,12 +75,33 @@ template<> struct fex_gen_config<wl_proxy_set_tag> {};
|
||||
template<> struct fex_gen_config<wl_proxy_set_user_data> {};
|
||||
template<> struct fex_gen_config<wl_proxy_wrapper_destroy> {};
|
||||
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array> {};
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array, 2, wl_argument*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array_constructor> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_constructor, 2, wl_argument*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_constructor, 3, const wl_interface*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array_constructor_versioned> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_constructor_versioned, 2, wl_argument*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_constructor_versioned, 3, const wl_interface*> : fexgen::ptr_passthrough {};
|
||||
// wl_proxy_marshal_array_flags is only available starting from Wayland 1.19.91
|
||||
#if WAYLAND_VERSION_MAJOR * 10000 + WAYLAND_VERSION_MINOR * 100 + WAYLAND_VERSION_MICRO >= 11991
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array_flags> {};
|
||||
template<> struct fex_gen_config<wl_proxy_marshal_array_flags> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_flags, 2, const wl_interface*> : fexgen::ptr_passthrough {};
|
||||
template<> struct fex_gen_param<wl_proxy_marshal_array_flags, 5, wl_argument*> : fexgen::ptr_passthrough {};
|
||||
#endif
|
||||
|
||||
// Guest notifies host about its interface. Host returns its corresponding interface pointer
|
||||
wl_interface* fex_wl_exchange_interface_pointer(wl_interface*, const char* name);
|
||||
void fex_wl_exchange_interface_pointer(wl_interface*, const char* name);
|
||||
template<> struct fex_gen_config<fex_wl_exchange_interface_pointer> : fexgen::custom_host_impl {};
|
||||
template<> struct fex_gen_param<fex_wl_exchange_interface_pointer, 0, wl_interface*> : fexgen::ptr_passthrough {};
|
||||
|
||||
// This is equivalent to reading proxy->interface->methods[opcode].signature on 64-bit.
|
||||
// On 32-bit, the data layout differs between host and guest however, so we let the host extract the data.
|
||||
void fex_wl_get_method_signature(wl_proxy*, uint32_t opcode, char*);
|
||||
template<> struct fex_gen_config<fex_wl_get_method_signature> : fexgen::custom_host_impl {};
|
||||
int fex_wl_get_interface_event_count(wl_proxy*);
|
||||
template<> struct fex_gen_config<fex_wl_get_interface_event_count> : fexgen::custom_host_impl {};
|
||||
void fex_wl_get_interface_event_name(wl_proxy*, int, char*);
|
||||
template<> struct fex_gen_config<fex_wl_get_interface_event_name> : fexgen::custom_host_impl {};
|
||||
void fex_wl_get_interface_event_signature(wl_proxy*, int, char*);
|
||||
template<> struct fex_gen_config<fex_wl_get_interface_event_signature> : fexgen::custom_host_impl {};
|
||||
@@ -1,4 +1,4 @@
|
||||
# FEX-2402
|
||||
# FEX-2403
|
||||
|
||||
## FEXCore
|
||||
See [FEXCore/Readme.md](../FEXCore/Readme.md) for more details
|
||||
|
||||
@@ -117,4 +117,6 @@ add_custom_target(
|
||||
32bit_asm_tests
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
USES_TERMINAL
|
||||
DEPENDS 32bit_asm_files
|
||||
DEPENDS "${CMAKE_BINARY_DIR}/Bin/TestHarnessRunner"
|
||||
COMMAND "ctest" "--output-on-failure" "--timeout" "302" "-j${CORES}" "-R" "\.*32Bit\.*.asm$$")
|
||||
@@ -0,0 +1,43 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x41424344",
|
||||
"RBX": "0x41424344",
|
||||
"RCX": "0x51525354"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x00fd0000": "4096",
|
||||
"0xf0000000": "4096"
|
||||
},
|
||||
"MemoryData": {
|
||||
"0xf0000000": "0x41424344",
|
||||
"0x00fd0000": "0x51525354"
|
||||
},
|
||||
"Mode": "32BIT"
|
||||
}
|
||||
%endif
|
||||
|
||||
; Ensures that zero extension of addresses are adhered to.
|
||||
lea eax, [0xf000_0000]
|
||||
mov eax, [ds:eax]
|
||||
|
||||
; Ensures that zext occurs correctly with two registers that have the sign bit set.
|
||||
mov ebx, 0xffff_ffff
|
||||
mov ecx, 0xf000_0001
|
||||
|
||||
; Break the block so it can't optimize through.
|
||||
jmp .test
|
||||
.test:
|
||||
mov ebx, [ebx+ecx]
|
||||
|
||||
; Ensures that zext occurs correctly with SIB indexing with second argument not having sign bit set but "index" having sign bit.
|
||||
; Originally saw in Metal Gear Rising Revengeance with a `jmp dword [ecx*4+0xfdbf10]` instruction.
|
||||
; With ecx = 0xfffffff4 = -12. This is them loading a switch table's branches just before the switch base.
|
||||
mov ecx, -12
|
||||
|
||||
; Break the block so it can't optimize through.
|
||||
jmp .test2
|
||||
.test2:
|
||||
|
||||
mov ecx, [ecx*4+0x00fd_0030]
|
||||
hlt
|
||||
@@ -83,7 +83,7 @@ foreach(ASM_SRC ${ASM_SOURCES})
|
||||
list(GET TEST_ARGS ${TEST_NAME_INDEX} TEST_DESC)
|
||||
list(GET TEST_ARGS ${TEST_TYPE_INDEX} TEST_TYPE)
|
||||
|
||||
set(TEST_NAME "${TEST_DESC}/Test_${REL_TEST_ASM}")
|
||||
set(TEST_NAME "${TEST_DESC}/Test_64Bit_${REL_TEST_ASM}")
|
||||
string(REPLACE " " ";" ARGS_LIST ${ARGS})
|
||||
|
||||
if (TEST_NAME MATCHES "SelfModifyingCode")
|
||||
@@ -120,8 +120,19 @@ add_custom_target(asm_files ALL
|
||||
execute_process(COMMAND "nproc" OUTPUT_VARIABLE CORES)
|
||||
string(STRIP ${CORES} CORES)
|
||||
|
||||
add_custom_target(
|
||||
64bit_asm_tests
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
USES_TERMINAL
|
||||
DEPENDS asm_files
|
||||
DEPENDS "${CMAKE_BINARY_DIR}/Bin/TestHarnessRunner"
|
||||
COMMAND "ctest" "--output-on-failure" "--timeout" "302" "-j${CORES}" "-R" "\.*64Bit\.*.asm$$")
|
||||
|
||||
add_custom_target(
|
||||
asm_tests
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
USES_TERMINAL
|
||||
DEPENDS asm_files
|
||||
DEPENDS 32bit_asm_files
|
||||
DEPENDS "${CMAKE_BINARY_DIR}/Bin/TestHarnessRunner"
|
||||
COMMAND "ctest" "--output-on-failure" "--timeout" "302" "-j${CORES}" "-R" "\.*.asm$$")
|
||||
@@ -0,0 +1,32 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; 32-bit:
|
||||
; 265 = clock_gettime
|
||||
; 64-bit
|
||||
; 265 = linkat
|
||||
|
||||
; rax = syscall on both 32-bit and 64-bit
|
||||
mov rax, 265
|
||||
|
||||
; rdi/rbx = first argument on 64-bit and 32-bit respectively
|
||||
mov rdi, 0
|
||||
mov rbx, 0
|
||||
|
||||
; rsi/rcx = second argument on 64-bit and 32-bit respectively
|
||||
lea rsi, [rel .data]
|
||||
lea rcx, [rel .data]
|
||||
|
||||
; Do a 32-bit syscall
|
||||
; On a real linux kernel this will execute clock_gettime
|
||||
; Under FEX without 32-bit syscall support this might try to execute linkat and return -ENOENT.
|
||||
int 0x80
|
||||
hlt
|
||||
|
||||
.data:
|
||||
dq 0, 0, 0, 0
|
||||
Loaded 100 of 126 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user