Implement support for additional provided volatile metadata

Only wired up for wow64 and arm64ec. Gives more granular control over
TSO enabling and disabling. Matches arm64ec volatile metadata except
with one more additional feature that whole modules can be disabled at a
time.

Once we know the mapped size of files in Linux then we'll be able to do
the same thing there, but there's not a full mechanism wired up for that
yet.
This commit is contained in:
Ryan Houdek committed 2025-08-22 15:03:56 -07:00
1 parent 6db5bc3721
commit f050571696
7 files changed
+269 -13

No files matched your search

+30 -9
View File
@@ -43,6 +43,7 @@ $end_info$
#include "DummyHandlers.h"
#include "BTInterface.h"
#include "Windows/Common/SHMStats.h"
#include "Windows/Common/VolatileMetadata.h"
#include <cstdint>
#include <cstdio>
@@ -80,6 +81,7 @@ void* WineSyscallDispatcher;
uint64_t WineNtContinueSyscallId;
uint64_t WineNtAllocateVirtualMemorySyscallId;
uint64_t WineNtProtectVirtualMemorySyscallId;
static fextl::unordered_map<fextl::string, FEX::VolatileMetadata::ExtendedVolatileMetadata> ExtendedMetaData {};
NTSTATUS NtContinueNative(ARM64_NT_CONTEXT* NativeContext, BOOLEAN Alert);
NTSTATUS NtAllocateVirtualMemoryNative(HANDLE, PVOID*, ULONG_PTR, SIZE_T*, ULONG, ULONG);
@@ -267,11 +269,10 @@ void InitSyscalls() {
PatchCallChecker();
}
void LoadImageVolatileMetadata(uint64_t Address) {
const auto Module = reinterpret_cast<HMODULE>(Address);
IMAGE_NT_HEADERS* Nt = RtlImageNtHeader(Module);
uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage;
void LoadImageVolatileMetadata(fextl::set<uint64_t>& VolatileInstructions, FEXCore::IntervalList<uint64_t>& VolatileValidRanges,
HMODULE Module, IMAGE_NT_HEADERS* Nt, uint64_t Address, uint64_t EndAddress) {
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)) {
@@ -288,7 +289,6 @@ void LoadImageVolatileMetadata(uint64_t Address) {
return;
}
fextl::set<uint64_t> VolatileInstructions;
const auto* VolatileAccessTableBegin = reinterpret_cast<IMAGE_VOLATILE_RVA_METADATA*>(Address + VolatileMetadata->VolatileAccessTable);
const auto* VolatileAccessTableEnd =
VolatileAccessTableBegin + (VolatileMetadata->VolatileAccessTableSize / sizeof(IMAGE_VOLATILE_RVA_METADATA));
@@ -296,13 +296,31 @@ void LoadImageVolatileMetadata(uint64_t Address) {
VolatileInstructions.emplace(Address + It->Rva);
}
FEXCore::IntervalList<uint64_t> VolatileValidRanges;
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});
}
}
void LoadImageVolatileMetadata(const fextl::string& ModuleName, uint64_t Address) {
const auto Module = reinterpret_cast<HMODULE>(Address);
IMAGE_NT_HEADERS* Nt = 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);
auto it = ExtendedMetaData.find(ModuleName);
if (it != ExtendedMetaData.end()) {
FEX::Windows::ApplyFEXExtendedVolatileMetadata(it->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress);
}
if (VolatileInstructions.empty() && VolatileValidRanges.Empty()) {
return;
}
LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size());
std::scoped_lock Lock(CTX->GetCodeInvalidationMutex());
@@ -314,7 +332,7 @@ void HandleImageMap(uint64_t Address) {
LogMan::Msg::DFmt("Load module {}: {:X}", ModuleName, Address);
FEX_CONFIG_OPT(VolatileMetadata, VOLATILEMETADATA);
if (VolatileMetadata) {
LoadImageVolatileMetadata(Address);
LoadImageVolatileMetadata(ModuleName, Address);
}
InvalidationTracker->HandleImageMap(ModuleName, Address);
}
@@ -630,6 +648,9 @@ NTSTATUS ProcessInit() {
FEXCore::Context::InitializeStaticTables(FEXCore::Context::MODE_64BIT);
FEX_CONFIG_OPT(ExtendedVolatileMetadataConfig, EXTENDEDVOLATILEMETADATA);
ExtendedMetaData = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig());
SignalDelegator = fextl::make_unique<FEX::DummyHandlers::DummySignalDelegator>();
SyscallHandler = fextl::make_unique<Exception::ECSyscallHandler>();
Exception::HandlerConfig.emplace();
@@ -941,7 +962,7 @@ NTSTATUS ThreadInit() {
auto NewSegments = new FEXCore::Core::CPUState::gdt_segment[32];
// Setup initial code-segment GDT
auto &GDT = NewSegments[FEXCore::Core::CPUState::DEFAULT_USER_CS];
auto& GDT = NewSegments[FEXCore::Core::CPUState::DEFAULT_USER_CS];
FEXCore::Core::CPUState::SetGDTBase(&GDT, 0);
FEXCore::Core::CPUState::SetGDTLimit(&GDT, 0xF'FFFFU);
GDT.L = 1; // L = Long Mode = 64-bit
@@ -1033,7 +1054,7 @@ NTSTATUS ThreadTerm(HANDLE Thread, LONG ExitCode) {
auto ThreadState = CPUArea.ThreadState();
// GDT and LDT are mirrored, only free one.
delete [] ThreadState->CurrentFrame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT];
delete[] ThreadState->CurrentFrame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT];
FEX::Windows::CallRetStack::DestroyThread(ThreadState);
CTX->DestroyThread(ThreadState);