mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
Merge pull request #4773 from Sonicadvance1/extended_volatile_metadata
Implement support for additional provided volatile metadata
This commit is contained in:
10 files changed
+441
-13
No files matched your search
@@ -522,6 +522,27 @@
|
||||
"Desc": [
|
||||
"Disables inline syscalls in order to support seccomp handling"
|
||||
]
|
||||
},
|
||||
"ExtendedVolatileMetadata": {
|
||||
"Type": "str",
|
||||
"Default": "",
|
||||
"Desc": [
|
||||
"Configuration provided volatile metadata. Only implemented for WoW64/arm64ec.",
|
||||
"Limited in its use but can be handy.",
|
||||
"Extends on top of what Microsoft has for volatile metadata, but also supported for WoW64.",
|
||||
"Colon delimited modules, then semi-colon delimited instructions, then comma delimited ranges",
|
||||
"Default disables TSO in the module, unless instructions overlap the range",
|
||||
"<module>;<offset begin>-<offset-end>,...;<instruction offset to force TSO>,...:<another>",
|
||||
"examples:",
|
||||
" * Disable TSO for a full module: Just provide the module name:",
|
||||
" `hl2_linux`",
|
||||
" * Disable TSO for a part of the module:",
|
||||
" `hl2_linux;<offset begin>-<offset-end>`",
|
||||
" * Disable TSO for a part of the module, but enable TSO for some instructions within the module",
|
||||
" `hl2_linux;<offset begin>-<offset-end>;<instruction offset>,<instruction offset>`",
|
||||
" * Disable TSO for multiple modules",
|
||||
" `hl2_linux:libsdl2.so`"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,10 +34,23 @@ public:
|
||||
Interval Interval; ///< The interval that the query offset is enclosed by, or the next interval if `Enclosed` is false
|
||||
};
|
||||
|
||||
using const_iterator = typename fextl::vector<Interval>::const_iterator;
|
||||
|
||||
const_iterator begin() const {
|
||||
return Intervals.begin();
|
||||
}
|
||||
const_iterator end() const {
|
||||
return Intervals.end();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
Intervals.clear();
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return Intervals.empty();
|
||||
}
|
||||
|
||||
void Insert(Interval Entry) {
|
||||
if (Entry.Offset == Entry.End) {
|
||||
return;
|
||||
|
||||
@@ -9,7 +9,9 @@ set(SRCS
|
||||
HostFeatures.cpp
|
||||
JSONPool.cpp
|
||||
StringUtil.cpp
|
||||
SHMStats.cpp)
|
||||
SHMStats.cpp
|
||||
VolatileMetadata.cpp
|
||||
)
|
||||
|
||||
if (NOT MINGW_BUILD)
|
||||
list (APPEND SRCS
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "Common/VolatileMetadata.h"
|
||||
|
||||
namespace FEX::VolatileMetadata {
|
||||
fextl::unordered_map<fextl::string, ExtendedVolatileMetadata> ParseExtendedVolatileMetadata(std::string_view ListOfDescriptors) {
|
||||
// Parsing: `<module>;<address begin>-<address-end>,<more addresses>;<instruction offset to force TSO>:`
|
||||
if (ListOfDescriptors.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
fextl::unordered_map<fextl::string, ExtendedVolatileMetadata> ExtendedMetaData {};
|
||||
|
||||
auto current_module = ExtendedMetaData.end();
|
||||
|
||||
for (size_t module_offset = 0; module_offset != ListOfDescriptors.npos;) {
|
||||
size_t end_of_module = ListOfDescriptors.find(":", module_offset);
|
||||
std::string_view module_config = ListOfDescriptors.substr(module_offset, end_of_module - module_offset);
|
||||
|
||||
if (module_config.empty()) {
|
||||
module_offset = end_of_module == ListOfDescriptors.npos ? ListOfDescriptors.npos : end_of_module + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t end_of_name = module_config.find(";");
|
||||
size_t end_of_address_ranges = module_config.npos;
|
||||
size_t end_of_individual_inst = module_config.npos;
|
||||
|
||||
// Module name handling
|
||||
{
|
||||
std::string_view section_str = module_config.substr(0, end_of_name);
|
||||
|
||||
if (section_str.empty()) {
|
||||
module_offset = end_of_module == ListOfDescriptors.npos ? ListOfDescriptors.npos : end_of_module + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_module = ExtendedMetaData
|
||||
.insert_or_assign(fextl::string(section_str),
|
||||
ExtendedVolatileMetadata {
|
||||
.ModuleTSODisabled = true,
|
||||
})
|
||||
.first;
|
||||
}
|
||||
|
||||
// Address range handling
|
||||
if (end_of_name != module_config.npos) {
|
||||
end_of_address_ranges = module_config.find(";", end_of_name + 1);
|
||||
std::string_view section_str = module_config.substr(end_of_name + 1, end_of_address_ranges - (end_of_name + 1));
|
||||
|
||||
if (section_str.empty()) {
|
||||
module_offset = end_of_module == ListOfDescriptors.npos ? ListOfDescriptors.npos : end_of_module + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_module->second.ModuleTSODisabled = false;
|
||||
|
||||
// Walk all the address ranges provided.
|
||||
for (size_t non_tso_region_offset = 0; non_tso_region_offset != section_str.npos;) {
|
||||
size_t end_of_region_substr = section_str.find(",", non_tso_region_offset);
|
||||
std::string_view tso_region_view = section_str.substr(non_tso_region_offset, end_of_region_substr - non_tso_region_offset);
|
||||
|
||||
if (tso_region_view.empty()) {
|
||||
non_tso_region_offset = end_of_region_substr == section_str.npos ? section_str.npos : end_of_region_substr + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t begin {}, end {};
|
||||
char* str_end;
|
||||
begin = std::strtoull(tso_region_view.data(), &str_end, 16);
|
||||
LOGMAN_THROW_A_FMT(tso_region_view.data() != str_end, "Couldn't parse begin {}", tso_region_view);
|
||||
|
||||
// Skip `-` separator.
|
||||
++str_end;
|
||||
|
||||
LOGMAN_THROW_A_FMT(str_end != tso_region_view.end(), "Couldn't parse end {}", tso_region_view);
|
||||
auto str_begin = str_end;
|
||||
end = std::strtoull(str_begin, &str_end, 16);
|
||||
LOGMAN_THROW_A_FMT(str_begin != str_end, "Couldn't parse end {}", tso_region_view);
|
||||
|
||||
current_module->second.VolatileValidRanges.Insert({begin, end});
|
||||
non_tso_region_offset = end_of_region_substr == section_str.npos ? section_str.npos : end_of_region_substr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Individual instruction handling
|
||||
if (end_of_address_ranges != module_config.npos) {
|
||||
end_of_individual_inst = module_config.find(";", end_of_address_ranges + 1);
|
||||
std::string_view section_str = module_config.substr(end_of_address_ranges + 1, end_of_individual_inst);
|
||||
|
||||
if (section_str.empty()) {
|
||||
module_offset = end_of_module == ListOfDescriptors.npos ? ListOfDescriptors.npos : end_of_module + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t force_tso_region_offset = 0; force_tso_region_offset != section_str.npos;) {
|
||||
size_t end_of_region_substr = section_str.find(",", force_tso_region_offset);
|
||||
std::string_view tso_region_view = section_str.substr(force_tso_region_offset, end_of_region_substr - force_tso_region_offset);
|
||||
|
||||
if (tso_region_view.empty()) {
|
||||
force_tso_region_offset = end_of_region_substr == section_str.npos ? section_str.npos : end_of_region_substr + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t offset {};
|
||||
char* str_end;
|
||||
offset = std::strtoull(tso_region_view.data(), &str_end, 16);
|
||||
LOGMAN_THROW_A_FMT(tso_region_view.data() != str_end, "Couldn't parse offset {}", tso_region_view);
|
||||
|
||||
current_module->second.VolatileInstructions.insert(offset);
|
||||
|
||||
force_tso_region_offset = end_of_region_substr == section_str.npos ? section_str.npos : end_of_region_substr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
module_offset = end_of_module == ListOfDescriptors.npos ? ListOfDescriptors.npos : end_of_module + 1;
|
||||
}
|
||||
|
||||
return ExtendedMetaData;
|
||||
}
|
||||
} // namespace FEX::VolatileMetadata
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
#include <FEXCore/Utils/IntervalList.h>
|
||||
#include <FEXCore/fextl/unordered_map.h>
|
||||
#include <FEXCore/fextl/set.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
|
||||
namespace FEX::VolatileMetadata {
|
||||
struct ExtendedVolatileMetadata {
|
||||
FEXCore::IntervalList<uint64_t> VolatileValidRanges;
|
||||
fextl::set<uint64_t> VolatileInstructions;
|
||||
bool ModuleTSODisabled;
|
||||
};
|
||||
|
||||
fextl::unordered_map<fextl::string, ExtendedVolatileMetadata> ParseExtendedVolatileMetadata(std::string_view ListOfDescriptors);
|
||||
} // namespace FEX::VolatileMetadata
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
|
||||
#include "Common/VolatileMetadata.h"
|
||||
|
||||
#include <FEXCore/fextl/unordered_map.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/set.h>
|
||||
#include <FEXCore/Utils/IntervalList.h>
|
||||
|
||||
namespace FEX::Windows {
|
||||
inline void ApplyFEXExtendedVolatileMetadata(FEX::VolatileMetadata::ExtendedVolatileMetadata& ExtendedMetaData,
|
||||
fextl::set<uint64_t>& VolatileInstructions,
|
||||
FEXCore::IntervalList<uint64_t>& 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
|
||||
@@ -26,6 +26,7 @@ $end_info$
|
||||
#include <FEXCore/Utils/FPState.h>
|
||||
#include <FEXCore/Utils/ArchHelpers/Arm64.h>
|
||||
#include <FEXCore/Utils/TypeDefines.h>
|
||||
#include <FEXCore/Utils/SignalScopeGuards.h>
|
||||
|
||||
#include "Common/ArgumentLoader.h"
|
||||
#include "Common/CallRetStack.h"
|
||||
@@ -43,6 +44,7 @@ $end_info$
|
||||
#include "DummyHandlers.h"
|
||||
#include "BTInterface.h"
|
||||
#include "Windows/Common/SHMStats.h"
|
||||
#include "Windows/Common/VolatileMetadata.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
@@ -127,6 +129,8 @@ std::mutex ThreadCreationMutex;
|
||||
// Map of TIDs to their FEX thread state, `ThreadCreationMutex` must be locked when accessing
|
||||
std::unordered_map<DWORD, FEXCore::Core::InternalThreadState*> Threads;
|
||||
|
||||
static fextl::unordered_map<fextl::string, FEX::VolatileMetadata::ExtendedVolatileMetadata> ExtendedMetaData {};
|
||||
|
||||
decltype(__wine_unix_call_dispatcher) WineUnixCall;
|
||||
|
||||
std::pair<NTSTATUS, TLS> GetThreadTLS(HANDLE Thread) {
|
||||
@@ -159,9 +163,36 @@ bool IsAddressInJit(uint64_t Address) {
|
||||
return Thread->CTX->IsAddressInCodeBuffer(Thread, Address);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Load FEX extended volatile metadata.
|
||||
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());
|
||||
CTX->AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions));
|
||||
}
|
||||
|
||||
void HandleImageMap(uint64_t Address) {
|
||||
fextl::string ModuleName = FEX::Windows::GetSectionFilePath(Address);
|
||||
LogMan::Msg::DFmt("Load module {}: {:X}", ModuleName, Address);
|
||||
FEX_CONFIG_OPT(VolatileMetadata, VOLATILEMETADATA);
|
||||
if (VolatileMetadata) {
|
||||
LoadImageVolatileMetadata(ModuleName, Address);
|
||||
}
|
||||
InvalidationTracker->HandleImageMap(ModuleName, Address);
|
||||
}
|
||||
} // namespace
|
||||
@@ -494,6 +525,9 @@ void BTCpuProcessInit() {
|
||||
|
||||
FEXCore::Context::InitializeStaticTables(FEXCore::Context::MODE_32BIT);
|
||||
|
||||
FEX_CONFIG_OPT(ExtendedVolatileMetadataConfig, EXTENDEDVOLATILEMETADATA);
|
||||
ExtendedMetaData = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(ExtendedVolatileMetadataConfig());
|
||||
|
||||
SignalDelegator = fextl::make_unique<FEX::DummyHandlers::DummySignalDelegator>();
|
||||
SyscallHandler = fextl::make_unique<WowSyscallHandler>();
|
||||
Context::HandlerConfig.emplace();
|
||||
@@ -572,7 +606,7 @@ void BTCpuThreadInit() {
|
||||
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 = 0; // L = Long Mode = 32-bit
|
||||
@@ -638,7 +672,7 @@ void BTCpuThreadTerm(HANDLE Thread, LONG ExitCode) {
|
||||
auto ThreadState = TLS.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);
|
||||
@@ -734,7 +768,7 @@ __attribute__((naked)) void BTCpuSimulate() {
|
||||
".seh_endproc;");
|
||||
}
|
||||
|
||||
extern "C" void BTCpuSimulateImpl(CONTEXT *entry_context) {
|
||||
extern "C" void BTCpuSimulateImpl(CONTEXT* entry_context) {
|
||||
auto TLS = GetTLS();
|
||||
TLS.EntryContext() = entry_context;
|
||||
TLS.CachedCallRetSp() = TLS.ThreadState()->CurrentFrame->State.callret_sp;
|
||||
|
||||
@@ -5,6 +5,7 @@ set (TESTS
|
||||
Filesystem
|
||||
StringUtils
|
||||
fextl_function
|
||||
ExtendedVolatileMetadata
|
||||
)
|
||||
|
||||
list(APPEND LIBS Common FEXCore JemallocLibs)
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "Common/VolatileMetadata.h"
|
||||
|
||||
TEST_CASE("Basic - Empty") {
|
||||
const auto String = "";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Empty - modules") {
|
||||
const auto String = ":::::";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Single") {
|
||||
const auto String = "hl2_linux";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 1);
|
||||
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == true);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Multiple") {
|
||||
const auto String = "hl2_linux:DeckJob";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 2);
|
||||
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == true);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty());
|
||||
|
||||
REQUIRE(Result.contains("DeckJob"));
|
||||
CHECK(Result.at("DeckJob").ModuleTSODisabled == true);
|
||||
CHECK(Result.at("DeckJob").VolatileInstructions.empty());
|
||||
CHECK(Result.at("DeckJob").VolatileValidRanges.Empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Single plus empty") {
|
||||
const auto String = "hl2_linux:::::";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 1);
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == true);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty());
|
||||
}
|
||||
|
||||
static inline bool ContainsRange(std::pair<uint64_t, uint64_t> Range, const std::vector<std::pair<uint64_t, uint64_t>>& ValidRanges) {
|
||||
return std::ranges::find(ValidRanges, Range) != ValidRanges.end();
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Single - offset") {
|
||||
const auto String = "hl2_linux;0x0-0x1000";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 1);
|
||||
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == false);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty() == false);
|
||||
|
||||
const std::vector<std::pair<uint64_t, uint64_t>> ValidRanges = {
|
||||
{0, 0x1000},
|
||||
};
|
||||
|
||||
for (auto it : Result.at("hl2_linux").VolatileValidRanges) {
|
||||
CHECK(ContainsRange(std::make_pair(it.Offset, it.End), ValidRanges));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Single - offset x2") {
|
||||
const auto String = "hl2_linux;0x0-0x1000,0x2000-0x3000";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 1);
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == false);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty() == false);
|
||||
|
||||
const std::vector<std::pair<uint64_t, uint64_t>> ValidRanges = {
|
||||
{0, 0x1000},
|
||||
{0x2000, 0x3000},
|
||||
};
|
||||
|
||||
for (auto it : Result.at("hl2_linux").VolatileValidRanges) {
|
||||
CHECK(ContainsRange(std::make_pair(it.Offset, it.End), ValidRanges));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Single - offset plus instruction") {
|
||||
const auto String = "hl2_linux;0x0-0x1000;0x1,0x2,0x3";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 1);
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == false);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty() == false);
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty() == false);
|
||||
|
||||
const std::vector<std::pair<uint64_t, uint64_t>> ValidRanges = {
|
||||
{0, 0x1000},
|
||||
};
|
||||
|
||||
const std::vector<uint64_t> ValidInsts = {
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
};
|
||||
|
||||
for (auto it : Result.at("hl2_linux").VolatileValidRanges) {
|
||||
CHECK(ContainsRange(std::make_pair(it.Offset, it.End), ValidRanges));
|
||||
}
|
||||
|
||||
for (auto it : Result.at("hl2_linux").VolatileInstructions) {
|
||||
CHECK_THAT(ValidInsts, Catch::Matchers::Contains(it));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Basic - Double - offset") {
|
||||
const auto String = "hl2_linux;0x0-0x1000:DeckJob;0x2000-0x3000";
|
||||
const auto Result = FEX::VolatileMetadata::ParseExtendedVolatileMetadata(String);
|
||||
REQUIRE(Result.size() == 2);
|
||||
|
||||
{
|
||||
REQUIRE(Result.contains("hl2_linux"));
|
||||
CHECK(Result.at("hl2_linux").ModuleTSODisabled == false);
|
||||
CHECK(Result.at("hl2_linux").VolatileInstructions.empty());
|
||||
CHECK(Result.at("hl2_linux").VolatileValidRanges.Empty() == false);
|
||||
|
||||
const std::vector<std::pair<uint64_t, uint64_t>> ValidRanges = {
|
||||
{0, 0x1000},
|
||||
};
|
||||
|
||||
for (auto it : Result.at("hl2_linux").VolatileValidRanges) {
|
||||
CHECK(ContainsRange(std::make_pair(it.Offset, it.End), ValidRanges));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
REQUIRE(Result.contains("DeckJob"));
|
||||
CHECK(Result.at("DeckJob").ModuleTSODisabled == false);
|
||||
CHECK(Result.at("DeckJob").VolatileInstructions.empty());
|
||||
CHECK(Result.at("DeckJob").VolatileValidRanges.Empty() == false);
|
||||
|
||||
const std::vector<std::pair<uint64_t, uint64_t>> ValidRanges = {
|
||||
{0x2000, 0x3000},
|
||||
};
|
||||
|
||||
for (auto it : Result.at("DeckJob").VolatileValidRanges) {
|
||||
CHECK(ContainsRange(std::make_pair(it.Offset, it.End), ValidRanges));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user