mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-12 22:00:41 +02:00
Merge pull request #705 from FEX-Emu/skmp/mmap-cache-flushing
Flush IR/Code cache on mmap, mmunmap & mprot
This commit is contained in:
commit
cc2b2cf346
13 files changed
+100
-33
No files matched your search
+1
-1
@@ -34,7 +34,7 @@ namespace FEXCore::Config {
|
||||
CTX->Config.TSOEnabled = Config != 0;
|
||||
break;
|
||||
case FEXCore::Config::CONFIG_SMC_CHECKS:
|
||||
CTX->Config.SMCChecks = Config != 0;
|
||||
CTX->Config.SMCChecks = static_cast<FEXCore::Config::ConfigSMCChecks>(Config);
|
||||
break;
|
||||
case FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS:
|
||||
CTX->Config.ABILocalFlags = Config != 0;
|
||||
|
||||
+2
-2
@@ -68,7 +68,7 @@ namespace FEXCore::Context {
|
||||
|
||||
bool Is64BitMode {true};
|
||||
bool TSOEnabled {true};
|
||||
bool SMCChecks {false};
|
||||
FEXCore::Config::ConfigSMCChecks SMCChecks {FEXCore::Config::CONFIG_SMC_MMAN};
|
||||
bool ABILocalFlags {false};
|
||||
bool ABINoPF {false};
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace FEXCore::Context {
|
||||
void ExecutionThread(FEXCore::Core::InternalThreadState *Thread);
|
||||
void NotifyPause();
|
||||
|
||||
void AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr);
|
||||
void AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr, uint64_t Start, uint64_t Length);
|
||||
|
||||
FEXCore::CodeLoader *LocalLoader{};
|
||||
|
||||
|
||||
+22
-7
@@ -607,8 +607,8 @@ namespace FEXCore::Context {
|
||||
return Thread;
|
||||
}
|
||||
|
||||
void Context::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr) {
|
||||
Thread->LookupCache->AddBlockMapping(Address, Ptr);
|
||||
void Context::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr, uint64_t Start, uint64_t Length) {
|
||||
Thread->LookupCache->AddBlockMapping(Address, Ptr, Start, Length);
|
||||
}
|
||||
|
||||
void Context::ClearCodeCache(FEXCore::Core::InternalThreadState *Thread, bool AlsoClearIRCache) {
|
||||
@@ -670,7 +670,7 @@ namespace FEXCore::Context {
|
||||
TableInfo = Block.DecodedInstructions[i].TableInfo;
|
||||
DecodedInfo = &Block.DecodedInstructions[i];
|
||||
|
||||
if (Config.SMCChecks) {
|
||||
if (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) {
|
||||
auto ExistingCodePtr = reinterpret_cast<uint64_t*>(Block.Entry + BlockInstructionsLength);
|
||||
|
||||
auto CodeChanged = Thread->OpDispatcher->_ValidateCode(ExistingCodePtr[0], ExistingCodePtr[1], (uintptr_t)ExistingCodePtr - GuestRIP, DecodedInfo->InstSize);
|
||||
@@ -853,7 +853,8 @@ namespace FEXCore::Context {
|
||||
|
||||
if (AOTEntry != Mod->end()) {
|
||||
// verify hash
|
||||
auto hash = fasthash64((void*)(AOTEntry->second.start + file->second.Start - file->second.Offset), AOTEntry->second.len, 0);
|
||||
auto MappedStart = AOTEntry->second.start + file->second.Start - file->second.Offset;
|
||||
auto hash = fasthash64((void*)MappedStart, AOTEntry->second.len, 0);
|
||||
if (hash == AOTEntry->second.crc) {
|
||||
IRList = AOTEntry->second.IR;
|
||||
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
|
||||
@@ -862,7 +863,7 @@ namespace FEXCore::Context {
|
||||
|
||||
RAData = AOTEntry->second.RAData;
|
||||
DebugData = new FEXCore::Core::DebugData();
|
||||
StartAddr = AOTEntry->second.start;
|
||||
StartAddr = MappedStart;
|
||||
Length = AOTEntry->second.len;
|
||||
|
||||
GeneratedIR = true;
|
||||
@@ -1117,7 +1118,7 @@ namespace FEXCore::Context {
|
||||
--Thread->CompileBlockReentrantRefCount;
|
||||
|
||||
// Insert to lookup cache
|
||||
AddBlockMapping(Thread, GuestRIP, CodePtr);
|
||||
AddBlockMapping(Thread, GuestRIP, CodePtr, StartAddr, Length);
|
||||
|
||||
return (uintptr_t)CodePtr;
|
||||
|
||||
@@ -1177,6 +1178,20 @@ namespace FEXCore::Context {
|
||||
SignalDelegation->UninstallTLSState(Thread);
|
||||
}
|
||||
|
||||
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) {
|
||||
|
||||
if (Thread->CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_MMAN) {
|
||||
auto lower = Thread->LookupCache->CodePages.lower_bound(Start >> 12);
|
||||
auto upper = Thread->LookupCache->CodePages.upper_bound((Start + Length) >> 12);
|
||||
|
||||
for (auto it = lower; it != upper; it++) {
|
||||
for (auto Address: it->second)
|
||||
Context::RemoveCodeEntry(Thread, Address);
|
||||
it->second.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::RemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||
Thread->LocalIRCache.erase(GuestRIP);
|
||||
Thread->LookupCache->Erase(GuestRIP);
|
||||
@@ -1248,7 +1263,7 @@ namespace FEXCore::Context {
|
||||
auto fileid = base_filename + "-" + std::to_string(filename_hash) + "-";
|
||||
|
||||
// append optimization flags to the fileid
|
||||
fileid += Config.SMCChecks ? "S" : "s";
|
||||
fileid += (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? "S" : "s";
|
||||
fileid += Config.TSOEnabled ? "T" : "t";
|
||||
fileid += Config.ABILocalFlags ? "L" : "l";
|
||||
fileid += Config.ABINoPF ? "p" : "P";
|
||||
|
||||
+8
-1
@@ -35,10 +35,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void AddBlockMapping(uint64_t Address, void *HostCode) {
|
||||
std::map<uint64_t, std::vector<uint64_t>> CodePages;
|
||||
|
||||
void AddBlockMapping(uint64_t Address, void *HostCode, uint64_t Start, uint64_t Length) {
|
||||
auto InsertPoint = BlockList.emplace(Address, (uintptr_t)HostCode);
|
||||
LogMan::Throw::A(InsertPoint.second == true, "Dupplicate block mapping added");
|
||||
|
||||
for (auto CurrentPage = Start >> 12, EndPage = (Start + Length) >> 12; CurrentPage <= EndPage; CurrentPage++) {
|
||||
CodePages[CurrentPage].push_back(Address);
|
||||
}
|
||||
|
||||
// no need to update L1 or L2, they will get updated on first lookup
|
||||
}
|
||||
|
||||
@@ -197,6 +203,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
std::map<BlockLinkTag, std::function<void()>> BlockLinks;
|
||||
std::map<uint64_t, uint64_t> BlockList;
|
||||
|
||||
|
||||
@@ -44,6 +44,12 @@ namespace FEXCore::Config {
|
||||
CONFIG_CUSTOM,
|
||||
};
|
||||
|
||||
enum ConfigSMCChecks {
|
||||
CONFIG_SMC_NONE,
|
||||
CONFIG_SMC_MMAN,
|
||||
CONFIG_SMC_FULL,
|
||||
};
|
||||
|
||||
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, uint64_t Config);
|
||||
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, std::string const &Config);
|
||||
uint64_t GetConfig(FEXCore::Context::Context *CTX, ConfigOption Option);
|
||||
|
||||
@@ -238,4 +238,5 @@ namespace FEXCore::Context {
|
||||
void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
|
||||
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader);
|
||||
bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
|
||||
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
|
||||
}
|
||||
@@ -66,11 +66,11 @@ namespace FEX::ArgLoader {
|
||||
.help("Number of physical hardware threads to tell the process we have")
|
||||
.set_default(1);
|
||||
|
||||
CPUGroup.add_option("--smc-full-checks")
|
||||
CPUGroup.add_option("--smc-checks")
|
||||
.dest("SMCChecks")
|
||||
.action("store_true")
|
||||
.help("Checks code for modification before execution. Slow.")
|
||||
.set_default(false);
|
||||
.choices({"none", "mman", "full"})
|
||||
.help("Checks code for modification before execution.\n\tnone: No checks\n\tmman: Invalidate on mmap, mprotect, munmap\n\tfull: Validate code before every run (slow)")
|
||||
.set_default("mman");
|
||||
|
||||
CPUGroup.add_option("--unsafe-no-tso")
|
||||
.dest("TSOEnabled")
|
||||
@@ -229,8 +229,13 @@ namespace FEX::ArgLoader {
|
||||
}
|
||||
|
||||
if (Options.is_set_by_user("SMCChecks")) {
|
||||
bool SMCChecks = Options.get("SMCChecks");
|
||||
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, std::to_string(SMCChecks));
|
||||
auto SMCChecks = Options["SMCChecks"];
|
||||
if (SMCChecks == "none")
|
||||
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "0");
|
||||
else if (SMCChecks == "mman")
|
||||
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "1");
|
||||
else if (SMCChecks == "full")
|
||||
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "2");
|
||||
}
|
||||
if (Options.is_set_by_user("AbiLocalFlags")) {
|
||||
bool AbiLocalFlags = Options.get("AbiLocalFlags");
|
||||
|
||||
@@ -205,7 +205,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEXCore::Config::Value<std::string> OutputLog{FEXCore::Config::CONFIG_OUTPUTLOG, "stderr"};
|
||||
FEXCore::Config::Value<std::string> DumpIR{FEXCore::Config::CONFIG_DUMPIR, "no"};
|
||||
FEXCore::Config::Value<bool> TSOEnabledConfig{FEXCore::Config::CONFIG_TSO_ENABLED, true};
|
||||
FEXCore::Config::Value<bool> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, false};
|
||||
FEXCore::Config::Value<uint8_t> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, FEXCore::Config::CONFIG_SMC_MMAN};
|
||||
FEXCore::Config::Value<bool> ABILocalFlags{FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS, false};
|
||||
FEXCore::Config::Value<bool> AbiNoPF{FEXCore::Config::CONFIG_ABI_NO_PF, false};
|
||||
FEXCore::Config::Value<bool> AOTIRCapture{FEXCore::Config::CONFIG_AOTIR_GENERATE, false};
|
||||
|
||||
@@ -24,10 +24,13 @@ namespace FEX::HLE::x32 {
|
||||
auto Result = (uint64_t)static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
|
||||
mmap(reinterpret_cast<void*>(addr), length, prot,flags, fd, offset);
|
||||
|
||||
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
if (Result != -1) {
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
|
||||
}
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
|
||||
}
|
||||
|
||||
return Result;
|
||||
@@ -37,10 +40,13 @@ namespace FEX::HLE::x32 {
|
||||
auto Result = (uint64_t)static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
|
||||
mmap(reinterpret_cast<void*>(addr), length, prot,flags, fd, (uint64_t)pgoffset * 0x1000);
|
||||
|
||||
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
if (Result != -1) {
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, pgoffset * 0x1000, filename);
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, pgoffset * 0x1000, filename);
|
||||
}
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
|
||||
}
|
||||
|
||||
return Result;
|
||||
@@ -51,12 +57,16 @@ namespace FEX::HLE::x32 {
|
||||
munmap(addr, length);
|
||||
if (Result != -1) {
|
||||
FEXCore::Context::RemoveNamedRegion(Thread->CTX, (uintptr_t)addr, length);
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, length);
|
||||
}
|
||||
return Result;
|
||||
});
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X32(mprotect, [](FEXCore::Core::InternalThreadState *Thread, void *addr, uint32_t len, int prot) -> uint64_t {
|
||||
uint64_t Result = ::mprotect(addr, len, prot);
|
||||
if (Result != -1 && prot & PROT_EXEC) {
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, len);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace FEX::HLE::x64 {
|
||||
uint64_t Result = ::munmap(addr, length);
|
||||
if (Result != -1) {
|
||||
FEXCore::Context::RemoveNamedRegion(Thread->CTX, (uintptr_t)addr, length);
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, length);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -32,10 +33,13 @@ namespace FEX::HLE::x64 {
|
||||
REGISTER_SYSCALL_IMPL_X64(mmap, [](FEXCore::Core::InternalThreadState *Thread, void *addr, size_t length, int prot, int flags, int fd, off_t offset) -> uint64_t {
|
||||
static FEXCore::Config::Value<bool> AOTIRLoad(FEXCore::Config::CONFIG_AOTIR_LOAD, false);
|
||||
uint64_t Result = reinterpret_cast<uint64_t>(::mmap(addr, length, prot, flags, fd, offset));
|
||||
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
if (Result != -1) {
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
auto filename = get_fdpath(fd);
|
||||
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
|
||||
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
|
||||
}
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
@@ -47,6 +51,9 @@ namespace FEX::HLE::x64 {
|
||||
|
||||
REGISTER_SYSCALL_IMPL_X64(mprotect, [](FEXCore::Core::InternalThreadState *Thread, void *addr, size_t len, int prot) -> uint64_t {
|
||||
uint64_t Result = ::mprotect(addr, len, prot);
|
||||
if (Result != -1 && prot & PROT_EXEC) {
|
||||
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, len);
|
||||
}
|
||||
SYSCALL_ERRNO();
|
||||
});
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEXCore::Config::Value<std::string> OutputLog{FEXCore::Config::CONFIG_OUTPUTLOG, "stderr"};
|
||||
FEXCore::Config::Value<std::string> DumpIR{FEXCore::Config::CONFIG_DUMPIR, "no"};
|
||||
FEXCore::Config::Value<bool> TSOEnabledConfig{FEXCore::Config::CONFIG_TSO_ENABLED, true};
|
||||
FEXCore::Config::Value<bool> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, false};
|
||||
FEXCore::Config::Value<uint8_t> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, FEXCore::Config::CONFIG_SMC_MMAN};
|
||||
FEXCore::Config::Value<bool> ABILocalFlags{FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS, false};
|
||||
FEXCore::Config::Value<bool> AbiNoPF{FEXCore::Config::CONFIG_ABI_NO_PF, false};
|
||||
|
||||
|
||||
@@ -301,11 +301,27 @@ namespace {
|
||||
ConfigChanged = true;
|
||||
}
|
||||
|
||||
ImGui::Text("SMC Checks: ");
|
||||
int SMCChecks = FEXCore::Config::CONFIG_SMC_MMAN;
|
||||
|
||||
Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS);
|
||||
bool SMCChecks = Value.has_value() && **Value == "1";
|
||||
if (ImGui::Checkbox("SMC Checks", &SMCChecks)) {
|
||||
LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, SMCChecks ? "1" : "0");
|
||||
ConfigChanged = true;
|
||||
if (Value.has_value()) {
|
||||
if (**Value == "0") {
|
||||
SMCChecks = FEXCore::Config::CONFIG_SMC_NONE;
|
||||
} else if (**Value == "1") {
|
||||
SMCChecks = FEXCore::Config::CONFIG_SMC_MMAN;
|
||||
} else if (**Value == "2") {
|
||||
SMCChecks = FEXCore::Config::CONFIG_SMC_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool SMCChanged = false;
|
||||
SMCChanged |= ImGui::RadioButton("None", &SMCChecks, FEXCore::Config::CONFIG_SMC_NONE); ImGui::SameLine();
|
||||
SMCChanged |= ImGui::RadioButton("MMan", &SMCChecks, FEXCore::Config::CONFIG_SMC_MMAN); ImGui::SameLine();
|
||||
SMCChanged |= ImGui::RadioButton("Full", &SMCChecks, FEXCore::Config::CONFIG_SMC_FULL);
|
||||
|
||||
if (SMCChanged) {
|
||||
LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, std::to_string(SMCChecks));
|
||||
}
|
||||
|
||||
Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ABI_LOCAL_FLAGS);
|
||||
|
||||
@@ -74,7 +74,7 @@ foreach(ASM_SRC ${ASM_SOURCES})
|
||||
string(REPLACE " " ";" ARGS_LIST ${ARGS})
|
||||
|
||||
if (TEST_NAME MATCHES "SelfModifyingCode")
|
||||
list(APPEND ARGS_LIST "--smc-full-checks")
|
||||
list(APPEND ARGS_LIST "--smc-checks=full")
|
||||
endif()
|
||||
|
||||
add_test(NAME ${TEST_NAME}
|
||||
|
||||
Reference in new issue
Block a user