From 03cf15a9e11f5d0ed930817da33db16b096d337a Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 23 Feb 2025 14:37:21 +0000 Subject: [PATCH 1/5] Windows: Add IntervalList batch Insert and Contains methods --- Source/Windows/Common/IntervalList.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/Windows/Common/IntervalList.h b/Source/Windows/Common/IntervalList.h index 69e729651..086e2f297 100644 --- a/Source/Windows/Common/IntervalList.h +++ b/Source/Windows/Common/IntervalList.h @@ -66,6 +66,12 @@ public: FirstIt->End = End; } + void Insert(const IntervalList &Other) { + for (const auto &Interval : Other.Intervals) { + Insert(Interval); + } + } + void Remove(Interval Entry) { if (Entry.Offset == Entry.End) { return; @@ -142,4 +148,12 @@ public: return It != Intervals.end() && It->Offset < Entry.End; } + + bool Contains(Interval Entry) { + const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { + return LHS.Offset < RHS.End; + }); // Lowest offset interval that (maybe) overlaps with the query offset + + return It != Intervals.end() && It->Offset <= Entry.Offset && It->End >= Entry.End; + } }; From f51fd6c78db6affab2e64707e2c574db290c70ad Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 23 Feb 2025 14:38:58 +0000 Subject: [PATCH 2/5] Move IntervalList to FEXCore --- .../include/FEXCore/Utils}/IntervalList.h | 13 ++++++++----- Source/Windows/Common/InvalidationTracker.h | 4 ++-- Source/Windows/Common/OvercommitTracker.h | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) rename {Source/Windows/Common => FEXCore/include/FEXCore/Utils}/IntervalList.h (94%) diff --git a/Source/Windows/Common/IntervalList.h b/FEXCore/include/FEXCore/Utils/IntervalList.h similarity index 94% rename from Source/Windows/Common/IntervalList.h rename to FEXCore/include/FEXCore/Utils/IntervalList.h index 086e2f297..729e57e58 100644 --- a/Source/Windows/Common/IntervalList.h +++ b/FEXCore/include/FEXCore/Utils/IntervalList.h @@ -6,6 +6,7 @@ #include +namespace FEXCore { template class IntervalList { public: @@ -66,8 +67,8 @@ public: FirstIt->End = End; } - void Insert(const IntervalList &Other) { - for (const auto &Interval : Other.Intervals) { + void Insert(const IntervalList& Other) { + for (const auto& Interval : Other.Intervals) { Insert(Interval); } } @@ -127,7 +128,7 @@ public: Intervals.erase(EraseStartIt, EraseEndIt); } - QueryResult Query(SizeType Offset) { + QueryResult Query(SizeType Offset) const { const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Offset, [](const auto& LHS, const auto& RHS) { return LHS < RHS.End; }); // Lowest offset interval that (maybe) overlaps with the query offset @@ -141,7 +142,7 @@ public: } } - bool Intersect(Interval Entry) { + bool Intersect(Interval Entry) const { const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { return LHS.Offset < RHS.End; }); // Lowest offset interval that (maybe) overlaps with the query offset @@ -149,7 +150,7 @@ public: return It != Intervals.end() && It->Offset < Entry.End; } - bool Contains(Interval Entry) { + bool Contains(Interval Entry) const { const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto& LHS, const auto& RHS) { return LHS.Offset < RHS.End; }); // Lowest offset interval that (maybe) overlaps with the query offset @@ -157,3 +158,5 @@ public: return It != Intervals.end() && It->Offset <= Entry.Offset && It->End >= Entry.End; } }; + +} // namespace FEXCore diff --git a/Source/Windows/Common/InvalidationTracker.h b/Source/Windows/Common/InvalidationTracker.h index 771b352e4..75d89c7a6 100644 --- a/Source/Windows/Common/InvalidationTracker.h +++ b/Source/Windows/Common/InvalidationTracker.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT #pragma once -#include "IntervalList.h" +#include #include #include @@ -28,7 +28,7 @@ public: bool HandleRWXAccessViolation(uint64_t FaultAddress); private: - IntervalList RWXIntervals; + FEXCore::IntervalList RWXIntervals; std::mutex RWXIntervalsLock; FEXCore::Context::Context& CTX; const std::unordered_map& Threads; diff --git a/Source/Windows/Common/OvercommitTracker.h b/Source/Windows/Common/OvercommitTracker.h index 797c4c748..ba521e8a8 100644 --- a/Source/Windows/Common/OvercommitTracker.h +++ b/Source/Windows/Common/OvercommitTracker.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT #pragma once -#include "IntervalList.h" +#include #include #include @@ -13,7 +13,7 @@ namespace FEX::Windows { class OvercommitTracker { private: bool IsWine; - IntervalList OvercommitIntervals; + FEXCore::IntervalList OvercommitIntervals; std::shared_mutex OvercommitIntervalsMutex; public: From 642903a7bf5cd5a091ed492cfd4926b42e8d70b4 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 23 Feb 2025 14:41:03 +0000 Subject: [PATCH 3/5] FEXCore: Support tracking TSO range information --- FEXCore/Source/Interface/Context/Context.h | 6 ++++++ FEXCore/Source/Interface/Core/Core.cpp | 13 +++++++++++++ FEXCore/include/FEXCore/Core/Context.h | 10 ++++++++++ 3 files changed, 29 insertions(+) diff --git a/FEXCore/Source/Interface/Context/Context.h b/FEXCore/Source/Interface/Context/Context.h index c3074ba25..0361961a2 100644 --- a/FEXCore/Source/Interface/Context/Context.h +++ b/FEXCore/Source/Interface/Context/Context.h @@ -186,6 +186,10 @@ public: void AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t GuestThunkEntrypoint) override; + void AddForceTSOInformation(const IntervalList& ValidRanges, fextl::set&& Instructions) override; + + void RemoveForceTSOInformation(uint64_t Address, uint64_t Size) override; + public: friend class FEXCore::HLE::SyscallHandler; #ifdef JIT_ARM64 @@ -373,5 +377,7 @@ private: std::shared_mutex CustomIRMutex; std::atomic HasCustomIRHandlers {}; fextl::unordered_map> CustomIRHandlers; + IntervalList ForceTSOValidRanges; // The ranges for which ForceTSOInstructions has populated data + fextl::set ForceTSOInstructions; }; } // namespace FEXCore::Context diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index ee8d60a7e..4e505325f 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -971,6 +971,19 @@ void ContextImpl::AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t Gu } } +void ContextImpl::AddForceTSOInformation(const IntervalList& ValidRanges, fextl::set&& Instructions) { + LogMan::Throw::AFmt(CodeInvalidationMutex.try_lock() == false, "CodeInvalidationMutex needs to be unique_locked here"); + ForceTSOValidRanges.Insert(ValidRanges); + ForceTSOInstructions.merge(Instructions); +} + +void ContextImpl::RemoveForceTSOInformation(uint64_t Address, uint64_t Size) { + LogMan::Throw::AFmt(CodeInvalidationMutex.try_lock() == false, "CodeInvalidationMutex needs to be unique_locked here"); + + ForceTSOValidRanges.Remove({Address, Address + Size}); + ForceTSOInstructions.erase(ForceTSOInstructions.lower_bound(Address), ForceTSOInstructions.upper_bound(Address + Size)); +} + void ContextImpl::RemoveCustomIREntrypoint(uintptr_t Entrypoint) { LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint); diff --git a/FEXCore/include/FEXCore/Core/Context.h b/FEXCore/include/FEXCore/Core/Context.h index e80710701..27dbf2de1 100644 --- a/FEXCore/include/FEXCore/Core/Context.h +++ b/FEXCore/include/FEXCore/Core/Context.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -216,6 +217,15 @@ public: */ FEX_DEFAULT_VISIBILITY virtual void AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t GuestThunkEntrypoint) = 0; + /** + * @brief Adds additional per-instruction granularity TSO enable/disable information for the given range. + * + * @param ValidRanges The set of address ranges covered by this information + * @param Instructions The set of instruction addresses within the given ranges for which TSO should be enabled + */ + FEX_DEFAULT_VISIBILITY virtual void AddForceTSOInformation(const IntervalList& ValidRanges, fextl::set&& Instructions) = 0; + + FEX_DEFAULT_VISIBILITY virtual void RemoveForceTSOInformation(uint64_t Address, uint64_t Size) = 0; private: }; From 7a5e08c5ab21250a18d354c9c6cc7530ab603021 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sun, 23 Feb 2025 14:41:58 +0000 Subject: [PATCH 4/5] FEXCore: Use TSO range information when emitting IR --- FEXCore/Source/Interface/Core/Core.cpp | 27 ++++++++++++++++--- .../Source/Interface/Core/OpcodeDispatcher.h | 20 +++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 4e505325f..95cb88e19 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -565,6 +565,16 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue for (size_t j = 0; j < CodeBlocks->size(); ++j) { const FEXCore::Frontend::Decoder::DecodedBlocks& Block = CodeBlocks->at(j); + + bool BlockInForceTSOValidRange = false; + auto InstForceTSOIt = ForceTSOInstructions.end(); + if (ForceTSOValidRanges.Contains({Block.Entry, Block.Entry + Block.Size})) { + if (auto It = ForceTSOInstructions.lower_bound(Block.Entry); *It < Block.Entry + Block.Size) { + InstForceTSOIt = It; + BlockInForceTSOValidRange = true; + } + } + // Set the block entry point Thread->OpDispatcher->SetNewBlockIfChanged(Block.Entry); @@ -581,6 +591,7 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue } for (size_t i = 0; i < InstsInBlock; ++i) { + uint64_t InstAddress = Block.Entry + BlockInstructionsLength; const FEXCore::X86Tables::X86InstInfo* TableInfo {nullptr}; const FEXCore::X86Tables::DecodedInst* DecodedInfo {nullptr}; @@ -603,7 +614,7 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue Thread->OpDispatcher->FlushRegisterCache(true); if (ExtendedDebugInfo || Thread->OpDispatcher->CanHaveSideEffects(TableInfo, DecodedInfo)) { - Thread->OpDispatcher->_GuestOpcode(Block.Entry + BlockInstructionsLength - GuestRIP); + Thread->OpDispatcher->_GuestOpcode(InstAddress - GuestRIP); } if (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) { @@ -620,7 +631,7 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock); Thread->OpDispatcher->_ThreadRemoveCodeEntry(); - Thread->OpDispatcher->ExitFunction(Thread->OpDispatcher->_EntrypointOffset(GPRSize, Block.Entry + BlockInstructionsLength - GuestRIP)); + Thread->OpDispatcher->ExitFunction(Thread->OpDispatcher->_EntrypointOffset(GPRSize, InstAddress - GuestRIP)); auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlockAfter(CurrentBlock); @@ -632,17 +643,27 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue auto Fn = TableInfo->OpcodeDispatcher; Thread->OpDispatcher->ResetHandledLock(); Thread->OpDispatcher->ResetDecodeFailure(); + IR::ForceTSOMode ForceTSO = + BlockInForceTSOValidRange ? + (InstForceTSOIt != ForceTSOInstructions.end() && *InstForceTSOIt == InstAddress ? IR::ForceTSOMode::ForceEnabled : + IR::ForceTSOMode::ForceDisabled) : + IR::ForceTSOMode::NoOverride; + Thread->OpDispatcher->SetForceTSO(ForceTSO); std::invoke(Fn, Thread->OpDispatcher, DecodedInfo); if (Thread->OpDispatcher->HadDecodeFailure()) { HadDispatchError = true; } else { if (Thread->OpDispatcher->HasHandledLock() != IsLocked) { HadDispatchError = true; - LogMan::Msg::EFmt("Missing LOCK HANDLER at 0x{:x}{{'{}'}}", Block.Entry + BlockInstructionsLength, TableInfo->Name ?: "UND"); + LogMan::Msg::EFmt("Missing LOCK HANDLER at 0x{:x}{{'{}'}}", InstAddress, TableInfo->Name ?: "UND"); } BlockInstructionsLength += DecodedInfo->InstSize; TotalInstructionsLength += DecodedInfo->InstSize; ++TotalInstructions; + + // Walk InstForceTSOIt forward past the handled instruction + InstForceTSOIt = + std::find_if(InstForceTSOIt, ForceTSOInstructions.end(), [&](auto Val) { return Val >= Block.Entry + BlockInstructionsLength; }); } } else { // Invalid instruction diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index d3cfc23b7..41bd16c29 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -47,6 +47,12 @@ enum class BTAction { BTComplement, }; +enum class ForceTSOMode { + NoOverride, + ForceDisabled, + ForceEnabled, +}; + struct LoadSourceOptions { // Alignment of the load in bytes. iInvalid signifies opsize aligned. IR::OpSize Align = OpSize::iInvalid; @@ -261,6 +267,13 @@ public: return HandledLock; } + void SetForceTSO(ForceTSOMode Mode) { + ForceTSO = Mode; + } + ForceTSOMode GetForceTSO() const { + return ForceTSO; + } + void SetDumpIR(bool DumpIR) { ShouldDump = DumpIR; } @@ -1319,6 +1332,7 @@ private: bool HandledLock {false}; bool DecodeFailure {false}; bool NeedsBlockEnd {false}; + ForceTSOMode ForceTSO {ForceTSOMode::NoOverride}; // Used during new op bringup bool ShouldDump {false}; @@ -2346,7 +2360,11 @@ private: IROp_IRHeader* CurrentHeader {}; bool IsTSOEnabled(FEXCore::IR::RegisterClassType Class) { - if (Class == FPRClass) { + if (ForceTSO == ForceTSOMode::ForceEnabled) { + return true; + } else if (ForceTSO == ForceTSOMode::ForceDisabled) { + return false; + } else if (Class == FPRClass) { return CTX->IsVectorAtomicTSOEnabled(); } else { return CTX->IsAtomicTSOEnabled(); From 51281f6a3ac8acd91b91670d3e38132254f1bd30 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 27 Feb 2025 23:35:43 +0000 Subject: [PATCH 5/5] ARM64EC: Load volatile metadata --- .../Source/Interface/Config/Config.json.in | 8 +++ Source/Tools/FEXConfig/main.qml | 5 ++ Source/Windows/ARM64EC/Module.cpp | 66 +++++++++++++++++-- Source/Windows/Common/InvalidationTracker.cpp | 6 +- Source/Windows/Common/InvalidationTracker.h | 6 +- Source/Windows/include/winnt.h | 19 ++++++ 6 files changed, 103 insertions(+), 7 deletions(-) diff --git a/FEXCore/Source/Interface/Config/Config.json.in b/FEXCore/Source/Interface/Config/Config.json.in index 01ef105dc..01aa2bd70 100644 --- a/FEXCore/Source/Interface/Config/Config.json.in +++ b/FEXCore/Source/Interface/Config/Config.json.in @@ -420,6 +420,14 @@ "Should work without issues in most cases." ] }, + "VolatileMetadata": { + "Type": "bool", + "Default": "true", + "Desc": [ + "Use volatile metadata in PE files to inform TSO instructions when available.", + "When metadata is unavailable falls back to the currently enabled TSO options." + ] + }, "X87ReducedPrecision": { "Type": "bool", "Default": "false", diff --git a/Source/Tools/FEXConfig/main.qml b/Source/Tools/FEXConfig/main.qml index 59d65711f..7973bc9d3 100644 --- a/Source/Tools/FEXConfig/main.qml +++ b/Source/Tools/FEXConfig/main.qml @@ -601,6 +601,11 @@ ApplicationWindow { text: qsTr("Enable non-tearing split-lock atomics") config: "StrictInProcessSplitLocks" } + ConfigCheckBox { + topPadding: 4 + text: qsTr("Use PE volatile metadata for ARM64EC") + config: "VolatileMetadata" + } } } diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 8db65561b..4fd14c60f 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -24,6 +24,7 @@ $end_info$ #include #include #include +#include #include "Common/ArgumentLoader.h" #include "Common/Config.h" @@ -243,6 +244,55 @@ void InitSyscalls() { FillNtDllLUTs(NtDll); PatchCallChecker(); } + +void LoadImageVolatileMetadata(uint64_t Address) { + const auto Module = reinterpret_cast(Address); + IMAGE_NT_HEADERS* Nt = RtlImageNtHeader(Module); + uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage; + ULONG Size; + const auto* LoadConfig = + reinterpret_cast<_IMAGE_LOAD_CONFIG_DIRECTORY64*>(RtlImageDirectoryEntryToData(Module, true, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &Size)); + if (!LoadConfig || LoadConfig->Size <= offsetof(_IMAGE_LOAD_CONFIG_DIRECTORY64, VolatileMetadataPointer)) { + return; + } + + if (LoadConfig->VolatileMetadataPointer < Address || LoadConfig->VolatileMetadataPointer + sizeof(IMAGE_VOLATILE_METADATA) >= EndAddress) { + return; + } + + const auto* VolatileMetadata = reinterpret_cast(LoadConfig->VolatileMetadataPointer); + if (!VolatileMetadata || Address + VolatileMetadata->VolatileAccessTable + VolatileMetadata->VolatileAccessTableSize >= EndAddress || + Address + VolatileMetadata->VolatileInfoRangeTable + VolatileMetadata->VolatileInfoRangeTableSize >= EndAddress) { + return; + } + + fextl::set VolatileInstructions; + const auto* VolatileAccessTableBegin = reinterpret_cast(Address + VolatileMetadata->VolatileAccessTable); + const auto* VolatileAccessTableEnd = + VolatileAccessTableBegin + (VolatileMetadata->VolatileAccessTableSize / sizeof(IMAGE_VOLATILE_RVA_METADATA)); + for (auto It = VolatileAccessTableBegin; It != VolatileAccessTableEnd; It++) { + VolatileInstructions.emplace(Address + It->Rva); + } + + FEXCore::IntervalList VolatileValidRanges; + const auto* VolatileInfoRangeTableBegin = reinterpret_cast(Address + VolatileMetadata->VolatileInfoRangeTable); + const auto* VolatileInfoRangeTableEnd = + VolatileInfoRangeTableBegin + (VolatileMetadata->VolatileInfoRangeTableSize / sizeof(IMAGE_VOLATILE_RANGE_METADATA)); + for (auto It = VolatileInfoRangeTableBegin; It != VolatileInfoRangeTableEnd; It++) { + VolatileValidRanges.Insert({Address + It->Rva, Address + It->Rva + It->Size}); + } + + std::scoped_lock Lock(CTX->GetCodeInvalidationMutex()); + CTX->AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions)); +} + +void HandleImageMap(uint64_t Address) { + FEX_CONFIG_OPT(VolatileMetadata, VOLATILEMETADATA); + if (VolatileMetadata) { + LoadImageVolatileMetadata(Address); + } + InvalidationTracker->HandleImageMap(Address); +} } // namespace namespace Exception { @@ -562,7 +612,7 @@ NTSTATUS ProcessInit() { InvalidationTracker.emplace(*CTX, Threads); auto MainModule = reinterpret_cast<__TEB*>(NtCurrentTeb())->Peb->ImageBaseAddress; - InvalidationTracker->HandleImageMap(reinterpret_cast(MainModule)); + HandleImageMap(reinterpret_cast(MainModule)); CPUFeatures.emplace(*CTX); @@ -736,8 +786,12 @@ NTSTATUS NotifyMapViewOfSection(void* Unk1, void* Address, void* Unk2, SIZE_T Si return STATUS_SUCCESS; } - std::scoped_lock Lock(ThreadCreationMutex); - InvalidationTracker->HandleImageMap(reinterpret_cast(Address)); + { + std::scoped_lock Lock(ThreadCreationMutex); + HandleImageMap(reinterpret_cast(Address)); + } + + return STATUS_SUCCESS; } @@ -751,7 +805,11 @@ void NotifyUnmapViewOfSection(void* Address, BOOL After, NTSTATUS Status) { } std::scoped_lock Lock(ThreadCreationMutex); - InvalidationTracker->InvalidateContainingSection(reinterpret_cast(Address), true); + auto [Start, Size] = InvalidationTracker->InvalidateContainingSection(reinterpret_cast(Address), true); + if (Size) { + std::scoped_lock Lock(CTX->GetCodeInvalidationMutex()); + CTX->RemoveForceTSOInformation(Start, Size); + } } void FlushInstructionCacheHeavy(const void* Address, SIZE_T Size) { diff --git a/Source/Windows/Common/InvalidationTracker.cpp b/Source/Windows/Common/InvalidationTracker.cpp index 363609f19..1173b27a4 100644 --- a/Source/Windows/Common/InvalidationTracker.cpp +++ b/Source/Windows/Common/InvalidationTracker.cpp @@ -50,10 +50,10 @@ void InvalidationTracker::HandleImageMap(uint64_t Address) { } } -void InvalidationTracker::InvalidateContainingSection(uint64_t Address, bool Free) { +InvalidationTracker::InvalidateContainingSectionResult InvalidationTracker::InvalidateContainingSection(uint64_t Address, bool Free) { MEMORY_BASIC_INFORMATION Info; if (NtQueryVirtualMemory(NtCurrentProcess(), reinterpret_cast(Address), MemoryBasicInformation, &Info, sizeof(Info), nullptr)) { - return; + return {Address, 0}; } const auto SectionBase = reinterpret_cast(Info.AllocationBase); @@ -75,6 +75,8 @@ void InvalidationTracker::InvalidateContainingSection(uint64_t Address, bool Fre std::scoped_lock Lock(RWXIntervalsLock); RWXIntervals.Remove({SectionBase, SectionBase + SectionSize}); } + + return {SectionBase, SectionSize}; } void InvalidationTracker::InvalidateAlignedInterval(uint64_t Address, uint64_t Size, bool Free) { diff --git a/Source/Windows/Common/InvalidationTracker.h b/Source/Windows/Common/InvalidationTracker.h index 75d89c7a6..190983566 100644 --- a/Source/Windows/Common/InvalidationTracker.h +++ b/Source/Windows/Common/InvalidationTracker.h @@ -22,7 +22,11 @@ public: InvalidationTracker(FEXCore::Context::Context& CTX, const std::unordered_map& Threads); void HandleMemoryProtectionNotification(uint64_t Address, uint64_t Size, ULONG Prot); void HandleImageMap(uint64_t Address); - void InvalidateContainingSection(uint64_t Address, bool Free); + struct InvalidateContainingSectionResult { + uint64_t SectionStart; + uint64_t SectionSize; + }; + InvalidateContainingSectionResult InvalidateContainingSection(uint64_t Address, bool Free); void InvalidateAlignedInterval(uint64_t Address, uint64_t Size, bool Free); void ReprotectRWXIntervals(uint64_t Address, uint64_t Size); bool HandleRWXAccessViolation(uint64_t FaultAddress); diff --git a/Source/Windows/include/winnt.h b/Source/Windows/include/winnt.h index ecd4ffa03..244ce728d 100644 --- a/Source/Windows/include/winnt.h +++ b/Source/Windows/include/winnt.h @@ -136,6 +136,25 @@ typedef struct _CONTEXT_EX { #endif } CONTEXT_EX, *PCONTEXT_EX; +// From process hacker +typedef struct _IMAGE_VOLATILE_METADATA { + ULONG Size; + ULONG Version; + ULONG VolatileAccessTable; + ULONG VolatileAccessTableSize; + ULONG VolatileInfoRangeTable; + ULONG VolatileInfoRangeTableSize; +} IMAGE_VOLATILE_METADATA, *PIMAGE_VOLATILE_METADATA; + +typedef struct _IMAGE_VOLATILE_RVA_METADATA { + ULONG Rva; +} IMAGE_VOLATILE_RVA_METADATA, *PIMAGE_VOLATILE_RVA_METADATA; + +typedef struct _IMAGE_VOLATILE_RANGE_METADATA { + ULONG Rva; + ULONG Size; +} IMAGE_VOLATILE_RANGE_METADATA, *PIMAGE_VOLATILE_RANGE_METADATA; + NTSYSAPI DWORD WINAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE, PRTL_RUN_ONCE_INIT_FN, PVOID, PVOID*); // This is a FEX extension, and requires corresponding wine patches