diff --git a/Source/Common/VolatileMetadata.h b/Source/Common/VolatileMetadata.h index e131e9dc2..a6141fe1b 100644 --- a/Source/Common/VolatileMetadata.h +++ b/Source/Common/VolatileMetadata.h @@ -16,4 +16,36 @@ struct ExtendedVolatileMetadata { }; fextl::unordered_map ParseExtendedVolatileMetadata(std::string_view ListOfDescriptors); + +inline void ApplyFEXExtendedVolatileMetadata(FEX::VolatileMetadata::ExtendedVolatileMetadata& ExtendedMetaData, + fextl::set& VolatileInstructions, FEXCore::IntervalList& VolatileValidRanges, + uint64_t Address, uint64_t EndAddress, uint64_t FileOffset = 0, uint64_t FileOffsetEnd = ~0ULL) { + // Load FEX extended volatile metadata. + // Walk the volatile instructions first if they exist. + for (const auto it_inst : ExtendedMetaData.VolatileInstructions) { + const auto inst_address = it_inst + Address; + if (inst_address < EndAddress) { + VolatileInstructions.emplace(Address + it_inst); + } else { + LogMan::Msg::DFmt("Volatile instruction 0x{:x} couldn't fit in to module range [0x{:x}, 0x{:x}). Not adding anymore volatile " + "instructions. Inspect your config!", + inst_address, Address, EndAddress); + return; + } + } + + // Walk the volatile list + for (const auto it_ranges : ExtendedMetaData.VolatileValidRanges) { + if (it_ranges.Offset >= FileOffset && it_ranges.End < FileOffsetEnd) { + VolatileValidRanges.Insert({Address + it_ranges.Offset - FileOffset, Address + it_ranges.End - FileOffset}); + } + } + + // If it is fully disabled, then set the entire module range + if (ExtendedMetaData.ModuleTSODisabled) { + VolatileValidRanges.Clear(); + VolatileValidRanges.Insert({Address, EndAddress}); + } +} + } // namespace FEX::VolatileMetadata diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp index 924cf0369..bae2c8331 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.cpp @@ -771,6 +771,9 @@ SyscallHandler::SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::Signal Alloc32Handler = FEX::HLE::Create32BitAllocator(); SignalDelegation->RegisterHostSignalHandler(SIGSEGV, HandleSegfault, true); + + FEX_CONFIG_OPT(ExtendedVolatileMetadataConfig, EXTENDEDVOLATILEMETADATA); + ExtendedMetaData = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig()); } SyscallHandler::~SyscallHandler() { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h index 6c527e21f..0c05185f6 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/VolatileMetadata.h" #include "LinuxSyscalls/FileManagement.h" #include "LinuxSyscalls/LinuxAllocator.h" #include "LinuxSyscalls/ThreadManager.h" @@ -253,7 +254,12 @@ public: uint64_t GuestShmdt(bool Is64Bit, FEXCore::Core::InternalThreadState*, const void* shmaddr); ///// Memory Manager tracking ///// - void TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint64_t addr, size_t length, int prot, int flags, int fd, off_t offset); + struct LateApplyExtendedVolatileMetadata { + fextl::set VolatileInstructions {}; + FEXCore::IntervalList VolatileValidRanges {}; + }; + std::optional + TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint64_t addr, size_t length, int prot, int flags, int fd, off_t offset); void TrackMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length); void TrackMremap(FEXCore::Core::InternalThreadState* Thread, uint64_t OldAddress, size_t OldSize, size_t NewSize, int flags, uint64_t NewAddress); void TrackShmat(FEXCore::Core::InternalThreadState* Thread, int shmid, uint64_t shmaddr, int shmflg, uint64_t Length); @@ -350,6 +356,8 @@ private: FEX::HLE::SignalDelegator* SignalDelegation; FEX::HLE::ThunkHandler* ThunkHandler; + fextl::unordered_map ExtendedMetaData {}; + std::mutex FutexMutex; std::mutex SyscallMutex; FEX::CodeLoader* LocalLoader {}; diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp index 1bebc4df8..a1ff4b705 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp @@ -22,6 +22,7 @@ $end_info$ #include #include #include +#include namespace FEX::HLE { // SMC interactions @@ -200,6 +201,7 @@ void* SyscallHandler::GuestMmap(bool Is64Bit, FEXCore::Core::InternalThreadState uint64_t Result {}; size_t Size = FEXCore::AlignUp(length, FEXCore::Utils::FEX_PAGE_SIZE); + std::optional LateMetadata = std::nullopt; { // NOTE: Frontend calls this with a nullptr Thread during initialization, but @@ -221,10 +223,16 @@ void* SyscallHandler::GuestMmap(bool Is64Bit, FEXCore::Core::InternalThreadState } } - FEX::HLE::_SyscallHandler->TrackMmap(Thread, Result, length, prot, flags, fd, offset); + LateMetadata = FEX::HLE::_SyscallHandler->TrackMmap(Thread, Result, length, prot, flags, fd, offset); } FEX::HLE::_SyscallHandler->InvalidateCodeRangeIfNecessary(Thread, Result, Size); + + if (LateMetadata) { + auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), Thread); + CTX->AddForceTSOInformation(LateMetadata->VolatileValidRanges, std::move(LateMetadata->VolatileInstructions)); + } + return reinterpret_cast(Result); } @@ -256,6 +264,11 @@ uint64_t SyscallHandler::GuestMunmap(bool Is64Bit, FEXCore::Core::InternalThread } FEX::HLE::_SyscallHandler->InvalidateCodeRangeIfNecessary(Thread, reinterpret_cast(addr), Size); + if (length) { + auto CodeInvalidationlk = GuardSignalDeferringSectionWithFallback(CTX->GetCodeInvalidationMutex(), Thread); + CTX->RemoveForceTSOInformation(reinterpret_cast(addr), length); + } + return Result; } @@ -360,11 +373,15 @@ uint64_t SyscallHandler::GuestShmdt(bool Is64Bit, FEXCore::Core::InternalThreadS } // MMan Tracking -void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint64_t addr, size_t length, int prot, int flags, int fd, off_t offset) { +std::optional SyscallHandler::TrackMmap( + FEXCore::Core::InternalThreadState* Thread, uint64_t addr, size_t length, int prot, int flags, int fd, off_t offset) { size_t Size = FEXCore::AlignUp(length, FEXCore::Utils::FEX_PAGE_SIZE); + const auto ProtMapping = VMATracking::VMAProt::fromProt(prot); VMATracking::MappedResource* Resource = nullptr; + std::optional VolatileMetadata = std::nullopt; + if (!(flags & MAP_ANONYMOUS)) { struct stat64 buf; fstat64(fd, &buf); @@ -382,6 +399,21 @@ void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint6 Resource->MappedFile->Filename = fextl::string(Tmp, PathLength); Resource->Iterator = Iter; } + + const fextl::string Filename = FHU::Filesystem::GetFilename(Resource->MappedFile->Filename); + + // We now have the filename and the offset in the filename getting mapped. + // Check for extended volatile metadata. + auto it = ExtendedMetaData.find(Filename); + if (it != ExtendedMetaData.end()) { + SyscallHandler::LateApplyExtendedVolatileMetadata LateMetadata; + FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata( + it->second, LateMetadata.VolatileInstructions, LateMetadata.VolatileValidRanges, addr, addr + length, offset, offset + length); + + if (!LateMetadata.VolatileInstructions.empty() || !LateMetadata.VolatileValidRanges.Empty()) { + VolatileMetadata.emplace(std::move(LateMetadata)); + } + } } } else if (flags & MAP_SHARED) { VMATracking::MRID mrid {VMATracking::SpecialDev::Anon, AnonSharedId++}; @@ -394,7 +426,8 @@ void SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint6 Resource = nullptr; } - VMATracking.TrackVMARange(CTX, Resource, addr, offset, Size, VMATracking::VMAFlags::fromFlags(flags), VMATracking::VMAProt::fromProt(prot)); + VMATracking.TrackVMARange(CTX, Resource, addr, offset, Size, VMATracking::VMAFlags::fromFlags(flags), ProtMapping); + return VolatileMetadata; } void SyscallHandler::TrackMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length) { diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 33b7538bd..cc1332432 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -39,10 +39,10 @@ $end_info$ #include "Common/CRT/CRT.h" #include "Common/PortabilityInfo.h" #include "Common/Handle.h" +#include "Common/VolatileMetadata.h" #include "DummyHandlers.h" #include "BTInterface.h" #include "Windows/Common/SHMStats.h" -#include "Windows/Common/VolatileMetadata.h" #include #include @@ -314,7 +314,7 @@ void LoadImageVolatileMetadata(const fextl::string& ModuleName, uint64_t Address auto it = ExtendedMetaData.find(ModuleName); if (it != ExtendedMetaData.end()) { - FEX::Windows::ApplyFEXExtendedVolatileMetadata(it->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); + FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(it->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); } if (VolatileInstructions.empty() && VolatileValidRanges.Empty()) { diff --git a/Source/Windows/Common/VolatileMetadata.h b/Source/Windows/Common/VolatileMetadata.h deleted file mode 100644 index 8d6d3f813..000000000 --- a/Source/Windows/Common/VolatileMetadata.h +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MIT -#pragma once - -#include "Common/VolatileMetadata.h" - -#include -#include -#include -#include - -namespace FEX::Windows { -inline void ApplyFEXExtendedVolatileMetadata(FEX::VolatileMetadata::ExtendedVolatileMetadata& ExtendedMetaData, - fextl::set& VolatileInstructions, - FEXCore::IntervalList& VolatileValidRanges, uint64_t Address, uint64_t EndAddress) { - // Load FEX extended volatile metadata. - // Walk the volatile instructions first if they exist. - for (const auto it_inst : ExtendedMetaData.VolatileInstructions) { - const auto inst_address = it_inst + Address; - if (inst_address < EndAddress) { - VolatileInstructions.emplace(Address + it_inst); - } else { - LogMan::Msg::DFmt("Volatile instruction 0x{:x} couldn't fit in to module range [0x{:x}, 0x{:x}). Not adding anymore volatile " - "instructions. Inspect your config!", - inst_address, Address, EndAddress); - return; - } - } - - // Walk the volatile list - for (const auto it_ranges : ExtendedMetaData.VolatileValidRanges) { - VolatileValidRanges.Insert({Address + it_ranges.Offset, Address + it_ranges.End}); - } - - // If it is fully disabled, then set the entire module range - if (ExtendedMetaData.ModuleTSODisabled) { - VolatileValidRanges.Clear(); - VolatileValidRanges.Insert({Address, EndAddress}); - } -} - - -} // namespace FEX::Windows diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index bdb523d04..ce3a7458c 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -40,10 +40,10 @@ $end_info$ #include "Common/CRT/CRT.h" #include "Common/PortabilityInfo.h" #include "Common/Handle.h" +#include "Common/VolatileMetadata.h" #include "DummyHandlers.h" #include "BTInterface.h" #include "Windows/Common/SHMStats.h" -#include "Windows/Common/VolatileMetadata.h" #include #include @@ -173,7 +173,7 @@ void LoadImageVolatileMetadata(const fextl::string& ModuleName, uint64_t Address // Load FEX extended volatile metadata. auto it = ExtendedMetaData.find(ModuleName); if (it != ExtendedMetaData.end()) { - FEX::Windows::ApplyFEXExtendedVolatileMetadata(it->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); + FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(it->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); } if (VolatileInstructions.empty() && VolatileValidRanges.Empty()) {