From 50c75d1f432df8a6e3a126744d112d9194d56145 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 14 Jul 2026 20:05:22 -0700 Subject: [PATCH] Move Linux version calculation to common code --- Source/Common/CMakeLists.txt | 3 ++- Source/Common/Linux/LinuxVersion.cpp | 25 +++++++++++++++++++ Source/Common/Linux/LinuxVersion.h | 22 ++++++++++++++++ Source/Tools/FEXInterpreter/ELFCodeLoader.h | 4 +-- .../Tools/FEXInterpreter/FEXInterpreter.cpp | 5 ++-- .../EmulatedFiles/EmulatedFiles.cpp | 8 +++--- .../LinuxEmulation/LinuxSyscalls/Syscalls.cpp | 23 ++--------------- .../LinuxEmulation/LinuxSyscalls/Syscalls.h | 18 ++----------- .../LinuxSyscalls/Syscalls/Info.cpp | 6 ++--- .../LinuxEmulation/LinuxSyscalls/x32/Info.cpp | 8 +++--- 10 files changed, 69 insertions(+), 53 deletions(-) create mode 100644 Source/Common/Linux/LinuxVersion.cpp create mode 100644 Source/Common/Linux/LinuxVersion.h diff --git a/Source/Common/CMakeLists.txt b/Source/Common/CMakeLists.txt index 259dec4b3..d05e07d3a 100644 --- a/Source/Common/CMakeLists.txt +++ b/Source/Common/CMakeLists.txt @@ -14,7 +14,8 @@ if (NOT MINGW) list(APPEND SRCS FEXServerClient.cpp FileFormatCheck.cpp - Linux/SBRKAllocations.cpp) + Linux/SBRKAllocations.cpp + Linux/LinuxVersion.cpp) endif() add_library(${NAME} STATIC ${SRCS}) diff --git a/Source/Common/Linux/LinuxVersion.cpp b/Source/Common/Linux/LinuxVersion.cpp new file mode 100644 index 000000000..7861a5230 --- /dev/null +++ b/Source/Common/Linux/LinuxVersion.cpp @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +#include +#include +#include + +namespace FEX::LinuxVersion { +uint32_t CalculateHostKernelVersion() { + struct utsname buf {}; + if (uname(&buf) == -1) { + return 0; + } + + uint32_t Major {}; + uint32_t Minor {}; + uint32_t Patch {}; + + // Parse kernel version in the form of `..[Optional Data]` + const auto End = buf.release + sizeof(buf.release); + auto Results = std::from_chars(buf.release, End, Major, 10); + Results = std::from_chars(Results.ptr + 1, End, Minor, 10); + Results = std::from_chars(Results.ptr + 1, End, Patch, 10); + + return (Major << 24) | (Minor << 16) | Patch; +} +} // namespace FEX::LinuxVersion diff --git a/Source/Common/Linux/LinuxVersion.h b/Source/Common/Linux/LinuxVersion.h new file mode 100644 index 000000000..0ef379648 --- /dev/null +++ b/Source/Common/Linux/LinuxVersion.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +#pragma once +#include + +namespace FEX::LinuxVersion { +inline uint32_t KernelVersion(uint32_t Major, uint32_t Minor = 0, uint32_t Patch = 0) { + return (Major << 24) | (Minor << 16) | Patch; +} + +inline uint32_t KernelMajor(uint32_t Version) { + return Version >> 24; +} +inline uint32_t KernelMinor(uint32_t Version) { + return (Version >> 16) & 0xFF; +} + +inline uint32_t KernelPatch(uint32_t Version) { + return Version & 0xFFFF; +} + +uint32_t CalculateHostKernelVersion(); +} // namespace FEX::LinuxVersion diff --git a/Source/Tools/FEXInterpreter/ELFCodeLoader.h b/Source/Tools/FEXInterpreter/ELFCodeLoader.h index e96068789..5850c83d5 100644 --- a/Source/Tools/FEXInterpreter/ELFCodeLoader.h +++ b/Source/Tools/FEXInterpreter/ELFCodeLoader.h @@ -297,8 +297,8 @@ public: #ifndef AT_FLAGS_PRESERVE_ARGV0 #define AT_FLAGS_PRESERVE_ARGV0 1 #endif - uint32_t HostKernel = FEX::HLE::SyscallHandler::CalculateHostKernelVersion(); - if ((HostKernel >= FEX::HLE::SyscallHandler::KernelVersion(5, 12, 0) && (AtFlags & AT_FLAGS_PRESERVE_ARGV0)) || LoadedWithFD) { + uint32_t HostKernel = FEX::LinuxVersion::CalculateHostKernelVersion(); + if ((HostKernel >= FEX::LinuxVersion::KernelVersion(5, 12, 0) && (AtFlags & AT_FLAGS_PRESERVE_ARGV0)) || LoadedWithFD) { // Erase the initial argument from the list in this case ApplicationArgs.erase(ApplicationArgs.begin()); diff --git a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp index d0b639e8a..0514f9e4b 100644 --- a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp +++ b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp @@ -10,6 +10,7 @@ $end_info$ #include "Common/FEXServerClient.h" #include "Common/Config.h" #include "Common/HostFeatures.h" +#include "Common/Linux/LinuxVersion.h" #include "Common/Linux/SBRKAllocations.h" #include "PortabilityInfo.h" #include "ELFCodeLoader.h" @@ -463,8 +464,8 @@ int main(int argc, char** argv, char** const envp) { return -ENOEXEC; } - uint32_t KernelVersion = FEX::HLE::SyscallHandler::CalculateHostKernelVersion(); - if (KernelVersion < FEX::HLE::SyscallHandler::KernelVersion(5, 15)) { + uint32_t KernelVersion = FEX::LinuxVersion::CalculateHostKernelVersion(); + if (KernelVersion < FEX::LinuxVersion::KernelVersion(5, 15)) { LogMan::Msg::EFmt("FEX requires kernel 5.15 minimum. Expect problems."); } diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp index 1180be3cf..72f61e307 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp @@ -532,8 +532,8 @@ EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context* ctx) int FD = GenTmpFD(pathname, flags); uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); char Tmp[64] {}; - snprintf(Tmp, sizeof(Tmp), "%d.%d.%d\n", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(Tmp, sizeof(Tmp), "%d.%d.%d\n", FEX::LinuxVersion::KernelMajor(GuestVersion), FEX::LinuxVersion::KernelMinor(GuestVersion), + FEX::LinuxVersion::KernelPatch(GuestVersion)); // + 1 to ensure null at the end write(FD, Tmp, strlen(Tmp) + 1); lseek(FD, 0, SEEK_SET); @@ -548,8 +548,8 @@ EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context* ctx) const char kernel_version[] = "Linux version %d.%d.%d (FEX@FEX) (clang) #" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__ "\n"; uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); char Tmp[sizeof(kernel_version) + 64] {}; - snprintf(Tmp, sizeof(Tmp), kernel_version, FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(Tmp, sizeof(Tmp), kernel_version, FEX::LinuxVersion::KernelMajor(GuestVersion), FEX::LinuxVersion::KernelMinor(GuestVersion), + FEX::LinuxVersion::KernelPatch(GuestVersion)); // + 1 to ensure null at the end write(FD, Tmp, strlen(Tmp) + 1); lseek(FD, 0, SEEK_SET); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp index 1674f8951..c391337de 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp @@ -790,7 +790,7 @@ SyscallHandler::SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::Signal , SignalDelegation {_SignalDelegation} , ThunkHandler {ThunkHandler} { FEX::HLE::_SyscallHandler = this; - HostKernelVersion = CalculateHostKernelVersion(); + HostKernelVersion = LinuxVersion::CalculateHostKernelVersion(); GuestKernelVersion = CalculateGuestKernelVersion(); Alloc32Handler = FEX::HLE::Create32BitAllocator(); @@ -803,28 +803,9 @@ SyscallHandler::~SyscallHandler() { FEXCore::Allocator::munmap(reinterpret_cast(DataSpace), DataSpaceMappedSize); } -uint32_t SyscallHandler::CalculateHostKernelVersion() { - struct utsname buf {}; - if (uname(&buf) == -1) { - return 0; - } - - uint32_t Major {}; - uint32_t Minor {}; - uint32_t Patch {}; - - // Parse kernel version in the form of `..[Optional Data]` - const auto End = buf.release + sizeof(buf.release); - auto Results = std::from_chars(buf.release, End, Major, 10); - Results = std::from_chars(Results.ptr + 1, End, Minor, 10); - Results = std::from_chars(Results.ptr + 1, End, Patch, 10); - - return (Major << 24) | (Minor << 16) | Patch; -} - uint32_t SyscallHandler::CalculateGuestKernelVersion() { // We currently only emulate a kernel between the ranges of Kernel 5.15.0 and 6.11.0 - return std::max(KernelVersion(5, 15), std::min(KernelVersion(6, 11), GetHostKernelVersion())); + return std::max(LinuxVersion::KernelVersion(5, 15), std::min(LinuxVersion::KernelVersion(6, 11), GetHostKernelVersion())); } uint64_t SyscallHandler::HandleSyscall(FEXCore::Core::CpuStateFrame* Frame, FEXCore::HLE::SyscallArguments* Args) { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h index a3189a6e0..3909930cb 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h @@ -8,6 +8,7 @@ $end_info$ #pragma once +#include "Common/Linux/LinuxVersion.h" #include "Common/VolatileMetadata.h" #include "LinuxSyscalls/FileManagement.h" #include "LinuxSyscalls/LinuxAllocator.h" @@ -210,26 +211,11 @@ public: } bool IsHostKernelVersionAtLeast(uint32_t Major, uint32_t Minor = 0, uint32_t Patch = 0) const { - return GetHostKernelVersion() >= KernelVersion(Major, Minor, Patch); + return GetHostKernelVersion() >= LinuxVersion::KernelVersion(Major, Minor, Patch); } - static uint32_t CalculateHostKernelVersion(); uint32_t CalculateGuestKernelVersion(); - static uint32_t KernelVersion(uint32_t Major, uint32_t Minor = 0, uint32_t Patch = 0) { - return (Major << 24) | (Minor << 16) | Patch; - } - - static uint32_t KernelMajor(uint32_t Version) { - return Version >> 24; - } - static uint32_t KernelMinor(uint32_t Version) { - return (Version >> 16) & 0xFF; - } - static uint32_t KernelPatch(uint32_t Version) { - return Version & 0xFFFF; - } - virtual FEX::HLE::MemAllocator* Get32BitAllocator() { return Alloc32Handler.get(); } diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp index 6f359d1f3..1b61282d3 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Info.cpp @@ -51,10 +51,10 @@ void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); if (Thread->persona & UNAME26) { // Kernel version converts from 6.x.y to 2.6.60+x. - GuestVersion = FEX::HLE::SyscallHandler::KernelVersion(2, 6, 60 + FEX::HLE::SyscallHandler::KernelMinor(GuestVersion)); + GuestVersion = FEX::LinuxVersion::KernelVersion(2, 6, 60 + FEX::LinuxVersion::KernelMinor(GuestVersion)); } - snprintf(buf->release, sizeof(buf->release), "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(buf->release, sizeof(buf->release), "%d.%d.%d", FEX::LinuxVersion::KernelMajor(GuestVersion), + FEX::LinuxVersion::KernelMinor(GuestVersion), FEX::LinuxVersion::KernelPatch(GuestVersion)); const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; strcpy(buf->version, version); diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp index ddd07ec36..899de9b62 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/x32/Info.cpp @@ -61,8 +61,8 @@ void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { } strncpy(buf->sysname, "Linux", __OLD_UTS_LEN); uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __OLD_UTS_LEN, "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(buf->release, __OLD_UTS_LEN, "%d.%d.%d", FEX::LinuxVersion::KernelMajor(GuestVersion), + FEX::LinuxVersion::KernelMinor(GuestVersion), FEX::LinuxVersion::KernelPatch(GuestVersion)); const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; strncpy(buf->version, version, __OLD_UTS_LEN); @@ -85,8 +85,8 @@ void RegisterInfo(FEX::HLE::SyscallHandler* Handler) { } strncpy(buf->sysname, "Linux", __NEW_UTS_LEN); uint32_t GuestVersion = FEX::HLE::_SyscallHandler->GetGuestKernelVersion(); - snprintf(buf->release, __NEW_UTS_LEN, "%d.%d.%d", FEX::HLE::SyscallHandler::KernelMajor(GuestVersion), - FEX::HLE::SyscallHandler::KernelMinor(GuestVersion), FEX::HLE::SyscallHandler::KernelPatch(GuestVersion)); + snprintf(buf->release, __NEW_UTS_LEN, "%d.%d.%d", FEX::LinuxVersion::KernelMajor(GuestVersion), + FEX::LinuxVersion::KernelMinor(GuestVersion), FEX::LinuxVersion::KernelPatch(GuestVersion)); const char version[] = "#" GIT_DESCRIBE_STRING " SMP " __DATE__ " " __TIME__; strncpy(buf->version, version, __NEW_UTS_LEN);