Skip to content

Commit

Permalink
Merge pull request #705 from FEX-Emu/skmp/mmap-cache-flushing
Browse files Browse the repository at this point in the history
Flush IR/Code cache on mmap, mmunmap & mprot
  • Loading branch information
Stefanos Kornilios Mitsis Poiitidis authored Mar 3, 2021
2 parents e95d1bd + 613e5b6 commit 3978097
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 33 deletions.
2 changes: 1 addition & 1 deletion External/FEXCore/Source/Interface/Config/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions External/FEXCore/Source/Interface/Context/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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{};

Expand Down
29 changes: 22 additions & 7 deletions External/FEXCore/Source/Interface/Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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";
Expand Down
9 changes: 8 additions & 1 deletion External/FEXCore/Source/Interface/Core/LookupCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ class LookupCache {
}
}

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
}

Expand Down Expand Up @@ -197,6 +203,7 @@ class LookupCache {
}
};


std::map<BlockLinkTag, std::function<void()>> BlockLinks;
std::map<uint64_t, uint64_t> BlockList;

Expand Down
6 changes: 6 additions & 0 deletions External/FEXCore/include/FEXCore/Config/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions External/FEXCore/include/FEXCore/Core/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
17 changes: 11 additions & 6 deletions Source/Common/ArgumentLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion Source/Tests/ELFLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
22 changes: 16 additions & 6 deletions Source/Tests/LinuxSyscalls/x32/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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();
});

Expand Down
13 changes: 10 additions & 3 deletions Source/Tests/LinuxSyscalls/x64/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,21 @@ 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();
});

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();
});
Expand All @@ -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();
});

Expand Down
2 changes: 1 addition & 1 deletion Source/Tests/TestHarnessRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
24 changes: 20 additions & 4 deletions Source/Tools/FEXConfig/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion unittests/ASM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down

0 comments on commit 3978097

Please sign in to comment.