mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 14:00:16 +02:00
Windows: Introduce ImageTracker for tracking per-loaded-image data
and use it to commonise volatile metadata code (adding WOW64 image voltmd support in the process). This will be extended to track mapped images for code caching.
This commit is contained in:
1 parent
2d6dbd5600
commit
64ad853a5c
3 files changed
+137
-1
No files matched your search
@@ -8,7 +8,7 @@ target_include_directories(CommonWindowsRuntime PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/Source/Windows/include/"
|
||||
)
|
||||
|
||||
add_library(CommonWindows STATIC CPUFeatures.cpp SHMStats.cpp InvalidationTracker.cpp Logging.cpp)
|
||||
add_library(CommonWindows STATIC CPUFeatures.cpp SHMStats.cpp InvalidationTracker.cpp ImageTracker.cpp Logging.cpp)
|
||||
|
||||
target_link_libraries(CommonWindows FEXCore_Base)
|
||||
target_include_directories(CommonWindows PRIVATE
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <FEXCore/Core/Context.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/SignalScopeGuards.h>
|
||||
#include <FEXCore/fextl/fmt.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
|
||||
#include <winternl.h>
|
||||
|
||||
#include "Module.h"
|
||||
#include "ImageTracker.h"
|
||||
|
||||
namespace FEX::Windows {
|
||||
static void LoadImageVolatileMetadata(fextl::set<uint64_t>& VolatileInstructions, FEXCore::IntervalList<uint64_t>& VolatileValidRanges,
|
||||
HMODULE Module, ArchImageNtHeaders* Nt, uint64_t Address, uint64_t EndAddress) {
|
||||
ULONG Size;
|
||||
|
||||
const auto* LoadConfig =
|
||||
reinterpret_cast<ArchImageLoadConfigDirectory*>(RtlImageDirectoryEntryToData(Module, true, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &Size));
|
||||
if (!LoadConfig || LoadConfig->Size <= offsetof(ArchImageLoadConfigDirectory, VolatileMetadataPointer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LoadConfig->VolatileMetadataPointer < Address || LoadConfig->VolatileMetadataPointer + sizeof(IMAGE_VOLATILE_METADATA) >= EndAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* VolatileMetadata = reinterpret_cast<IMAGE_VOLATILE_METADATA*>(LoadConfig->VolatileMetadataPointer);
|
||||
if (!VolatileMetadata || Address + VolatileMetadata->VolatileAccessTable + VolatileMetadata->VolatileAccessTableSize >= EndAddress ||
|
||||
Address + VolatileMetadata->VolatileInfoRangeTable + VolatileMetadata->VolatileInfoRangeTableSize >= EndAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* VolatileAccessTableBegin = reinterpret_cast<IMAGE_VOLATILE_RVA_METADATA*>(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);
|
||||
}
|
||||
|
||||
const auto* VolatileInfoRangeTableBegin = reinterpret_cast<IMAGE_VOLATILE_RANGE_METADATA*>(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});
|
||||
}
|
||||
}
|
||||
|
||||
ImageTracker::ImageTracker(FEXCore::Context::Context& CTX)
|
||||
: CTX {CTX}
|
||||
, ExtendedMetaData {FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig())} {}
|
||||
|
||||
void ImageTracker::HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage) {
|
||||
fextl::string ModuleName {BaseName(Path)};
|
||||
LogMan::Msg::DFmt("Load module {}: {:X}", ModuleName, Address);
|
||||
|
||||
const auto Module = reinterpret_cast<HMODULE>(Address);
|
||||
auto* Nt = reinterpret_cast<ArchImageNtHeaders*>(RtlImageNtHeader(Module));
|
||||
uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage;
|
||||
fextl::set<uint64_t> VolatileInstructions {};
|
||||
FEXCore::IntervalList<uint64_t> VolatileValidRanges {};
|
||||
LoadImageVolatileMetadata(VolatileInstructions, VolatileValidRanges, Module, Nt, Address, EndAddress);
|
||||
if (auto It = ExtendedMetaData.find(ModuleName); It != ExtendedMetaData.end()) {
|
||||
FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
|
||||
}
|
||||
|
||||
if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) {
|
||||
LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size());
|
||||
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
|
||||
CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions));
|
||||
}
|
||||
}
|
||||
|
||||
void ImageTracker::HandleImageUnmap(uint64_t Address, uint64_t Size) {
|
||||
std::scoped_lock Lock(CTX.GetCodeInvalidationMutex());
|
||||
CTX.RemoveForceTSOInformation(Address, Size);
|
||||
}
|
||||
} // namespace FEX::Windows
|
||||
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
#include <string_view>
|
||||
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/Config/Config.h>
|
||||
|
||||
#include "Common/VolatileMetadata.h"
|
||||
#include "Module.h"
|
||||
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::Context {
|
||||
class Context;
|
||||
}
|
||||
|
||||
namespace FEX::Windows {
|
||||
#ifdef _M_ARM_64EC
|
||||
using ArchImageNtHeaders = IMAGE_NT_HEADERS64;
|
||||
using ArchImageLoadConfigDirectory = _IMAGE_LOAD_CONFIG_DIRECTORY64;
|
||||
#else
|
||||
using ArchImageNtHeaders = IMAGE_NT_HEADERS32;
|
||||
using ArchImageLoadConfigDirectory = _IMAGE_LOAD_CONFIG_DIRECTORY32;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Tracks mapped PE code images and handles their volatile metadata
|
||||
*/
|
||||
class ImageTracker {
|
||||
public:
|
||||
ImageTracker(FEXCore::Context::Context& CTX);
|
||||
void HandleImageMap(std::string_view Path, uint64_t Address, bool MainImage);
|
||||
void HandleImageUnmap(uint64_t Address, uint64_t Size);
|
||||
|
||||
private:
|
||||
FEXCore::Context::Context& CTX;
|
||||
|
||||
FEX_CONFIG_OPT(ExtendedVolatileMetadataConfig, EXTENDEDVOLATILEMETADATA);
|
||||
fextl::unordered_map<fextl::string, FEX::VolatileMetadata::ExtendedVolatileMetadata> ExtendedMetaData;
|
||||
};
|
||||
|
||||
} // namespace FEX::Windows
|
||||
Reference in new issue
Block a user