mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-07 19:00:16 +02:00
Including fallback to non-unixlib path because we need to support both. Showcases how these are going to be implemented without throwing the entire world at it right away. Next PR will be implementing the remaining four necessary unixlib handlers that we will require: - Kernel unaligned atomic control - shm_stats thing - madvise operation - prctl vma naming
103 lines
2.9 KiB
C++
103 lines
2.9 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
|
|
#include <cstdint>
|
|
#include <windef.h>
|
|
#define __WINESRC__
|
|
#include <winternl.h>
|
|
#include <libloaderapi.h>
|
|
#include "FEXUnixLib.h"
|
|
|
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
|
|
|
namespace FEX::Windows::UnixLib {
|
|
unixlib_handle_t UnixLibHandle {};
|
|
|
|
decltype(__wine_unix_call_dispatcher) UnixCallDispatcher {};
|
|
|
|
#ifdef ARCHITECTURE_arm64ec
|
|
// On ARM64EC, indirect calls go through __os_arm64x_dispatch_icall which invokes
|
|
// FEX's custom call checker. Use a naked trampoline to bypass the dispatch mechanism
|
|
// and call the unix dispatcher directly via a register branch.
|
|
static decltype(__wine_unix_call_dispatcher) UnixCallDispatcherDirect {};
|
|
|
|
static NTSTATUS __attribute__((naked)) TrampolineCall(unixlib_handle_t, unsigned int, void*) {
|
|
asm(R"(
|
|
adrp x16, %[Displace];
|
|
ldr x16, [x16, #:lo12:%[Displace]]
|
|
br x16
|
|
)" ::[Displace] "S"(&UnixCallDispatcherDirect)
|
|
: "memory");
|
|
}
|
|
#endif
|
|
|
|
bool Init(HMODULE NtDll) {
|
|
const auto Sym = GetProcAddress(NtDll, "__wine_unix_call_dispatcher");
|
|
|
|
if (!Sym) {
|
|
return false;
|
|
}
|
|
|
|
auto TryNewWineMethod = []() {
|
|
#ifdef ARCHITECTURE_arm64ec
|
|
constexpr auto Name = "libarm64ecfex";
|
|
#else
|
|
constexpr auto Name = "libwow64fex";
|
|
#endif
|
|
|
|
// Not supported in Proton at all, but supported in upstream WINE.
|
|
uint64_t Result[2];
|
|
if (NtQueryVirtualMemory(NtCurrentProcess(), Name, MemoryWineLoadUnixLibByName, Result, sizeof(Result), nullptr)) {
|
|
return false;
|
|
}
|
|
|
|
// Result[0] = unixlib_module_t
|
|
// Result[1] = unixlib_handle_t
|
|
// Module is ignored as it's only used to unload.
|
|
UnixLibHandle = Result[1];
|
|
return true;
|
|
};
|
|
|
|
auto TryOldWineMethod = []() {
|
|
// Supported in Proton 11 and Experimental (2026-06-26).
|
|
return NtQueryVirtualMemory(NtCurrentProcess(), &__ImageBase, MemoryWineUnixFuncs, &UnixLibHandle, sizeof(UnixLibHandle), nullptr) == 0;
|
|
};
|
|
|
|
if (!TryNewWineMethod() && !TryOldWineMethod()) {
|
|
return false;
|
|
}
|
|
|
|
#ifdef ARCHITECTURE_arm64ec
|
|
UnixCallDispatcherDirect = *reinterpret_cast<decltype(__wine_unix_call_dispatcher)*>(Sym);
|
|
UnixCallDispatcher = TrampolineCall;
|
|
#else
|
|
UnixCallDispatcher = *reinterpret_cast<decltype(__wine_unix_call_dispatcher)*>(Sym);
|
|
#endif
|
|
|
|
// Give a log saying that the unix lib was loaded.
|
|
LogMan::Msg::IFmt("FEX: Loaded FEXUnixLib");
|
|
return true;
|
|
}
|
|
|
|
static bool UnixLibAvailable() {
|
|
return UnixLibHandle != 0;
|
|
}
|
|
|
|
bool TryEnableHardwareTSO() {
|
|
if (UnixLibAvailable()) {
|
|
// UnixLib path.
|
|
FEXUnixLib_SetHardwareTSOControlArgs Args {
|
|
.Enable = true,
|
|
};
|
|
|
|
return Call(FEXUnixLibFunctions::SetHardwareTSOControl, &Args) == STATUS_SUCCESS;
|
|
}
|
|
|
|
// Legacy Proton path.
|
|
bool Enable = TRUE;
|
|
NTSTATUS Status = NtSetInformationProcess(NtCurrentProcess(), ProcessFexHardwareTso, &Enable, sizeof(Enable));
|
|
return Status == STATUS_SUCCESS;
|
|
}
|
|
|
|
} // namespace FEX::Windows::UnixLib
|